Skip to content

Commit e6f5fe7

Browse files
Merge pull request #97 from romankurnovskii/problems-2211-190-191-201-202-207-209-210-211-212-221-222-224-226-295
Add solutions and explanations for problems 2211, 190, 191, 201, 202, 207, 209, 210, 211, 212, 221, 222, 224, 226, 295
2 parents f9ccc4d + bd2bf9d commit e6f5fe7

File tree

30 files changed

+1196
-10
lines changed

30 files changed

+1196
-10
lines changed

explanations/190/en.md

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
## Explanation
2+
3+
### Strategy (The "Why")
4+
5+
**1.1 Constraints & Complexity:**
6+
- **Constraints:** We're working with a 32-bit unsigned integer. The input `n` ranges from 0 to 2^31 - 2 and is always even.
7+
- **Time Complexity:** O(1) - We iterate exactly 32 times regardless of input size.
8+
- **Space Complexity:** O(1) - We use only a constant amount of extra space.
9+
- **Edge Case:** If `n = 0`, all bits are 0, so the reversed number is also 0.
10+
11+
**1.2 High-level approach:**
12+
The goal is to reverse the bits of a 32-bit integer. We need to extract each bit from the original number and place it in the corresponding reversed position.
13+
14+
**1.3 Brute force vs. optimized strategy:**
15+
- **Brute Force:** Convert to binary string, reverse it, convert back. This requires string manipulation and is less efficient.
16+
- **Optimized Strategy:** Use bit manipulation to extract each bit and place it in the reversed position. This is O(1) time and space.
17+
- **Why optimized is better:** Direct bit manipulation avoids string conversion overhead and is more efficient.
18+
19+
**1.4 Decomposition:**
20+
1. Iterate through all 32 bit positions from 0 to 31.
21+
2. Extract the bit at position `i` from the input number.
22+
3. Place this bit at position `31 - i` in the result.
23+
4. Combine all bits to form the final reversed number.
24+
25+
### Steps (The "How")
26+
27+
**2.1 Initialization & Example Setup:**
28+
Let's use the example: `n = 43261596` (binary: `00000010100101000001111010011100`)
29+
30+
Initialize `res = 0`. We'll build the result bit by bit.
31+
32+
**2.2 Start Checking:**
33+
We iterate through positions 0 to 31, extracting each bit and placing it in the reversed position.
34+
35+
**2.3 Trace Walkthrough:**
36+
37+
| Position i | Bit from n | Position in result (31-i) | Action |
38+
|------------|------------|--------------------------|--------|
39+
| 0 | 0 | 31 | Place 0 at position 31 |
40+
| 1 | 0 | 30 | Place 0 at position 30 |
41+
| 2 | 1 | 29 | Place 1 at position 29 |
42+
| ... | ... | ... | ... |
43+
| 29 | 1 | 2 | Place 1 at position 2 |
44+
| 30 | 0 | 1 | Place 0 at position 1 |
45+
| 31 | 0 | 0 | Place 0 at position 0 |
46+
47+
**2.4 Increment and Loop:**
48+
For each position `i` from 0 to 31:
49+
- Extract bit: `bit = (n >> i) & 1`
50+
- Place in reversed position: `res |= (bit << (31 - i))`
51+
52+
**2.5 Return Result:**
53+
After processing all 32 bits, `res = 964176192`, which is the reversed bit representation of the input.
54+

