diff --git a/Hard/2742 Painting the Walls.md b/Hard/2742 Painting the Walls.md new file mode 100644 index 0000000..0dad8e3 --- /dev/null +++ b/Hard/2742 Painting the Walls.md @@ -0,0 +1,50 @@ +# 2742. Painting the Walls + +## Intuition + +The key insight is that while a paid painter is painting one wall, the free painter can paint other walls during that time. We can use this to optimize our solution by considering the trade-off between cost and time. + +## Approach + +1. We use dynamic programming where `dp[i]` represents the minimum cost to paint `i` walls +2. Initialize dp array with maximum values except dp[0] = 0 +3. For each wall: + - We consider using the paid painter for this wall + - While paid painter works on current wall, free painter can paint `time[i]` walls + - We update dp[k] where k is min(total_walls, current_walls + 1 + time[i]) + - The minimum cost would be either existing cost or cost of painting current wall plus previous state +4. The final answer is stored in dp[len(cost)] + +## Complexity + +- Time complexity: O(n^2) +- Space complexity: O(n) + +## Keywords + +- Dynamic Programming +- Array +- Optimization +- Minimum Cost +- Two Painters Problem + +## Code + +```go +func paintWalls(cost []int, time []int) int { + dp := make([]int, len(cost)+1) + for i := range dp { + dp[i] = math.MaxInt32 + } + dp[0] = 0 + + for i := range cost { + for j := len(cost)-1; j >= 0; j -= 1 { + k := min(len(cost), j+1+time[i]) + dp[k] = min(dp[k], dp[j]+cost[i]) + } + } + + return dp[len(cost)] +} +``` diff --git a/Hard/44 Wildcard Matching.md b/Hard/44 Wildcard Matching.md new file mode 100644 index 0000000..4b3ccf5 --- /dev/null +++ b/Hard/44 Wildcard Matching.md @@ -0,0 +1,52 @@ +# 44. Wildcard Matching + +## Intuition + +This problem can be solved using a greedy approach with two pointers. The key insight is to handle the '*' character differently from other characters. When we encounter a '*', we keep track of its position and the position in the string where we matched it, so we can try different matching lengths for the '*' if needed. + +## Approach + +1. Use two pointers `ss` and `pp` to track positions in string `s` and pattern `p` respectively +2. Keep track of the latest '*' position (`latestStar`) and the position in string where we started matching this '*' (`latestStarMatch`) +3. For each character in string s: + - If current characters match (same char or '?'), move both pointers forward + - If we see a '*', record its position and current string position, then move pattern pointer + - If characters don't match but we have a previous '*', backtrack to try matching one more character with that '*' + - If none of above works, return false +4. After processing string s, check if remaining pattern only contains '*' + +## Complexity + +- Time complexity: O(S*P) +- Space complexity: O(1) + +## Keywords + +- Two Pointers +- Greedy Algorithm +- Pattern Matching + +## Code + +```go +func isMatch(s string, p string) bool { + ss, pp, latestStar, latestStarMatch := 0, 0, -1, 0 + + for ss < len(s) { + if pp < len(p) && (p[pp] == '?' || p[pp] == s[ss]) { + ss, pp = ss+1, pp+1 + } else if pp < len(p) && p[pp] == '*' { + latestStar, latestStarMatch, pp = pp, ss, pp+1 + } else if latestStar != -1 { + pp, latestStarMatch, ss = latestStar+1, latestStarMatch+1, latestStarMatch+1 + } else { + return false + } + } + + for pp < len(p) && p[pp] == '*' { + pp += 1 + } + return pp == len(p) +} +``` diff --git a/Medium/435 Non-overlapping Intervals.md b/Medium/435 Non-overlapping Intervals.md new file mode 100644 index 0000000..d73cc2b --- /dev/null +++ b/Medium/435 Non-overlapping Intervals.md @@ -0,0 +1,53 @@ +# 435. Non-overlapping Intervals + +## Intuition + +To minimize the number of intervals that need to be removed to make the remaining intervals non-overlapping, we should: + +1. Sort the intervals by their end time +2. Keep track of the current end time +3. Remove intervals that overlap with the current end time + +## Approach + +1. Sort all intervals based on their end time in ascending order +2. Initialize variables: + - `end`: tracks the end time of the last valid interval (initialized to -50001) + - `ret`: counts the number of intervals that need to be removed +3. Iterate through the sorted intervals: + - If current interval's start time is greater than or equal to previous end time: + - Update end time to current interval's end time + - Otherwise: + - Increment the removal counter (ret) +4. Return the total number of intervals that need to be removed + +## Complexity + +- Time complexity: O(nlogn) +- Space complexity: O(1) + +## Keywords + +- Array +- Sorting +- Greedy +- Interval Scheduling + +## Code + +```go +func eraseOverlapIntervals(intervals [][]int) int { + sort.Slice(intervals, func(i, j int) bool { + return intervals[i][1] < intervals[j][1] + }) + end, ret := -50001, 0 + for _, interval := range intervals { + if end <= interval[0] { + end = interval[1] + } else { + ret += 1 + } + } + return ret +} +``` diff --git a/README.md b/README.md index fa192e2..28296f7 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,7 @@ | 23 | Merge k Sorted Lists | [go](/Hard/23%20Merge%20k%20Sorted%20Lists.md) | H | | 24 | Swap Nodes in Pairs | [go](/Medium/24%20Swap%20Nodes%20in%20Pairs.md) | M | | 25 | Reverse Nodes in k-Group | [go](/Hard/25%20Reverse%20Nodes%20in%20k-Group.md) | H | +| 44 | Wildcard Matching | [go](/Hard/44%20Wildcard%20Matching.md) | H | | 45 | Jump Game II | [go](/Medium/45%20Jump%20Game%20II.md) | M | | 46 | Permutations | [go](/Medium/46%20Permutations.md) | M | | 50 | Pow(x, n) | [go](/Medium/50%20Pow(x,%20n).md) | M | @@ -25,6 +26,7 @@ | 236 | Lowest Common Ancestor of a Binary Tree | [go](/Medium/236%20Lowest%20Common%20Ancestor%20of%20a%20Binary%20Tree.md) | M | | 239 | Sliding Window Maximum | [go](/Hard/239%20Sliding%20Window%20Maximum.md) | H | | 322 | Coin Change | [go](/Medium/322%20Coin%20Change.md) | M | +| 435 | Non-overlapping Interval | [go](/Medium/435%20Non-overlapping%20Intervals.md) | M | | 460 | LFU Cache | [go](/Hard/460%20LFU%20Cache.md) | H | | 592 | Fraction Addition and Subtraction | [go](/Medium/592%20Fraction%20Addition%20and%20Subtraction.md) | M | | 752 | Open the Lock | [go](/Medium/752%20Open%20the%20Lock.md) | M | @@ -38,4 +40,5 @@ | 948 | Bag of Tokens | [go](/Medium/948%20Bag%20Of%20Tokens.md) | M | | 1395 | Count Number of Trams | [go](/Medium/1395%20Count%20Number%20of%20Teams.md) | M | | 2366 | Mimimum Replacements to Sort the Array | [go](/Hard/2366%20Minimum%20Replacements%20to%20Sort%20the%20Array.md) | H | +| 2742 | Paiting the Walls | [go](/Hard/2742%20Painting%20the%20Walls.md) | H | | 2932 | Build A Matrix with Conditions | [go](/Hard/2932%20Build%20A%20Matrix%20With%20Conditions.md) | H | diff --git a/Week9/2742 AC.png b/Week9/2742 AC.png new file mode 100644 index 0000000..8aa983a Binary files /dev/null and b/Week9/2742 AC.png differ diff --git a/Week9/2742 Painting the Walls.md b/Week9/2742 Painting the Walls.md new file mode 100644 index 0000000..0dad8e3 --- /dev/null +++ b/Week9/2742 Painting the Walls.md @@ -0,0 +1,50 @@ +# 2742. Painting the Walls + +## Intuition + +The key insight is that while a paid painter is painting one wall, the free painter can paint other walls during that time. We can use this to optimize our solution by considering the trade-off between cost and time. + +## Approach + +1. We use dynamic programming where `dp[i]` represents the minimum cost to paint `i` walls +2. Initialize dp array with maximum values except dp[0] = 0 +3. For each wall: + - We consider using the paid painter for this wall + - While paid painter works on current wall, free painter can paint `time[i]` walls + - We update dp[k] where k is min(total_walls, current_walls + 1 + time[i]) + - The minimum cost would be either existing cost or cost of painting current wall plus previous state +4. The final answer is stored in dp[len(cost)] + +## Complexity + +- Time complexity: O(n^2) +- Space complexity: O(n) + +## Keywords + +- Dynamic Programming +- Array +- Optimization +- Minimum Cost +- Two Painters Problem + +## Code + +```go +func paintWalls(cost []int, time []int) int { + dp := make([]int, len(cost)+1) + for i := range dp { + dp[i] = math.MaxInt32 + } + dp[0] = 0 + + for i := range cost { + for j := len(cost)-1; j >= 0; j -= 1 { + k := min(len(cost), j+1+time[i]) + dp[k] = min(dp[k], dp[j]+cost[i]) + } + } + + return dp[len(cost)] +} +``` diff --git a/Week9/435 AC.png b/Week9/435 AC.png new file mode 100644 index 0000000..7011758 Binary files /dev/null and b/Week9/435 AC.png differ diff --git a/Week9/435 Non-overlapping Intervals.md b/Week9/435 Non-overlapping Intervals.md new file mode 100644 index 0000000..d73cc2b --- /dev/null +++ b/Week9/435 Non-overlapping Intervals.md @@ -0,0 +1,53 @@ +# 435. Non-overlapping Intervals + +## Intuition + +To minimize the number of intervals that need to be removed to make the remaining intervals non-overlapping, we should: + +1. Sort the intervals by their end time +2. Keep track of the current end time +3. Remove intervals that overlap with the current end time + +## Approach + +1. Sort all intervals based on their end time in ascending order +2. Initialize variables: + - `end`: tracks the end time of the last valid interval (initialized to -50001) + - `ret`: counts the number of intervals that need to be removed +3. Iterate through the sorted intervals: + - If current interval's start time is greater than or equal to previous end time: + - Update end time to current interval's end time + - Otherwise: + - Increment the removal counter (ret) +4. Return the total number of intervals that need to be removed + +## Complexity + +- Time complexity: O(nlogn) +- Space complexity: O(1) + +## Keywords + +- Array +- Sorting +- Greedy +- Interval Scheduling + +## Code + +```go +func eraseOverlapIntervals(intervals [][]int) int { + sort.Slice(intervals, func(i, j int) bool { + return intervals[i][1] < intervals[j][1] + }) + end, ret := -50001, 0 + for _, interval := range intervals { + if end <= interval[0] { + end = interval[1] + } else { + ret += 1 + } + } + return ret +} +``` diff --git a/Week9/44 AC.png b/Week9/44 AC.png new file mode 100644 index 0000000..98c04f5 Binary files /dev/null and b/Week9/44 AC.png differ diff --git a/Week9/44 Wildcard Matching.md b/Week9/44 Wildcard Matching.md new file mode 100644 index 0000000..4b3ccf5 --- /dev/null +++ b/Week9/44 Wildcard Matching.md @@ -0,0 +1,52 @@ +# 44. Wildcard Matching + +## Intuition + +This problem can be solved using a greedy approach with two pointers. The key insight is to handle the '*' character differently from other characters. When we encounter a '*', we keep track of its position and the position in the string where we matched it, so we can try different matching lengths for the '*' if needed. + +## Approach + +1. Use two pointers `ss` and `pp` to track positions in string `s` and pattern `p` respectively +2. Keep track of the latest '*' position (`latestStar`) and the position in string where we started matching this '*' (`latestStarMatch`) +3. For each character in string s: + - If current characters match (same char or '?'), move both pointers forward + - If we see a '*', record its position and current string position, then move pattern pointer + - If characters don't match but we have a previous '*', backtrack to try matching one more character with that '*' + - If none of above works, return false +4. After processing string s, check if remaining pattern only contains '*' + +## Complexity + +- Time complexity: O(S*P) +- Space complexity: O(1) + +## Keywords + +- Two Pointers +- Greedy Algorithm +- Pattern Matching + +## Code + +```go +func isMatch(s string, p string) bool { + ss, pp, latestStar, latestStarMatch := 0, 0, -1, 0 + + for ss < len(s) { + if pp < len(p) && (p[pp] == '?' || p[pp] == s[ss]) { + ss, pp = ss+1, pp+1 + } else if pp < len(p) && p[pp] == '*' { + latestStar, latestStarMatch, pp = pp, ss, pp+1 + } else if latestStar != -1 { + pp, latestStarMatch, ss = latestStar+1, latestStarMatch+1, latestStarMatch+1 + } else { + return false + } + } + + for pp < len(p) && p[pp] == '*' { + pp += 1 + } + return pp == len(p) +} +```