Skip to content

Commit f0f382f

Browse files
committed
Assn 5 Prob 1 implemented
Passing tests Current implementation clones the parameter arr array to store NGEs, then later traverses that array left to right to construct a stringbuilder object which is finally converted to string Getting ready to refactor to prepend to stringbuilder object as we go while determining NGEs (so don't have to traverse an array of NGEs to build the string afterwards) Also to tell stringbuilder at creation time how big to be (since this is easily calculated) to avoid possible future perf hit
1 parent ada1b92 commit f0f382f

File tree

3 files changed

+162
-98
lines changed

3 files changed

+162
-98
lines changed

Assignment4/Problem10.cs

+1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using System.Collections.Generic;
33
using System.Text;
44
using System.Linq;
5+
using DataStructuresAndAlgos;
56

67
namespace Assignment4
78
{

Assignment5/Problem1.cs

+159-96
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,29 @@ public static void RunTests()
1414
new TestCase
1515
{
1616
InputIntArray = new int[]{ 4, 5, 2, 25 },
17-
CorrectLeadersString = "{ {4, 5}, {5, 25}, {2, 25}, {25, -1} }",
17+
CorrectNGEString = "{ {4, 5}, {5, 25}, {2, 25}, {25, -1} }",
1818
},
1919
new TestCase
2020
{
2121
InputIntArray = new int[]{ 13, 7, 6, 12 },
22-
CorrectLeadersString = "{ {13, -1}, {7, 12}, {6, 12}, {12, -1} }",
22+
CorrectNGEString = "{ {13, -1}, {7, 12}, {6, 12}, {12, -1} }",
23+
},
24+
new TestCase
25+
{
26+
InputIntArray = new int[]{ 50, 2, 15, 0, 5, -3, -8, 7, 4, 1, 10, 6, 5, 12, 8, 2, 20 },
27+
CorrectNGEString = "{ {50, -1}, {2, 15}, {15, 20}, {0, 5}, {5, 7}, {-3, 7}, {-8, 7}, {7, 10}, {4, 10}, {1, 10}, {10, 12}, {6, 12}, {5, 12}, {12, 20}, {8, 20}, {2, 20}, {20, -1} }",
28+
},
29+
new TestCase
30+
{
31+
// Same principle as using String.Empty instead of ""
32+
InputIntArray = Array.Empty<int>(),
33+
//InputIntArray = new int[]{},
34+
CorrectNGEString = "{}",
35+
},
36+
new TestCase
37+
{
38+
InputIntArray = new int[]{ 4 },
39+
CorrectNGEString = "{ {4, -1} }",
2340
},
2441
//new TestCase
2542
//{
@@ -56,13 +73,13 @@ public static void RunTests()
5673

5774
string intro =
5875
"==============\n" +
59-
"= Problem #7 =\n" +
76+
"= Problem #1 =\n" +
6077
"==============\n" +
6178
"\n" +
62-
"Write a program to print all the LEADERS in the array." +
63-
"An element is leader if it is greater than all the elements to its right side." +
64-
"And the rightmost element is always a leader." +
65-
"For example int the array { 16, 17, 4, 3, 5, 2}, leaders are 17, 5 and 2.";
79+
"Given an array, print the Next Greater Element (NGE) for every element. " +
80+
"The Next greater Element for an element x is the first greater element " +
81+
"on the right side of x in array. Elements for which no greater element " +
82+
"exist, consider next greater element as -1.";
6683

6784
Console.WriteLine(intro);
6885

@@ -74,13 +91,13 @@ public static void RunTests()
7491

7592

7693
Console.WriteLine($"For the array: {Utility.CollectionToString(testCases[i].InputIntArray)}");
77-
Console.WriteLine($"The correct result is: {testCases[i].CorrectLeadersString}.");
94+
Console.WriteLine($"The correct result is: {testCases[i].CorrectNGEString}");
7895

79-
var testCaseResult = PrintLeadersToString(testCases[i].InputIntArray);
96+
var testCaseResult = PrintElementsWithNextGreaterElements(testCases[i].InputIntArray);
8097

8198
string resultMessage;
8299

83-
if (testCaseResult == testCases[i].CorrectLeadersString)
100+
if (testCaseResult == testCases[i].CorrectNGEString)
84101
{
85102
resultMessage = "SUCCESS";
86103
}
@@ -90,7 +107,8 @@ public static void RunTests()
90107
resultMessage = "OOPS";
91108
}
92109

93-
Console.WriteLine($"{resultMessage}! Your answer is: {testCaseResult}.");
110+
Console.WriteLine($"{resultMessage}!");
111+
Console.WriteLine($"Your answer is: {testCaseResult}");
94112
}
95113

96114
var testCount = testCases.Count;
@@ -107,123 +125,168 @@ public static void RunTests()
107125
}
108126

109127