explanations/191/en.md

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
## Explanation
2+
3+
### Strategy (The "Why")
4+
5+
**1.1 Constraints & Complexity:**
6+
- **Constraints:** The input `n` is a positive integer from 1 to 2^31 - 1.
7+
- **Time Complexity:** O(k) where k is the number of set bits (1s) in the binary representation. In worst case, this is O(32) = O(1) for 32-bit integers.
8+
- **Space Complexity:** O(1) - We use only a constant amount of extra space.
9+
- **Edge Case:** If `n = 0`, there are no set bits, so the result is 0.
10+
11+
**1.2 High-level approach:**
12+
The goal is to count the number of set bits (1s) in the binary representation of a number. We use a clever bit manipulation trick to efficiently count bits.
13+
14+
**1.3 Brute force vs. optimized strategy:**
15+
- **Brute Force:** Check each bit position individually using bitwise AND. This requires 32 iterations for a 32-bit number.
16+
- **Optimized Strategy:** Use the trick `n & (n - 1)` which removes the rightmost set bit. We count how many times we can do this until `n` becomes 0. This only iterates for the number of set bits.
17+
- **Why optimized is better:** We only iterate for the number of set bits, not all 32 positions. For numbers with few set bits, this is much faster.
18+
19+
**1.4 Decomposition:**
20+
1. Initialize a counter to track the number of set bits.
21+
2. While the number is not zero, repeatedly remove the rightmost set bit using `n & (n - 1)`.
22+
3. Increment the counter each time we remove a bit.
23+
4. Return the total count when the number becomes zero.
24+
25+
### Steps (The "How")
26+
27+
**2.1 Initialization & Example Setup:**
28+
Let's use the example: `n = 11` (binary: `1011`)
29+
30+
Initialize `res = 0`. We'll count set bits by removing them one by one.
31+
32+
**2.2 Start Checking:**
33+
We repeatedly remove the rightmost set bit until `n` becomes 0.
34+
35+
**2.3 Trace Walkthrough:**
36+
37+
| Iteration | n (binary) | n & (n-1) | res | Action |
38+
|-----------|------------|-----------|-----|--------|
39+
| 0 | 1011 | 1010 | 0 | Remove rightmost bit, res = 1 |
40+
| 1 | 1010 | 1000 | 1 | Remove rightmost bit, res = 2 |
41+
| 2 | 1000 | 0000 | 2 | Remove rightmost bit, res = 3 |
42+
| 3 | 0000 | - | 3 | n is 0, stop |
43+
44+
**2.4 Increment and Loop:**
45+
Each iteration:
46+
- `n = n & (n - 1)` removes the rightmost set bit
47+
- `res += 1` increments our count
48+
49+
**2.5 Return Result:**
50+
After all iterations, `res = 3`, which is the number of set bits in 11 (binary: 1011).
51+

explanations/201/en.md

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
## Explanation
2+
3+
### Strategy (The "Why")
4+
5+
**1.1 Constraints & Complexity:**
6+
- **Constraints:** `left` and `right` range from 0 to 2^31 - 1, with `left <= right`.
7+
- **Time Complexity:** O(log n) where n is the maximum of left and right. We shift bits until left equals right.
8+
- **Space Complexity:** O(1) - We use only a constant amount of extra space.
9+
- **Edge Case:** If `left == right`, the result is `left` itself.
10+
11+
**1.2 High-level approach:**
12+
The goal is to find the bitwise AND of all numbers in a range. The key insight is that the result is the common prefix of `left` and `right` in binary representation, with all remaining bits set to 0.
13+
14+
**1.3 Brute force vs. optimized strategy:**
15+
- **Brute Force:** Iterate through all numbers from `left` to `right` and compute their AND. This is O(n) where n is the range size, which can be very large.
16+
- **Optimized Strategy:** Find the common prefix by right-shifting both numbers until they're equal, then left-shift back. This is O(log n) time.
17+
- **Why optimized is better:** We avoid iterating through potentially millions of numbers and directly compute the result from the common prefix.
18+
19+
**1.4 Decomposition:**
20+
1. Right-shift both `left` and `right` until they become equal (finding the common prefix).
21+
2. Count how many times we shifted (stored in `shift`).
22+
3. Left-shift the common value back by `shift` positions to restore the common prefix with trailing zeros.
23+
4. Return the result.
24+
25+
### Steps (The "How")
26+
27+
**2.1 Initialization & Example Setup:**
28+
Let's use the example: `left = 5` (binary: `101`), `right = 7` (binary: `111`)
29+
30+
Initialize `shift = 0`.
31+
32+
**2.2 Start Checking:**
33+
Right-shift both numbers until they're equal.
34+
35+
**2.3 Trace Walkthrough:**
36+
37+
| Iteration | left | right | left < right? | Action |
38+
|-----------|------|-------|---------------|--------|
39+
| 0 | 5 (101) | 7 (111) | Yes | Shift both: left=2, right=3, shift=1 |
40+
| 1 | 2 (10) | 3 (11) | Yes | Shift both: left=1, right=1, shift=2 |
41+
| 2 | 1 (1) | 1 (1) | No | Stop, common prefix is 1 |
42+
43+
**2.4 Increment and Loop:**
44+
While `left < right`:
45+
- Right-shift both: `left >>= 1`, `right >>= 1`
46+
- Increment `shift`
47+
48+
**2.5 Return Result:**
49+
Common prefix is `1`, shift back: `1 << 2 = 4` (binary: `100`). This is the bitwise AND of [5, 6, 7] because the common prefix is `1` and all other bits differ.
50+

