Skip to content

Commit 7b678d3

Browse files
authored
Merge pull request #51 from NSS-Workshops/develop
Change the other challenge to be binary search similar
2 parents 471941b + 8c42466 commit 7b678d3

1 file changed

Lines changed: 99 additions & 137 deletions

File tree

src/chapters/sorting-and-binary-search/72eee61a.js

Lines changed: 99 additions & 137 deletions
Original file line numberDiff line numberDiff line change
@@ -36,112 +36,105 @@ Leave 10–15 minutes to reflect, share feedback, and then switch roles.
3636
3737
Best of luck, and enjoy the practice! 🚀
3838
39-
## Problem: Sort Colors (Dutch Flag)
39+
## Problem: Find First Occurrence (Binary Search Variant)
4040
41-
Given an array with n objects colored red, white, or blue, sort them in-place so that objects of the same color are adjacent, with the colors in the order red, white, and blue.
41+
Given a sorted array of integers that may contain duplicates and a target value, return the index of the first occurrence of the target if it exists in the array. If the target doesn't exist, return -1.
4242
43-
We will use the integers 0, 1, and 2 to represent the color red, white, and blue, respectively.
44-
45-
You must solve this problem without using the library's sort function and in one pass (O(n) time).
43+
You must write an algorithm with O(log n) runtime complexity.
4644
4745
### Follow-up Questions:
4846
- What is the time complexity of your solution?
4947
- What is the space complexity?
50-
- How would this extend to k colors instead of 3?`,
48+
- How would you modify this to find the last occurrence instead?`,
5149
exercise: {
5250
starterCode:`/*
53-
Problem: Sort Colors (Dutch Flag)
54-
55-
Given an array with n objects colored red, white, or blue, sort them in-place so that objects of the same color are adjacent, with the colors in the order red, white, and blue.
51+
Problem: Find First Occurrence (Binary Search Variant)
5652
57-
We will use the integers 0, 1, and 2 to represent the color red, white, and blue, respectively.
53+
Given a sorted array of integers that may contain duplicates and a target value, return the index of the first occurrence of the target if it exists in the array. If the target doesn't exist, return -1.
5854
59-
You must solve this problem without using the library's sort function and in one pass (O(n) time).
55+
You must write an algorithm with O(log n) runtime complexity.
6056
6157
Examples:
62-
Input: [2, 0, 2, 1, 1, 0]
63-
Output: [0, 0, 1, 1, 2, 2]
58+
Input: nums = [5, 7, 7, 8, 8, 10], target = 8
59+
Output: 3
60+
61+
Input: nums = [5, 7, 7, 8, 8, 10], target = 6
62+
Output: -1
6463
65-
Input: [2, 0, 1]
66-
Output: [0, 1, 2]
64+
Input: nums = [1, 1, 1, 1, 1], target = 1
65+
Output: 0
6766
6867
Follow-up Questions:
6968
- What is the time complexity of your solution?
7069
- What is the space complexity?
71-
- How would this extend to k colors instead of 3?
70+
- How would you modify this to find the last occurrence instead?
7271
*/
7372
74-
function sortColors(nums) {
75-
// Approach: Use three pointers (Dutch Flag algorithm)
76-
// left: boundary for 0s (red)
77-
// right: boundary for 2s (blue)
78-
// current: current element being processed
79-
// Goal: [0s][1s][2s]
73+
function searchFirst(nums, target) {
74+
// Approach: Modified binary search
75+
// When we find the target, continue searching left to find first occurrence
76+
// Keep track of the leftmost found index
8077
8178
// Your code here
8279
}`,
8380
solution:`/*
84-
Problem: Sort Colors (Dutch Flag)
81+
Problem: Find First Occurrence (Binary Search Variant)
8582
86-
Given an array with n objects colored red, white, or blue, sort them in-place.
87-
Use integers 0, 1, and 2 to represent red, white, and blue respectively.
83+
Given a sorted array that may contain duplicates, find the first occurrence of target.
8884
*/
8985
90-
function sortColors(nums) {
91-
// Initialize three pointers
92-
let left = 0; // Boundary for 0s (red)
93-
let right = nums.length - 1; // Boundary for 2s (blue)
94-
let current = 0; // Current element being processed
86+
function searchFirst(nums, target) {
87+
// Initialize left and right pointers
88+
let left = 0;
89+
let right = nums.length - 1;
90+
let result = -1; // Store the first occurrence index
9591
96-
// Process elements until current passes right boundary
97-
while (current <= right) {
98-
if (nums[current] === 0) {
99-
// Found red (0): swap with left boundary and move both pointers
100-
[nums[current], nums[left]] = [nums[left], nums[current]];
101-
left++;
102-
current++;
103-
}
104-
else if (nums[current] === 2) {
105-
// Found blue (2): swap with right boundary, move right pointer
106-
// Don't increment current as we need to check the swapped element
107-
[nums[current], nums[right]] = [nums[right], nums[current]];
108-
right--;
109-
}
92+
// Continue searching while search space is valid
93+
while (left <= right) {
94+
// Calculate middle index (avoid overflow)
95+
const mid = Math.floor(left + (right - left) / 2);
96+
97+
// Check if we found the target
98+
if (nums[mid] === target) {
99+
result = mid; // Record this occurrence
100+
// Continue searching left for first occurrence
101+
right = mid - 1;
102+
}
103+
// If target is smaller, search left half
104+
else if (nums[mid] > target) {
105+
right = mid - 1;
106+
}
107+
// If target is larger, search right half
110108
else {
111-
// Found white (1): it's in correct position, just move current
112-
current++;
109+
left = mid + 1;
113110
}
114111
}
115112
116-
// Array is now sorted in-place: [0s][1s][2s]
113+
// Return first occurrence index or -1 if not found
114+
return result;
117115
118-
// Time Complexity: O(n) - single pass through the array
116+
// Time Complexity: O(log n) - we eliminate half the search space each iteration
119117
// Space Complexity: O(1) - only using constant extra space for pointers
120118
}`,
121119
tests:[
122120
{
123-
name: "Basic color sorting",
121+
name: "Find first occurrence with duplicates",
124122
test: (code) => {
125123
try {
126-
const sortColors = new Function(`${code}; return sortColors;`)();
124+
const searchFirst = new Function(`${code}; return searchFirst;`)();
127125

128-
const test1 = [2, 0, 2, 1, 1, 0];
129-
sortColors(test1);
130-
const expected1 = [0, 0, 1, 1, 2, 2];
126+
const nums1 = [5, 7, 7, 8, 8, 10];
127+
const test1 = searchFirst(nums1, 8) === 3;
128+
const test2 = searchFirst(nums1, 7) === 1;
129+
const test3 = searchFirst(nums1, 5) === 0;
130+
const test4 = searchFirst(nums1, 10) === 5;
131131

132-
const test2 = [2, 0, 1];
133-
sortColors(test2);
134-
const expected2 = [0, 1, 2];
135-
136-
const result1 = JSON.stringify(test1) === JSON.stringify(expected1);
137-
const result2 = JSON.stringify(test2) === JSON.stringify(expected2);
138-
139-
if (result1 && result2) {
132+
if (test1 && test2 && test3 && test4) {
140133
return new TestResult({ passed: true });
141134
} else {
142135
return new TestResult({
143136
passed: false,
144-
message: `Basic sorting failed. Test1: ${JSON.stringify(test1)}, Test2: ${JSON.stringify(test2)}`
137+
message: `Failed to find first occurrences. 8: ${searchFirst(nums1, 8)}, 7: ${searchFirst(nums1, 7)}, 5: ${searchFirst(nums1, 5)}, 10: ${searchFirst(nums1, 10)}`
145138
});
146139
}
147140
} catch (error) {
@@ -151,41 +144,26 @@ function sortColors(nums) {
151144
});
152145
}
153146
},
154-
message: "Function should sort colors correctly in basic cases."
147+
message: "Function should find first occurrence of targets with duplicates."
155148
},
156149
{
157-
name: "Handle edge cases",
150+
name: "Handle non-existing targets",
158151
test: (code) => {
159152
try {
160-
const sortColors = new Function(`${code}; return sortColors;`)();
161-
162-
const test1 = [0];
163-
sortColors(test1);
164-
const expected1 = [0];
165-
166-
const test2 = [1];
167-
sortColors(test2);
168-
const expected2 = [1];
153+
const searchFirst = new Function(`${code}; return searchFirst;`)();
169154

170-
const test3 = [2];
171-
sortColors(test3);
172-
const expected3 = [2];
155+
const nums = [5, 7, 7, 8, 8, 10];
156+
const test1 = searchFirst(nums, 6) === -1;
157+
const test2 = searchFirst(nums, 4) === -1;
158+
const test3 = searchFirst(nums, 11) === -1;
159+
const test4 = searchFirst(nums, 9) === -1;
173160

174-
const test4 = [];
175-
sortColors(test4);
176-
const expected4 = [];
177-
178-
const result1 = JSON.stringify(test1) === JSON.stringify(expected1);
179-
const result2 = JSON.stringify(test2) === JSON.stringify(expected2);
180-
const result3 = JSON.stringify(test3) === JSON.stringify(expected3);
181-
const result4 = JSON.stringify(test4) === JSON.stringify(expected4);
182-
183-
if (result1 && result2 && result3 && result4) {
161+
if (test1 && test2 && test3 && test4) {
184162
return new TestResult({ passed: true });
185163
} else {
186164
return new TestResult({
187165
passed: false,
188-
message: `Edge cases failed. Single 0: ${JSON.stringify(test1)}, Single 1: ${JSON.stringify(test2)}, Single 2: ${JSON.stringify(test3)}, Empty: ${JSON.stringify(test4)}`
166+
message: `Failed to handle non-existing targets. 6: ${searchFirst(nums, 6)}, 4: ${searchFirst(nums, 4)}, 11: ${searchFirst(nums, 11)}, 9: ${searchFirst(nums, 9)}`
189167
});
190168
}
191169
} catch (error) {
@@ -195,31 +173,26 @@ function sortColors(nums) {
195173
});
196174
}
197175
},
198-
message: "Function should handle edge cases (single elements, empty array)."
176+
message: "Function should return -1 for non-existing targets."
199177
},
200178
{
201-
name: "Handle already sorted arrays",
179+
name: "Handle edge cases",
202180
test: (code) => {
203181
try {
204-
const sortColors = new Function(`${code}; return sortColors;`)();
205-
206-
const test1 = [0, 0, 1, 1, 2, 2];
207-
sortColors(test1);
208-
const expected1 = [0, 0, 1, 1, 2, 2];
209-
210-
const test2 = [0, 1, 2];
211-
sortColors(test2);
212-
const expected2 = [0, 1, 2];
182+
const searchFirst = new Function(`${code}; return searchFirst;`)();
213183

214-
const result1 = JSON.stringify(test1) === JSON.stringify(expected1);
215-
const result2 = JSON.stringify(test2) === JSON.stringify(expected2);
184+
const test1 = searchFirst([], 1) === -1; // Empty array
185+
const test2 = searchFirst([1], 1) === 0; // Single element found
186+
const test3 = searchFirst([1], 2) === -1; // Single element not found
187+
const test4 = searchFirst([1, 1], 1) === 0; // Two identical elements
188+
const test5 = searchFirst([1, 2], 2) === 1; // Two different elements
216189

217-
if (result1 && result2) {
190+
if (test1 && test2 && test3 && test4 && test5) {
218191
return new TestResult({ passed: true });
219192
} else {
220193
return new TestResult({
221194
passed: false,
222-
message: `Already sorted cases failed. Test1: ${JSON.stringify(test1)}, Test2: ${JSON.stringify(test2)}`
195+
message: `Edge cases failed. Empty: ${searchFirst([], 1)}, Single found: ${searchFirst([1], 1)}, Single not found: ${searchFirst([1], 2)}, Two identical: ${searchFirst([1, 1], 1)}, Two different: ${searchFirst([1, 2], 2)}`
223196
});
224197
}
225198
} catch (error) {
@@ -229,31 +202,25 @@ function sortColors(nums) {
229202
});
230203
}
231204
},
232-
message: "Function should handle already sorted arrays correctly."
205+
message: "Function should handle edge cases correctly."
233206
},
234207
{
235-
name: "Handle reverse sorted arrays",
208+
name: "Handle arrays with all same elements",
236209
test: (code) => {
237210
try {
238-
const sortColors = new Function(`${code}; return sortColors;`)();
211+
const searchFirst = new Function(`${code}; return searchFirst;`)();
239212

240-
const test1 = [2, 2, 1, 1, 0, 0];
241-
sortColors(test1);
242-
const expected1 = [0, 0, 1, 1, 2, 2];
213+
const test1 = searchFirst([1, 1, 1, 1, 1], 1) === 0;
214+
const test2 = searchFirst([5, 5, 5], 5) === 0;
215+
const test3 = searchFirst([2, 2, 2, 2], 2) === 0;
216+
const test4 = searchFirst([1, 1, 1, 1, 1], 2) === -1;
243217

244-
const test2 = [2, 1, 0];
245-
sortColors(test2);
246-
const expected2 = [0, 1, 2];
247-
248-
const result1 = JSON.stringify(test1) === JSON.stringify(expected1);
249-
const result2 = JSON.stringify(test2) === JSON.stringify(expected2);
250-
251-
if (result1 && result2) {
218+
if (test1 && test2 && test3 && test4) {
252219
return new TestResult({ passed: true });
253220
} else {
254221
return new TestResult({
255222
passed: false,
256-
message: `Reverse sorted cases failed. Test1: ${JSON.stringify(test1)}, Test2: ${JSON.stringify(test2)}`
223+
message: `Same elements cases failed. All 1s: ${searchFirst([1, 1, 1, 1, 1], 1)}, All 5s: ${searchFirst([5, 5, 5], 5)}, All 2s: ${searchFirst([2, 2, 2, 2], 2)}, Not found: ${searchFirst([1, 1, 1, 1, 1], 2)}`
257224
});
258225
}
259226
} catch (error) {
@@ -263,36 +230,31 @@ function sortColors(nums) {
263230
});
264231
}
265232
},
266-
message: "Function should handle reverse sorted arrays correctly."
233+
message: "Function should handle arrays with all same elements correctly."
267234
},
268235
{
269-
name: "Handle arrays with same color",
236+
name: "Work with larger arrays with duplicates",
270237
test: (code) => {
271238
try {
272-
const sortColors = new Function(`${code}; return sortColors;`)();
273-
274-
const test1 = [0, 0, 0, 0];
275-
sortColors(test1);
276-
const expected1 = [0, 0, 0, 0];
239+
const searchFirst = new Function(`${code}; return searchFirst;`)();
277240

278-
const test2 = [1, 1, 1];
279-
sortColors(test2);
280-
const expected2 = [1, 1, 1];
281-
282-
const test3 = [2, 2, 2, 2, 2];
283-
sortColors(test3);
284-
const expected3 = [2, 2, 2, 2, 2];
241+
// Create larger array with duplicates: [1,1,1,2,2,2,3,3,3,...]
242+
const largeArray = [];
243+
for (let i = 1; i <= 100; i++) {
244+
largeArray.push(i, i, i); // Each number appears 3 times
245+
}
285246

286-
const result1 = JSON.stringify(test1) === JSON.stringify(expected1);
287-
const result2 = JSON.stringify(test2) === JSON.stringify(expected2);
288-
const result3 = JSON.stringify(test3) === JSON.stringify(expected3);
247+
const test1 = searchFirst(largeArray, 50) === 147; // 50 first appears at index 147 (49*3)
248+
const test2 = searchFirst(largeArray, 1) === 0; // First element
249+
const test3 = searchFirst(largeArray, 100) === 297; // Last unique number first appears at 297
250+
const test4 = searchFirst(largeArray, 101) === -1; // Not in array
289251

290-
if (result1 && result2 && result3) {
252+
if (test1 && test2 && test3 && test4) {
291253
return new TestResult({ passed: true });
292254
} else {
293255
return new TestResult({
294256
passed: false,
295-
message: `Same color cases failed. All 0s: ${JSON.stringify(test1)}, All 1s: ${JSON.stringify(test2)}, All 2s: ${JSON.stringify(test3)}`
257+
message: `Large array test failed. 50: ${searchFirst(largeArray, 50)}, 1: ${searchFirst(largeArray, 1)}, 100: ${searchFirst(largeArray, 100)}, 101: ${searchFirst(largeArray, 101)}`
296258
});
297259
}
298260
} catch (error) {
@@ -302,7 +264,7 @@ function sortColors(nums) {
302264
});
303265
}
304266
},
305-
message: "Function should handle arrays with all same color."
267+
message: "Function should work efficiently with larger arrays containing duplicates."
306268
}
307269
]
308270
}

0 commit comments

Comments
 (0)