Skip to content

Commit 1c4738d

Browse files
authored
Merge pull request #52 from NSS-Workshops/week10
Week10
2 parents 6c195d5 + 1a410ea commit 1c4738d

40 files changed

Lines changed: 3236 additions & 3932 deletions

package-lock.json

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
"@monaco-editor/react": "^4.7.0",
1616
"@testing-library/jest-dom": "^6.6.3",
1717
"@testing-library/react": "^16.2.0",
18+
"canvas-confetti": "^1.9.3",
1819
"jest": "^29.7.0",
1920
"js-cookie": "^3.0.5",
2021
"marked": "^11.1.1",

src/chapters/combining-patterns/9b8a8427.js

Lines changed: 98 additions & 180 deletions
Original file line numberDiff line numberDiff line change
@@ -2,197 +2,122 @@ import { TestResult } from "../../utils/test_utils";
22

33
export const codeExcerciseOneChapter = {
44
id: '9b8a8427',
5-
title: 'Module 10 - Code Excercise 1',
5+
title: 'DSA Challenge 1 - Arrays: iterate, add, remove',
66
sectionId: 'combining-patterns',
77
previousChapterId: null,
88
content: `
9-
Hi 👋,
10-
You'll be guiding your partner through the coding problem on the right side of your screen.
9+
# Challenge 1: Arrays — iterate, add, remove
1110
12-
⚠️ **Please do not share this URL / problem before class.**
13-
Revealing the question early defeats the purpose of simulating a real-world interview, where candidates do not know the problem in advance. Let's give your partner the chance to experience the challenge authentically.
11+
**Navigate:** 1 | [2](a4b7c9d2) | [3](e8f1a5b3) | [4](c6d9e2f4) | [5](b3a8d7c1) | [6](f9e4b2a7) | [7](d1c5f8e3) | [8](a7b2e9f6) | [9](c4f7a1d8)
1412
15-
🧠 **Before class:**
16-
Take time to study the problem. During the session, you'll have 90 minutes in your breakout room to run a mock interview with your partner. Be sure to take turns acting as the interviewer and interviewee.
13+
## 👥 Pair Programming Instructions
1714
18-
🗣️ **As the interviewer, your responsibilities are:**
19-
- Send this URL to your partner (copy and past the whole url and slack it directly to you partner)
20-
- Briefly introduce the problem
21-
- Never give away the answer
22-
- Take notes and provide feedback
23-
- Fill out this [feedback form](https://forms.gle/sXK3tJaGNEk52jm4A)
15+
**Work in pairs for this challenge!** One person should be the **Driver** (writing code) and the other the **Navigator** (reviewing and guiding). **Switch roles for each function** you implement.
2416
25-
🗣️ **As the interviewee, your responsibilities are:**
26-
- Ask clarifying questions
27-
- Follow the steps in the [solving guide](https://forms.gle/sXK3tJaGNEk52jm4A):
28-
Step 1: Clarify
29-
Step 2: Plan
30-
Step 3: Implement
31-
Step 4: Test
32-
Step 5: Optimize
17+
<iframe width="560" height="315" src="https://www.youtube.com/embed/jqGmL6Hf23k?si=qXmQcnQigfo1adTb" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
3318
34-
🪞 **After the first interview:**
35-
Leave 10–15 minutes to reflect, share feedback, and then switch roles.
19+
**Why it matters:** Arrays are the workhorse. Mastering iteration and index-based edits builds intuition for time complexity.
3620
37-
Best of luck, and enjoy the practice! 🚀
21+
**Objectives:**
22+
- Implement code to iterate over an array and perform an operation.
23+
- Implement code to add/remove by index.
24+
- Explain why insert/remove by index is **O(n)** and \`.push/.pop\` are **O(1)** while \`.shift/.unshift\` are **O(n)\`.
3825
39-
## Problem: Group Anagrams
26+
**Time Estimate:** 20 minutes
4027
41-
Given an array of strings, group the anagrams together. You can return the answer in any order.
28+
## Problems to Solve:
4229
43-
An anagram is a word or phrase formed by rearranging the letters of a different word or phrase, typically using all the original letters exactly once.
30+
1. **sumOfSquares(nums)** - Return the sum of x² for each x in nums (no Array.prototype.map)
31+
- Example: \`sumOfSquares([1, 2, 3])\` → \`14\` (1² + 2² + 3² = 1 + 4 + 9 = 14)
32+
- Example: \`sumOfSquares([2, 4])\` → \`20\` (2² + 4² = 4 + 16 = 20)
4433
45-
### Follow-up Questions:
46-
- What is the time complexity of your solution?
47-
- What is the space complexity?
48-
- What are alternative approaches to detect anagrams?`,
49-
exercise: {
50-
starterCode:`/*
51-
Problem: Group Anagrams
34+
2. **insertAt(arr, index, value)** - Return NEW array with value inserted at index
35+
- Example: \`insertAt([10, 20, 30], 1, 99)\` → \`[10, 99, 20, 30]\`
36+
- Example: \`insertAt([], 0, 'a')\` → \`['a']\`
5237
53-
Given an array of strings, group the anagrams together. You can return the answer in any order.
38+
3. **removeAt(arr, index)** - Return NEW array without the element at index
39+
- Example: \`removeAt([10, 20, 30], 1)\` → \`[10, 30]\`
40+
- Example: \`removeAt([5], 0)\` → \`[]\`
5441
55-
An anagram is a word or phrase formed by rearranging the letters of a different word or phrase, typically using all the original letters exactly once.
42+
## Big-O Analysis:
43+
- **insertAt/removeAt are O(n)**: They require shifting elements to maintain array structure
44+
- **push/pop are O(1)**: They operate at the end, no shifting needed
45+
- **shift/unshift are O(n)**: They operate at the beginning, requiring all elements to shift`,
5646

57-
Examples:
58-
Input: ["eat", "tea", "tan", "ate", "nat", "bat"]
59-
Output: [["bat"], ["nat", "tan"], ["ate", "eat", "tea"]]
47+
exercise: {
48+
starterCode: `/*
49+
Challenge 1: Arrays — iterate, add, remove
6050
61-
Input: [""]
62-
Output: [[""]]
51+
Implement the following functions:
6352
64-
Input: ["a"]
65-
Output: [["a"]]
53+
1. sumOfSquares(nums) - return the sum of x^2 for each x in nums (no Array.prototype.map)
54+
2. insertAt(arr, index, value) - returns NEW array with value inserted at index
55+
3. removeAt(arr, index) - returns NEW array without the element at index
6656
67-
Follow-up Questions:
68-
- What is the time complexity of your solution?
69-
- What is the space complexity?
70-
- What are alternative approaches to detect anagrams?
57+
Time Complexity Questions:
58+
- Why are insertAt/removeAt O(n)?
59+
- Why are push/pop O(1) but shift/unshift O(n)?
7160
*/
7261
73-
function groupAnagrams(strs) {
74-
// Approach: Use Map with sorted string as key
75-
// Anagrams will have the same sorted characters
76-
// Group strings by their sorted version
77-
62+
function sumOfSquares(nums) {
63+
// return the sum of x^2 for each x in nums (no Array.prototype.map)
64+
// Your code here
65+
}
66+
67+
function insertAt(arr, index, value) {
68+
// returns NEW array with value inserted at index
69+
// Your code here
70+
}
71+
72+
function removeAt(arr, index) {
73+
// returns NEW array without the element at index
7874
// Your code here
7975
}`,
80-
solution:`/*
81-
Problem: Group Anagrams
8276

83-
Given an array of strings, group the anagrams together.
77+
solution: `/*
78+
Challenge 1: Arrays — iterate, add, remove
8479
*/
8580
86-
function groupAnagrams(strs) {
87-
// Use Map to group anagrams by their sorted characters
88-
const anagramGroups = new Map();
89-
90-
// Process each string
91-
for (let str of strs) {
92-
// Sort characters to create a key for anagrams
93-
// Anagrams will have the same sorted key
94-
const sortedKey = str.split('').sort().join('');
95-
96-
// If this key exists, add to existing group
97-
// Otherwise, create new group
98-
if (anagramGroups.has(sortedKey)) {
99-
anagramGroups.get(sortedKey).push(str);
100-
} else {
101-
anagramGroups.set(sortedKey, [str]);
102-
}
81+
function sumOfSquares(nums) {
82+
// return the sum of x^2 for each x in nums (no Array.prototype.map)
83+
let sum = 0;
84+
for (let i = 0; i < nums.length; i++) {
85+
sum += nums[i] * nums[i];
10386
}
104-
105-
// Return all groups as an array of arrays
106-
return Array.from(anagramGroups.values());
107-
108-
// Time Complexity: O(n * k log k) where n = number of strings, k = max string length
109-
// - Sorting each string takes O(k log k)
110-
// - We do this for n strings
111-
// Space Complexity: O(n * k) for storing all strings in the map
112-
}`,
113-
tests:[
114-
{
115-
name: "Basic anagram grouping",
116-
test: (code) => {
117-
try {
118-
const groupAnagrams = new Function(`${code}; return groupAnagrams;`)();
119-
120-
const result = groupAnagrams(["eat", "tea", "tan", "ate", "nat", "bat"]);
121-
122-
// Sort each group and the overall result for consistent comparison
123-
const sortedResult = result.map(group => group.sort()).sort();
124-
const expected = [["bat"], ["ate", "eat", "tea"], ["nat", "tan"]].map(group => group.sort()).sort();
125-
126-
const isCorrect = JSON.stringify(sortedResult) === JSON.stringify(expected);
127-
128-
if (isCorrect) {
129-
return new TestResult({ passed: true });
130-
} else {
131-
return new TestResult({
132-
passed: false,
133-
message: `Expected ${JSON.stringify(expected)}, got ${JSON.stringify(sortedResult)}`
134-
});
135-
}
136-
} catch (error) {
137-
return new TestResult({
138-
passed: false,
139-
message: `Error: ${error.message}`
140-
});
141-
}
142-
},
143-
message: "Function should group anagrams correctly."
144-
},
145-
{
146-
name: "Handle edge cases",
147-
test: (code) => {
148-
try {
149-
const groupAnagrams = new Function(`${code}; return groupAnagrams;`)();
150-
151-
const test1 = groupAnagrams([""]);
152-
const test2 = groupAnagrams(["a"]);
153-
const test3 = groupAnagrams([]);
154-
155-
const result1 = JSON.stringify(test1) === JSON.stringify([[""]]);
156-
const result2 = JSON.stringify(test2) === JSON.stringify([["a"]]);
157-
const result3 = JSON.stringify(test3) === JSON.stringify([]);
158-
159-
if (result1 && result2 && result3) {
160-
return new TestResult({ passed: true });
161-
} else {
162-
return new TestResult({
163-
passed: false,
164-
message: `Edge cases failed. Empty string: ${JSON.stringify(test1)}, Single char: ${JSON.stringify(test2)}, Empty array: ${JSON.stringify(test3)}`
165-
});
166-
}
167-
} catch (error) {
168-
return new TestResult({
169-
passed: false,
170-
message: `Error: ${error.message}`
171-
});
172-
}
173-
},
174-
message: "Function should handle edge cases correctly."
175-
},
87+
return sum;
88+
}
89+
90+
function insertAt(arr, index, value) {
91+
// returns NEW array with value inserted at index
92+
return [...arr.slice(0, index), value, ...arr.slice(index)];
93+
}
94+
95+
function removeAt(arr, index) {
96+
// returns NEW array without the element at index
97+
if (index < 0 || index >= arr.length) {
98+
return [...arr]; // Return a new array that is a copy of the original
99+
}
100+
return [...arr.slice(0, index), ...arr.slice(index + 1)];
101+
}
102+
103+
// Big-O Analysis:
104+
// - insertAt/removeAt are O(n): They require shifting elements to maintain array structure
105+
// - push/pop are O(1): They operate at the end, no shifting needed
106+
// - shift/unshift are O(n): They operate at the beginning, requiring all elements to shift`,
107+
108+
tests: [
176109
{
177-
name: "Handle no anagrams",
110+
name: "sumOfSquares calculates correctly",
178111
test: (code) => {
179112
try {
180-
const groupAnagrams = new Function(`${code}; return groupAnagrams;`)();
181-
182-
const result = groupAnagrams(["abc", "def", "ghi"]);
183-
184-
// Each string should be in its own group
185-
const sortedResult = result.map(group => group.sort()).sort();
186-
const expected = [["abc"], ["def"], ["ghi"]].sort();
187-
188-
const isCorrect = JSON.stringify(sortedResult) === JSON.stringify(expected);
189-
190-
if (isCorrect) {
113+
const sumOfSquares = new Function(`${code}; \n return sumOfSquares;`)();
114+
const result = sumOfSquares([1, 2, 3]);
115+
if (result === 14) {
191116
return new TestResult({ passed: true });
192117
} else {
193118
return new TestResult({
194119
passed: false,
195-
message: `Expected ${JSON.stringify(expected)}, got ${JSON.stringify(sortedResult)}`
120+
message: `Expected 14, got ${result}`
196121
});
197122
}
198123
} catch (error) {
@@ -202,27 +127,25 @@ function groupAnagrams(strs) {
202127
});
203128
}
204129
},
205-
message: "Function should handle strings with no anagrams."
130+
message: "Function should calculate sum of squares correctly."
206131
},
207132
{
208-
name: "Handle duplicate strings",
133+
name: "insertAt works correctly",
209134
test: (code) => {
210135
try {
211-
const groupAnagrams = new Function(`${code}; return groupAnagrams;`)();
136+
const insertAt = new Function(`${code}; \n return insertAt;`)();
137+
const result1 = insertAt([10, 20, 30], 1, 99);
138+
const result2 = insertAt([], 0, 'a');
212139

213-
const result = groupAnagrams(["abc", "bca", "abc", "cab"]);
140+
const test1 = JSON.stringify(result1) === JSON.stringify([10, 99, 20, 30]);
141+
const test2 = JSON.stringify(result2) === JSON.stringify(['a']);
214142

215-
// All should be grouped together as they're anagrams
216-
const hasOneGroup = result.length === 1;
217-
const groupSize = result[0] ? result[0].length : 0;
218-
const correctSize = groupSize === 4;
219-
220-
if (hasOneGroup && correctSize) {
143+
if (test1 && test2) {
221144
return new TestResult({ passed: true });
222145
} else {
223146
return new TestResult({
224147
passed: false,
225-
message: `Expected one group of 4 anagrams, got ${result.length} groups with sizes: ${result.map(g => g.length)}`
148+
message: `Test 1: ${JSON.stringify(result1)}, Test 2: ${JSON.stringify(result2)}`
226149
});
227150
}
228151
} catch (error) {
@@ -232,26 +155,21 @@ function groupAnagrams(strs) {
232155
});
233156
}
234157
},
235-
message: "Function should handle duplicate strings correctly."
158+
message: "Function should insert elements at correct positions."
236159
},
237160
{
238-
name: "Handle mixed case and special characters",
161+
name: "removeAt works correctly",
239162
test: (code) => {
240163
try {
241-
const groupAnagrams = new Function(`${code}; return groupAnagrams;`)();
242-
243-
const result = groupAnagrams(["a", "aa", "aaa"]);
244-
245-
// Each should be in separate groups (different lengths)
246-
const hasThreeGroups = result.length === 3;
247-
const allSingleGroups = result.every(group => group.length === 1);
164+
const removeAt = new Function(`${code}; \n return removeAt;`)();
165+
const result = removeAt([10, 20, 30], 1);
248166

249-
if (hasThreeGroups && allSingleGroups) {
167+
if (JSON.stringify(result) === JSON.stringify([10, 30])) {
250168
return new TestResult({ passed: true });
251169
} else {
252170
return new TestResult({
253171
passed: false,
254-
message: `Expected 3 separate groups, got ${result.length} groups: ${JSON.stringify(result)}`
172+
message: `Expected [10, 30], got ${JSON.stringify(result)}`
255173
});
256174
}
257175
} catch (error) {
@@ -261,7 +179,7 @@ function groupAnagrams(strs) {
261179
});
262180
}
263181
},
264-
message: "Function should handle strings of different lengths."
182+
message: "Function should remove elements at correct positions."
265183
}
266184
]
267185
}

0 commit comments

Comments
 (0)