explanations/202/en.md

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
## Explanation
2+
3+
### Strategy (The "Why")
4+
5+
**1.1 Constraints & Complexity:**
6+
- **Constraints:** The input `n` is a positive integer from 1 to 2^31 - 1.
7+
- **Time Complexity:** O(log n) in the worst case, but typically much better. The process either reaches 1 (happy) or enters a cycle (unhappy).
8+
- **Space Complexity:** O(log n) to store seen numbers in the set. The cycle length is bounded.
9+
- **Edge Case:** If `n = 1`, it's already happy, so we return true immediately.
10+
11+
**1.2 High-level approach:**
12+
The goal is to determine if a number is "happy" by repeatedly replacing it with the sum of squares of its digits until we reach 1 or detect a cycle.
13+
14+
**1.3 Brute force vs. optimized strategy:**
15+
- **Brute Force:** Same approach, but without cycle detection. This could run infinitely for unhappy numbers.
16+
- **Optimized Strategy:** Use a set to track seen numbers. If we encounter a number we've seen before, we've entered a cycle and the number is unhappy.
17+
- **Why optimized is better:** Cycle detection prevents infinite loops and correctly identifies unhappy numbers.
18+
19+
**1.4 Decomposition:**
20+
1. Use a set to track numbers we've seen during the process.
21+
2. While the current number is not 1, calculate the sum of squares of its digits.
22+
3. If we've seen this number before, we're in a cycle - return false.
23+
4. Add the current number to the set and continue.
24+
5. If we reach 1, return true.
25+
26+
### Steps (The "How")
27+
28+
**2.1 Initialization & Example Setup:**
29+
Let's use the example: `n = 19`
30+
31+
Initialize `seen = set()`. We'll track numbers we've encountered.
32+
33+
**2.2 Start Checking:**
34+
We repeatedly calculate the sum of squares of digits until we reach 1 or detect a cycle.
35+
36+
**2.3 Trace Walkthrough:**
37+
38+
| Iteration | n | Sum of Squares | In seen? | Action |
39+
|-----------|---|----------------|----------|--------|
40+
| 0 | 19 | 1² + 9² = 82 | No | Add 19 to seen, n = 82 |
41+
| 1 | 82 | 8² + 2² = 68 | No | Add 82 to seen, n = 68 |
42+
| 2 | 68 | 6² + 8² = 100 | No | Add 68 to seen, n = 100 |
43+
| 3 | 100 | 1² + 0² + 0² = 1 | No | n = 1, return True |
44+
45+
**2.4 Increment and Loop:**
46+
For each number:
47+
- Calculate sum of squares of digits: `res = 0`, then for each digit: `res += digit * digit`
48+
- Check if `n` is in `seen` (cycle detected)
49+
- Add `n` to `seen` and update `n = res`
50+
51+
**2.5 Return Result:**
52+
We reached 1, so `n = 19` is a happy number. Return `True`.
53+