110-
public static string PrintLeadersToString(int[] arr)
111-
{
112-
if (arr == null)
113-
throw new ArgumentNullException("The int[] arr parameter is null.");
114-
115-
if (arr.Length == 0)
116-
throw new ArgumentException("The parameter int[] arr is empty.");
117128

118-
var largestLeader = arr[arr.Length - 1];
129+
// BUG: Remember that each value in an enum declaration ends with
130+
// a comma, not a semicolon
131+
private enum CompResult
132+
{
133+
Default = 0,
134+
NoNotLessThan = 1,
135+
YesLessThan = 2,
136+
}
119137

120-
//var leaders = new Queue<int> { largestLeader }; // Can you init a queue in this way? nope.
121-
var leaders = new Queue<int>();
122-
leaders.Enqueue(largestLeader);
123138

124-
// Walk through arr right to left, starting at the the element to the left of the default leader
125-
for (var i = arr.Length - 2; i >= 0; --i)
126-
{
127-
//if (arr[i] > arr[i + 1]) // No, don't compare to the element to the right
128-
// Compare to the largestLeader
129-
if (arr[i] > largestLeader)
130-
{
131-
largestLeader = arr[i];
132-
leaders.Enqueue(largestLeader);
133-
}
134-
}
135-
136-
return ConstructLeaderResultString(leaders);
137-
}
139+
// Well, not really a bug in the whiteboard sense:
140+
// For testing, these methods must all be static (not require an object instance)
141+
public static string PrintElementsWithNextGreaterElements(int[] arr)
142+
{
143+
const int DEFAULT_NGE = -1;
138144

145+
if (arr == null)
146+
throw new ArgumentNullException();
147+
148+
if (arr.Length == 0)
149+
return "{}";
150+
151+
if (arr.Length == 1)
152+
return $"{{ {{{arr[0]}, {DEFAULT_NGE}}} }}";
153+
// For an interpolated string, use "{{" for a single '{' and "}}" for a single '}'
154+
155+
// Remember that the Array.Clone method returns an object[], must cast it to appropriate type
156+
var arrNGE = (int[])arr.Clone();
157+
158+
var localMaxes = new Stack<int>();
159+
// remains empty until the right element of a pair is actually larger than the left element of a pair
160+
161+
// By definition
162+
arrNGE[^1] = DEFAULT_NGE;
139163

140-
private static string ConstructLeaderResultString(Queue<int> leaders)
141-
{
142-
// Example: "leaders are 17, 5 and 2"
164+
// Will refer to result of last comparison to determine if arr[i + 1] is determined to be a new local maximum
165+
var lastResult = CompResult.NoNotLessThan;
166+
// NoNotLessThan is correct for the "comparison" between arr[^1] and the non-element to its right, since arr[^1] will be a local max if arr[i] < arr[i + 1]
167+
// Default is reserved to essentially mean uninitialized
143168

144-
if (leaders.Count == 0)
145-
throw new ArgumentException("Queue<int> leaders parameter is empty.");
169+
var thisResult = CompResult.Default;
146170

147-
if (leaders.Count == 1)
148-
return $"leader is {leaders.Dequeue()}";
171+
// walk array from right to left
172+
// i starts at next-to-last index
173+
// compare the elements in pairs
174+
for (var i = arr.Length - 2; i >= 0; --i)
175+
{
176+
if (arr[i] < arr[i + 1])
177+
// Immediately adjacent element is NGE
178+
{
179+
thisResult = CompResult.YesLessThan;
180+
arrNGE[i] = arr[i + 1];
149181

182+
if (lastResult == CompResult.NoNotLessThan)
183+
{
184+
localMaxes.Push(arr[i + 1]);
185+
}
186+
}
187+
else // arr[i] >= arr[i + 1]
188+
// Immediately adjacent element is not NGE
189+
{
190+
thisResult = CompResult.NoNotLessThan;
150191

151-
// Build from the right of the string to the left
152-
var builder = new StringBuilder($" and {leaders.Dequeue()}");
192+
// (Destructive) check of previous local maxes for NGE
193+
bool foundNGE = false;
194+
while(!foundNGE && localMaxes.Count > 0)
195+
{
196+
if (arr[i] < localMaxes.Peek())
197+
{
198+
arrNGE[i] = localMaxes.Peek();
199+
// Leave the NGE that we just used where we found it in localMaxes, it is still a candidate to be an NGE again in the future
200+
foundNGE = true;
201+
}
202+
else
203+
{
204+
// WAS BUG: Must check of stack has elements before Pop
205+
localMaxes.Pop();
206+
}
207+
}
153208

154-
// Insert at 0, or prepend, whatever the method is for that
155-
builder.Insert(0, leaders.Dequeue());
209+
if (localMaxes.Count == 0)
210+
// No candidate NGEs exist, or arr[i] was greater than each candidate NGE
211+
{
212+
arrNGE[i] = DEFAULT_NGE;
213+
}
156214

157-
// When you Insert into a StringBuilder (probably onto the front of it,
158-
// as a prepend), the index (probably zero) is the first param, while
159-
// the string or thing-to-be-stringified is the second param
215+
// Not pushing onto localMaxes here, since we won't know until next iteration whether the current arr[i] is a local max
216+
}
160217

218+
// Advance state of tracking for next loop iteration
219+
lastResult = thisResult;
220+
thisResult = CompResult.Default;
221+
}
161222

162-
while (leaders.Count > 0)
163-
{
164-
builder.Insert(0, $"{leaders.Dequeue()}, ");
165-
}
223+
// Now construct the string left to right (or print it out as you go...but not since we're doing fixup at the end of the string building...and we're headed back to build the string as we go in the next version anyway)
166224

167-
builder.Insert(0, "leaders are ");
225+
// Example: { {4, 5}, {5, 25}, {2, 25}, {25, -1} }
168226

169-
return builder.ToString();
170-
}
227+
// TODO: Tell the builder how big it needs to be to avoid later reallocation
228+
// (Since we already know)
229+
var builder = new StringBuilder("{ ");
171230

172231

173-
// made for video
174-
public static void PrintLeaders(int[] arr)
175-
{
176-
if (arr == null)
177-
throw new ArgumentNullException("The int[] arr parameter is null.");
232+
// BUG: it's either k < arr.Length OR k <= arr.Length-1
233+
for (var k = 0; k < arr.Length; ++k)
234+
{
235+
// It's Append, not Add, for StringBuilder, right?
236+
builder.Append($"{{{arr[k]}, {arrNGE[k]}}}, ");
237+
// BUG: array index var for this loop is k, not i
238+
// But this loop is going away in the next version anyway
239+
}
178240

179-
if (arr.Length == 0)
180-
throw new ArgumentException("The parameter int[] arr is empty.");
241+
// Drop the last comma
242+
// param1: remove starting from what index
243+
// param2: how many to remove
244+
// that is: builder.Remove(where, howmany);
245+
builder.Remove(builder.Length - 2, 1);
246+
247+
// Add the final curly brace
248+
builder.Append('}');
181249

182-
var largestLeader = arr[arr.Length - 1];
183250

184-
var leaders = new Queue<int>();
185-
leaders.Enqueue(largestLeader);
186-
187-
// Walk through arr right to left,
188-
// starting at the the element to the left of the default leader
189-
for (var i = arr.Length - 2; i >= 0; --i)
190-
{
191-
// Compare to the largestLeader
192-
if (arr[i] > largestLeader)
193-
{
194-
largestLeader = arr[i];
195-
leaders.Enqueue(largestLeader);
196-
}
197-
}
251+
return builder.ToString();
252+
253+
254+
// Go ahead and finish writing this, test that this solution works, then tomorrow adapt it to build the string right to left during initial traversal of the array (instead of cloning the array)
255+
256+
// That would actually make the StringBuilder approach kind of good, even if simply printing the result at the end
257+
258+
// Would reduce space complexity by O(n), since would not need the clone array
259+
// Would reduce time complexity by O(n), since would not need to traverse the array again to build the string at the end...the string would be built as you go
260+
261+
}
262+
263+
264+
private void PrependPair(int ele, int nge, StringBuilder sb)
265+
{
266+
// Example of overall finished string:
267+
// "{ {4, 5}, {5, 25}, {2, 25}, {25, -1} }"
198268

199-
// Example: "leaders are 17, 5 and 2"
200-
if (leaders.Count == 1)
201-
Console.WriteLine($"leader is {leaders.Dequeue()}");
202-
else
203-
{
204-
// Build from the right of the string to the left
205-
var builder = new StringBuilder($" and {leaders.Dequeue()}");
269+
// Each call adds this much:
270+
// ", {25, -1} "
206271

207-
// Use Insert at 0 as prepend
208-
builder.Insert(0, leaders.Dequeue());
272+
// param1: insert starting at what index
273+
// param2: what to insert
274+
// that is: sb.Insert(where, what);
209275

210-
while (leaders.Count > 0)
211-
{
212-
builder.Insert(0, $"{leaders.Dequeue()}, ");
213-
}
276+
sb.Insert(0, $", {{{ele}, {nge}}} ");
214277

215-
builder.Insert(0, "leaders are ");
216278

217-
Console.WriteLine(builder.ToString());
218-
}
279+
// Character array would be more performant
280+
// (placing characters in the array exactly where they belong vs.
281+
// continuously inserting into the sb at index 0)
219282
}
220283

221284

222285
private class TestCase
223286
{
224287
public int[] InputIntArray { get; set; }
225288

226-
public string CorrectLeadersString { get; set; }
289+
public string CorrectNGEString { get; set; }
227290
}
228291
}
229292
}

Program.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,9 @@ static void Main(string[] args)
3838
// looks like there's no copy constructor for Array
3939
// have to allocate first then copy
4040

41-
var arr = new int[] { };
41+
//var arr = new int[] { };
4242

43-
IEnumerable<int> ie = arr;
43+
//IEnumerable<int> ie = arr;
4444

4545

4646

0 commit comments

Comments
 (0)