diff --git a/easy/3024 Type of Triangle.md b/Easy/3024 Type of Triangle.md similarity index 100% rename from easy/3024 Type of Triangle.md rename to Easy/3024 Type of Triangle.md diff --git a/Hard/895 Maximum Frequency Stack.md b/Hard/895 Maximum Frequency Stack.md new file mode 100644 index 0000000..1c2de12 --- /dev/null +++ b/Hard/895 Maximum Frequency Stack.md @@ -0,0 +1,79 @@ +# 895. Maximum Frequency Stack + +## Intuition + +The problem requires us to implement a stack-like data structure that can track the frequency of elements and pop the most frequent element. When multiple elements have the same frequency, we need to pop the one that was pushed most recently. The key insight is to maintain a frequency map and a stack of stacks, where each inner stack contains elements of the same frequency. + +## Approach + +1. Use a `freqMap` to track the frequency of each element +2. Use a `freqStack` which is a 2D slice where: + - Each inner slice represents elements of the same frequency + - The index of the inner slice represents the frequency level + - Elements in the same inner slice maintain their push order +3. For Push operation: + - If element is new or has frequency -1, add it to frequency level 0 + - Otherwise, increment its frequency and add it to the corresponding level +4. For Pop operation: + - Remove the last element from the highest frequency level + - Decrement its frequency in the map + - Remove the frequency level if it becomes empty + +## Complexity + +- Time complexity: O(1) +- Space complexity: O(n) + +## Keywords + +- Stack +- Hash Map + +## Code + +```go +type FreqStack struct { + freqMap map[int]int + freqStack [][]int +} + + +func Constructor() FreqStack { + f := FreqStack{ + freqMap: make(map[int]int), + freqStack: make([][]int, 0), + } + f.freqStack = append(f.freqStack, make([]int, 0)) + return f +} + + +func (f *FreqStack) Push(val int) { + if level, found := f.freqMap[val]; !found || level == -1 { + f.freqStack[0], f.freqMap[val] = append(f.freqStack[0], val), 0 + } else { + if len(f.freqStack) - 1 == level { + f.freqStack = append(f.freqStack, make([]int, 0)) + } + f.freqStack[level + 1], f.freqMap[val] = append(f.freqStack[level + 1], val), level + 1 + } +} + + +func (f *FreqStack) Pop() int { + tgt := f.freqStack[len(f.freqStack) - 1][len(f.freqStack[len(f.freqStack) - 1]) - 1] + f.freqStack[len(f.freqStack) - 1], f.freqMap[tgt] = f.freqStack[len(f.freqStack) - 1][: len(f.freqStack[len(f.freqStack) - 1]) - 1], f.freqMap[tgt] - 1 + if len(f.freqStack[len(f.freqStack) - 1]) == 0 { + f.freqStack = f.freqStack[: len(f.freqStack) - 1] + } + return tgt +} + + +/** + * Your FreqStack object will be instantiated and called as such: + * obj := Constructor(); + * obj.Push(val); + * param_2 := obj.Pop(); + */ +``` diff --git a/Medium/1209 Remove All Adjacent Duplicates in String II.md b/Medium/1209 Remove All Adjacent Duplicates in String II.md new file mode 100644 index 0000000..5a1a4ca --- /dev/null +++ b/Medium/1209 Remove All Adjacent Duplicates in String II.md @@ -0,0 +1,62 @@ +# 1209. Remove All Adjacent Duplicates in String II + +## Intuition + +The problem requires us to remove k adjacent duplicate characters from a string. We can use a stack-based approach where we keep track of both the character and its count. When we encounter k consecutive same characters, we remove them from the stack. + +## Approach + +1. Create a stack to store pairs of (character, count) +2. Iterate through each character in the string: + - If stack is empty, push the character with count 1 + - If current character matches the top of stack: + - Increment the count + - If count reaches k, pop the element from stack + - If current character is different, push it with count 1 +3. Finally, reconstruct the string from the stack by repeating each character according to its count + +## Complexity + +- Time complexity: O(n) +- Space complexity: O(n) + +## Keywords + +- Stack +- String Manipulation + +## Code + +```go +func removeDuplicates(s string, k int) string { + type unit struct { + char rune + cnt int + } + + st := make([]unit, 0) + + for _, char := range s { + if len(st) == 0 { + st = append(st, unit{char: char, cnt: 1}) + continue + } + if st[len(st) - 1].char == char { + st[len(st) - 1].cnt += 1 + if st[len(st) - 1].cnt == k { + st = st[:len(st) - 1] + } + continue + } + st = append(st, unit{char: char, cnt: 1}) + } + + ret := "" + for _, u := range st { + for i := 0; i < u.cnt; i += 1 { + ret += string(u.char) + } + } + return ret +} +``` diff --git a/Medium/316. Remove Duplicate Letters.md b/Medium/316. Remove Duplicate Letters.md new file mode 100644 index 0000000..9ad4452 --- /dev/null +++ b/Medium/316. Remove Duplicate Letters.md @@ -0,0 +1,57 @@ +# 316. Remove Duplicate Letters + +## Intuition + +The problem requires us to remove duplicate letters from a string while maintaining the lexicographically smallest possible result. We need to ensure that: + +1. Each character appears only once in the result +2. The relative order of characters is preserved +3. The result is lexicographically smallest among all possible results + +## Approach + +1. First, we create a map `lastSeen` to record the last occurrence of each character in the string +2. We use a stack (`st`) to build our result and a set (`seen`) to track characters we've already included +3. For each character in the string: + - If we haven't seen it before, we try to add it to our result + - Before adding, we check if we can remove characters from the stack that are: + - Greater than the current character (to maintain lexicographical order) + - Will appear again later in the string (using lastSeen map) +4. Finally, we convert the stack to a string and return it + +## Complexity + +- Time complexity: O(n) +- Space complexity: O(n) + +## Keywords + +- Stack +- Greedy +- String +- Hash Map +- Lexicographical Order + +## Code + +```go +func removeDuplicateLetters(s string) string { + lastSeen := make(map[rune]int) + for i, c := range s { + lastSeen[c] = i + } + + st, seen := make([]rune, 0), make(map[rune]bool) + for i, c := range s { + if !seen[c] { + for len(st) > 0 && c < st[len(st) - 1] && i < lastSeen[st[len(st) - 1]] { + delete(seen, st[len(st) - 1]) + st = st[: len(st) - 1] + } + seen[c], st = true, append(st, c) + } + } + + return string(st) +} +``` diff --git a/README.md b/README.md index aa8f61e..b319c44 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,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 | | 312 | Burst Balloons | [go](/Hard/312%20Burst%20Balloons.md) | H | +| 316 | Remove Duplicate Letters | [go](/Medium/316.%20Remove%20Duplicate%20Letters.md) | M | | 322 | Coin Change | [go](/Medium/322%20Coin%20Change.md) | M | | 416 | Partition Equal Subset Sum | [go](/Medium/416%20Partition%20Equal%20Subset%20Sum.md) | M | | 435 | Non-overlapping Interval | [go](/Medium/435%20Non-overlapping%20Intervals.md) | M | @@ -46,8 +47,10 @@ | 875 | Koko Eating Bananas | [go](/Medium/875%20Koko%20Eating%20Bananas.md) | M | | 881 | Boats to Save People | [go](/Medium/881%20Boats%20to%20Save%20People.md) | M | | 887 | Super Egg Drop | [go](/Hard/887%20Super%20Egg%20Drop.md) | H | +| 895 | Maximum Frequency Stack | [go](/Hard/895%20Maximum%20Frequency%20Stack.md) | H | | 912 | Sort an Array | [go](/Medium/912%20Sort%20an%20Array.md) | M | | 948 | Bag of Tokens | [go](/Medium/948%20Bag%20Of%20Tokens.md) | M | +| 1209 | Remove All Adjacent Duplicates in String II | [go](/Medium/1209%20Remove%20All%20Adjacent%20Duplicates%20in%20String%20II.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 | | 2444 | Count Subarrays With Fixed Bounds | [go](/Hard/2444%20Count%20Subarrays%20With%20Fixed%20Bounds.md) | H | diff --git a/Week13/1209 AC.png b/Week13/1209 AC.png new file mode 100644 index 0000000..ed22965 Binary files /dev/null and b/Week13/1209 AC.png differ diff --git a/Week13/1209 Remove All Adjacent Duplicates in String II.md b/Week13/1209 Remove All Adjacent Duplicates in String II.md new file mode 100644 index 0000000..5a1a4ca --- /dev/null +++ b/Week13/1209 Remove All Adjacent Duplicates in String II.md @@ -0,0 +1,62 @@ +# 1209. Remove All Adjacent Duplicates in String II + +## Intuition + +The problem requires us to remove k adjacent duplicate characters from a string. We can use a stack-based approach where we keep track of both the character and its count. When we encounter k consecutive same characters, we remove them from the stack. + +## Approach + +1. Create a stack to store pairs of (character, count) +2. Iterate through each character in the string: + - If stack is empty, push the character with count 1 + - If current character matches the top of stack: + - Increment the count + - If count reaches k, pop the element from stack + - If current character is different, push it with count 1 +3. Finally, reconstruct the string from the stack by repeating each character according to its count + +## Complexity + +- Time complexity: O(n) +- Space complexity: O(n) + +## Keywords + +- Stack +- String Manipulation + +## Code + +```go +func removeDuplicates(s string, k int) string { + type unit struct { + char rune + cnt int + } + + st := make([]unit, 0) + + for _, char := range s { + if len(st) == 0 { + st = append(st, unit{char: char, cnt: 1}) + continue + } + if st[len(st) - 1].char == char { + st[len(st) - 1].cnt += 1 + if st[len(st) - 1].cnt == k { + st = st[:len(st) - 1] + } + continue + } + st = append(st, unit{char: char, cnt: 1}) + } + + ret := "" + for _, u := range st { + for i := 0; i < u.cnt; i += 1 { + ret += string(u.char) + } + } + return ret +} +``` diff --git a/Week13/316 AC.png b/Week13/316 AC.png new file mode 100644 index 0000000..254dd4e Binary files /dev/null and b/Week13/316 AC.png differ diff --git a/Week13/316. Remove Duplicate Letters.md b/Week13/316. Remove Duplicate Letters.md new file mode 100644 index 0000000..9ad4452 --- /dev/null +++ b/Week13/316. Remove Duplicate Letters.md @@ -0,0 +1,57 @@ +# 316. Remove Duplicate Letters + +## Intuition + +The problem requires us to remove duplicate letters from a string while maintaining the lexicographically smallest possible result. We need to ensure that: + +1. Each character appears only once in the result +2. The relative order of characters is preserved +3. The result is lexicographically smallest among all possible results + +## Approach + +1. First, we create a map `lastSeen` to record the last occurrence of each character in the string +2. We use a stack (`st`) to build our result and a set (`seen`) to track characters we've already included +3. For each character in the string: + - If we haven't seen it before, we try to add it to our result + - Before adding, we check if we can remove characters from the stack that are: + - Greater than the current character (to maintain lexicographical order) + - Will appear again later in the string (using lastSeen map) +4. Finally, we convert the stack to a string and return it + +## Complexity + +- Time complexity: O(n) +- Space complexity: O(n) + +## Keywords + +- Stack +- Greedy +- String +- Hash Map +- Lexicographical Order + +## Code + +```go +func removeDuplicateLetters(s string) string { + lastSeen := make(map[rune]int) + for i, c := range s { + lastSeen[c] = i + } + + st, seen := make([]rune, 0), make(map[rune]bool) + for i, c := range s { + if !seen[c] { + for len(st) > 0 && c < st[len(st) - 1] && i < lastSeen[st[len(st) - 1]] { + delete(seen, st[len(st) - 1]) + st = st[: len(st) - 1] + } + seen[c], st = true, append(st, c) + } + } + + return string(st) +} +``` diff --git a/Week13/895 AC.png b/Week13/895 AC.png new file mode 100644 index 0000000..b9515a7 Binary files /dev/null and b/Week13/895 AC.png differ diff --git a/Week13/895 Maximum Frequency Stack.md b/Week13/895 Maximum Frequency Stack.md new file mode 100644 index 0000000..1c2de12 --- /dev/null +++ b/Week13/895 Maximum Frequency Stack.md @@ -0,0 +1,79 @@ +# 895. Maximum Frequency Stack + +## Intuition + +The problem requires us to implement a stack-like data structure that can track the frequency of elements and pop the most frequent element. When multiple elements have the same frequency, we need to pop the one that was pushed most recently. The key insight is to maintain a frequency map and a stack of stacks, where each inner stack contains elements of the same frequency. + +## Approach + +1. Use a `freqMap` to track the frequency of each element +2. Use a `freqStack` which is a 2D slice where: + - Each inner slice represents elements of the same frequency + - The index of the inner slice represents the frequency level + - Elements in the same inner slice maintain their push order +3. For Push operation: + - If element is new or has frequency -1, add it to frequency level 0 + - Otherwise, increment its frequency and add it to the corresponding level +4. For Pop operation: + - Remove the last element from the highest frequency level + - Decrement its frequency in the map + - Remove the frequency level if it becomes empty + +## Complexity + +- Time complexity: O(1) +- Space complexity: O(n) + +## Keywords + +- Stack +- Hash Map + +## Code + +```go +type FreqStack struct { + freqMap map[int]int + freqStack [][]int +} + + +func Constructor() FreqStack { + f := FreqStack{ + freqMap: make(map[int]int), + freqStack: make([][]int, 0), + } + f.freqStack = append(f.freqStack, make([]int, 0)) + return f +} + + +func (f *FreqStack) Push(val int) { + if level, found := f.freqMap[val]; !found || level == -1 { + f.freqStack[0], f.freqMap[val] = append(f.freqStack[0], val), 0 + } else { + if len(f.freqStack) - 1 == level { + f.freqStack = append(f.freqStack, make([]int, 0)) + } + f.freqStack[level + 1], f.freqMap[val] = append(f.freqStack[level + 1], val), level + 1 + } +} + + +func (f *FreqStack) Pop() int { + tgt := f.freqStack[len(f.freqStack) - 1][len(f.freqStack[len(f.freqStack) - 1]) - 1] + f.freqStack[len(f.freqStack) - 1], f.freqMap[tgt] = f.freqStack[len(f.freqStack) - 1][: len(f.freqStack[len(f.freqStack) - 1]) - 1], f.freqMap[tgt] - 1 + if len(f.freqStack[len(f.freqStack) - 1]) == 0 { + f.freqStack = f.freqStack[: len(f.freqStack) - 1] + } + return tgt +} + + +/** + * Your FreqStack object will be instantiated and called as such: + * obj := Constructor(); + * obj.Push(val); + * param_2 := obj.Pop(); + */ +```