explanations/207/en.md

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
## Explanation
2+
3+
### Strategy (The "Why")
4+
5+
**1.1 Constraints & Complexity:**
6+
- **Constraints:** `numCourses` ranges from 1 to 2000, and there are up to 5000 prerequisite pairs.
7+
- **Time Complexity:** O(V + E) where V is the number of courses and E is the number of prerequisites. We visit each course once and process each edge once.
8+
- **Space Complexity:** O(V + E) for the graph adjacency list and in-degree array.
9+
- **Edge Case:** If there are no prerequisites, all courses can be finished, so return true.
10+
11+
**1.2 High-level approach:**
12+
The goal is to determine if we can finish all courses given their prerequisites. This is equivalent to detecting cycles in a directed graph. If a cycle exists, we cannot finish all courses.
13+
14+
**1.3 Brute force vs. optimized strategy:**
15+
- **Brute Force:** Use DFS to detect cycles by tracking visited nodes and nodes in the current path. This works but is more complex.
16+
- **Optimized Strategy:** Use Kahn's algorithm (topological sort with BFS). Start with courses that have no prerequisites, remove them, and continue. If we can process all courses, there's no cycle.
17+
- **Why optimized is better:** BFS-based approach is more intuitive and naturally handles the topological ordering.
18+
19+
**1.4 Decomposition:**
20+
1. Build an adjacency list representing the course dependency graph.
21+
2. Calculate in-degree (number of prerequisites) for each course.
22+
3. Start with courses that have no prerequisites (in-degree = 0).
23+
4. For each completed course, reduce the in-degree of its dependent courses.
24+
5. If a dependent course's in-degree becomes 0, add it to the queue.
25+
6. If we can process all courses, return true; otherwise, return false.
26+
27+
### Steps (The "How")
28+
29+
**2.1 Initialization & Example Setup:**
30+
Let's use the example: `numCourses = 2`, `prerequisites = [[1,0]]`
31+
32+
Build graph: `graph[0] = [1]` (course 0 is prerequisite for course 1)
33+
In-degrees: `in_degree[0] = 0`, `in_degree[1] = 1`
34+
35+
**2.2 Start Checking:**
36+
Initialize queue with courses having in-degree 0: `queue = [0]`
37+
38+
**2.3 Trace Walkthrough:**
39+
40+
| Step | Queue | Course | Count | Update in-degrees | New Queue |
41+
|------|-------|--------|-------|-------------------|-----------|
42+
| 0 | [0] | - | 0 | - | - |
43+
| 1 | [0] | 0 | 1 | `in_degree[1] = 0` | [1] |
44+
| 2 | [1] | 1 | 2 | - | [] |
45+
46+
**2.4 Increment and Loop:**
47+
For each course in the queue:
48+
- Remove it and increment count
49+
- For each dependent course, decrement its in-degree
50+
- If in-degree becomes 0, add to queue
51+
52+
**2.5 Return Result:**
53+
`count = 2` equals `numCourses = 2`, so we can finish all courses. Return `True`.
54+

explanations/209/en.md

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
## Explanation
2+
3+
### Strategy (The "Why")
4+
5+
**1.1 Constraints & Complexity:**
6+
- **Constraints:** `target` ranges from 1 to 10^9, `nums` length is 1 to 10^5, and each element is 1 to 10^4.
7+
- **Time Complexity:** O(n) where n is the length of `nums`. Each element is visited at most twice (once by right pointer, once by left pointer).
8+
- **Space Complexity:** O(1) - We use only a constant amount of extra space.
9+
- **Edge Case:** If the sum of all elements is less than `target`, return 0.
10+
11+
**1.2 High-level approach:**
12+
The goal is to find the minimal length subarray whose sum is at least `target`. We use a sliding window approach to efficiently find the minimum valid subarray.
13+
14+
**1.3 Brute force vs. optimized strategy:**
15+
- **Brute Force:** Check all possible subarrays and find the minimum length. This is O(n^2) time.
16+
- **Optimized Strategy:** Use a sliding window (two pointers). Expand the window by moving the right pointer, and shrink it by moving the left pointer when the sum is sufficient. This is O(n) time.
17+
- **Why optimized is better:** We avoid checking all subarrays and use the sliding window to efficiently find the minimum length.
18+
19+
**1.4 Decomposition:**
20+
1. Use two pointers: `left` (start of window) and `right` (end of window).
21+
2. Expand the window by moving `right` and adding elements to the sum.
22+
3. When the sum is >= `target`, try to shrink the window by moving `left` to find a smaller valid subarray.
23+
4. Track the minimum length found.
24+
5. Return the minimum length or 0 if no valid subarray exists.
25+
26+
### Steps (The "How")
27+
28+
**2.1 Initialization & Example Setup:**
29+
Let's use the example: `target = 7`, `nums = [2,3,1,2,4,3]`
30+
31+
Initialize `left = 0`, `res = inf`, `current_sum = 0`.
32+
33+
**2.2 Start Checking:**
34+
Expand the window by moving `right` from 0 to len(nums)-1.
35+
36+
**2.3 Trace Walkthrough:**
37+
38+
| right | nums[right] | current_sum | current_sum >= 7? | Action | res |
39+
|-------|-------------|--------------|-------------------|--------|-----|
40+
| 0 | 2 | 2 | No | Continue | inf |
41+
| 1 | 3 | 5 | No | Continue | inf |
42+
| 2 | 1 | 6 | No | Continue | inf |
43+
| 3 | 2 | 8 | Yes | Shrink: left=1, sum=6 | 4 |
44+
| 4 | 4 | 10 | Yes | Shrink: left=3, sum=6 | 2 |
45+
| 5 | 3 | 7 | Yes | Shrink: left=4, sum=3 | 2 |
46+
47+
**2.4 Increment and Loop:**
48+
For each `right`:
49+
- Add `nums[right]` to `current_sum`
50+
- While `current_sum >= target`:
51+
- Update `res = min(res, right - left + 1)`
52+
- Subtract `nums[left]` and increment `left`
53+
54+
**2.5 Return Result:**
55+
Minimum length found is 2 (subarray [4,3] with sum 7). Return `2`.
56+

explanations/210/en.md

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
## Explanation
2+
3+
### Strategy (The "Why")
4+
5+
**1.1 Constraints & Complexity:**
6+
- **Constraints:** `numCourses` ranges from 1 to 2000, and there are up to `numCourses * (numCourses - 1)` prerequisite pairs.
7+
- **Time Complexity:** O(V + E) where V is the number of courses and E is the number of prerequisites. We visit each course once and process each edge once.
8+
- **Space Complexity:** O(V + E) for the graph adjacency list, in-degree array, and result list.
9+
- **Edge Case:** If there are no prerequisites, return any valid ordering (e.g., [0, 1, 2, ..., numCourses-1]).
10+
11+
**1.2 High-level approach:**
12+
The goal is to find a valid course ordering that satisfies all prerequisites. This is a topological sorting problem. If a cycle exists, return an empty array.
13+
14+
**1.3 Brute force vs. optimized strategy:**
15+
- **Brute Force:** Try all possible orderings and check if they satisfy prerequisites. This is exponential time.
16+
- **Optimized Strategy:** Use Kahn's algorithm (topological sort with BFS). Process courses with no prerequisites first, then their dependents, building the ordering as we go.
17+
- **Why optimized is better:** Linear time complexity and naturally produces a valid topological ordering.
18+
19+
**1.4 Decomposition:**
20+
1. Build an adjacency list representing the course dependency graph.
21+
2. Calculate in-degree (number of prerequisites) for each course.
22+
3. Start with courses that have no prerequisites (in-degree = 0).
23+
4. For each completed course, add it to the result and reduce the in-degree of its dependent courses.
24+
5. If a dependent course's in-degree becomes 0, add it to the queue.
25+
6. If we process all courses, return the result; otherwise, return an empty array (cycle detected).
26+
27+
### Steps (The "How")
28+
29+
**2.1 Initialization & Example Setup:**
30+
Let's use the example: `numCourses = 4`, `prerequisites = [[1,0],[2,0],[3,1],[3,2]]`
31+
32+
Build graph: `graph[0] = [1,2]`, `graph[1] = [3]`, `graph[2] = [3]`
33+
In-degrees: `in_degree[0] = 0`, `in_degree[1] = 1`, `in_degree[2] = 1`, `in_degree[3] = 2`
34+
35+
**2.2 Start Checking:**
36+
Initialize queue with courses having in-degree 0: `queue = [0]`, `res = []`
37+
38+
**2.3 Trace Walkthrough:**
39+
40+
| Step | Queue | Course | res | Update in-degrees | New Queue |
41+
|------|-------|--------|-----|-------------------|-----------|
42+
| 0 | [0] | - | [] | - | - |
43+
| 1 | [0] | 0 | [0] | `in_degree[1]=0, in_degree[2]=0` | [1,2] |
44+
| 2 | [1,2] | 1 | [0,1] | `in_degree[3]=1` | [2] |
45+
| 3 | [2] | 2 | [0,1,2] | `in_degree[3]=0` | [3] |
46+
| 4 | [3] | 3 | [0,1,2,3] | - | [] |
47+
48+
**2.4 Increment and Loop:**
49+
For each course in the queue:
50+
- Remove it and append to result
51+
- For each dependent course, decrement its in-degree
52+
- If in-degree becomes 0, add to queue
53+
54+
**2.5 Return Result:**
55+
`res = [0,1,2,3]` and `len(res) = 4` equals `numCourses = 4`, so return `[0,1,2,3]` (or any valid ordering like `[0,2,1,3]`).
56+

0 commit comments

Comments
 (0)