From c4d8eb88af51d1d9bc3806e114e8c508c15ceb17 Mon Sep 17 00:00:00 2001 From: Sri Hari Date: Mon, 27 Jan 2025 20:50:29 +0530 Subject: [PATCH 1/7] Batch-5/Neetcode-ALL/Added-articles --- articles/132-pattern.md | 420 ++++++++++++++++ articles/flatten-nested-list-iterator.md | 142 ++++++ articles/make-the-string-great.md | 2 +- ...ve-all-adjacent-duplicates-in-string-ii.md | 467 ++++++++++++++++++ articles/remove-k-digits.md | 344 +++++++++++++ articles/removing-stars-from-a-string.md | 357 +++++++++++++ articles/validate-stack-sequences.md | 160 ++++++ 7 files changed, 1891 insertions(+), 1 deletion(-) create mode 100644 articles/132-pattern.md create mode 100644 articles/flatten-nested-list-iterator.md create mode 100644 articles/remove-all-adjacent-duplicates-in-string-ii.md create mode 100644 articles/remove-k-digits.md create mode 100644 articles/removing-stars-from-a-string.md create mode 100644 articles/validate-stack-sequences.md diff --git a/articles/132-pattern.md b/articles/132-pattern.md new file mode 100644 index 000000000..b0dc31957 --- /dev/null +++ b/articles/132-pattern.md @@ -0,0 +1,420 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def find132pattern(self, nums: List[int]) -> bool: + n = len(nums) + + for k in range(2, n): + for j in range(k - 1, 0, -1): + if nums[j] <= nums[k]: + continue + + for i in range(j - 1, -1, -1): + if nums[i] < nums[k]: + return True + + return False +``` + +```java +public class Solution { + public boolean find132pattern(int[] nums) { + int n = nums.length; + + for (int k = 2; k < n; k++) { + for (int j = k - 1; j > 0; j--) { + if (nums[j] <= nums[k]) { + continue; + } + + for (int i = j - 1; i >= 0; i--) { + if (nums[i] < nums[k]) { + return true; + } + } + } + } + + return false; + } +} +``` + +```cpp +class Solution { +public: + bool find132pattern(vector& nums) { + int n = nums.size(); + + for (int k = 2; k < n; k++) { + for (int j = k - 1; j > 0; j--) { + if (nums[j] <= nums[k]) { + continue; + } + + for (int i = j - 1; i >= 0; i--) { + if (nums[i] < nums[k]) { + return true; + } + } + } + } + + return false; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {boolean} + */ + find132pattern(nums) { + let n = nums.length; + + for (let k = 2; k < n; k++) { + for (let j = k - 1; j > 0; j--) { + if (nums[j] <= nums[k]) { + continue; + } + + for (let i = j - 1; i >= 0; i--) { + if (nums[i] < nums[k]) { + return true; + } + } + } + } + + return false; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 2)$ +* Space complexity: $O(1)$ + +--- + +## 2. Stack + +::tabs-start + +```python +class Solution: + def find132pattern(self, nums: List[int]) -> bool: + stack = [] # pair [num, minLeft], mono decreasing + curMin = nums[0] + + for i in range(1, len(nums)): + while stack and nums[i] >= stack[-1][0]: + stack.pop() + if stack and nums[i] > stack[-1][1]: + return True + + stack.append([nums[i], curMin]) + curMin = min(curMin, nums[i]) + + return False +``` + +```java +public class Solution { + public boolean find132pattern(int[] nums) { + Stack stack = new Stack<>(); // pair [num, minLeft] + int curMin = nums[0]; + + for (int i = 1; i < nums.length; i++) { + while (!stack.isEmpty() && nums[i] >= stack.peek()[0]) { + stack.pop(); + } + if (!stack.isEmpty() && nums[i] > stack.peek()[1]) { + return true; + } + + stack.push(new int[]{nums[i], curMin}); + curMin = Math.min(curMin, nums[i]); + } + + return false; + } +} +``` + +```cpp +class Solution { +public: + bool find132pattern(vector& nums) { + stack> stack; // pair + int curMin = nums[0]; + + for (int i = 1; i < nums.size(); i++) { + while (!stack.empty() && nums[i] >= stack.top().first) { + stack.pop(); + } + if (!stack.empty() && nums[i] > stack.top().second) { + return true; + } + + stack.push({nums[i], curMin}); + curMin = min(curMin, nums[i]); + } + + return false; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {boolean} + */ + find132pattern(nums) { + const stack = []; // pair [num, minLeft] + let curMin = nums[0]; + + for (let i = 1; i < nums.length; i++) { + while (stack.length > 0 && nums[i] >= stack[stack.length - 1][0]) { + stack.pop(); + } + if (stack.length > 0 && nums[i] > stack[stack.length - 1][1]) { + return true; + } + + stack.push([nums[i], curMin]); + curMin = Math.min(curMin, nums[i]); + } + + return false; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ + +--- + +## 3. Stack (Optimal) + +::tabs-start + +```python +class Solution: + def find132pattern(self, nums: List[int]) -> bool: + stack, k = [], float('-inf') + + for i in range(len(nums) - 1, -1, -1): + if nums[i] < k: + return True + + while stack and stack[-1] < nums[i]: + k = stack.pop() + stack.append(nums[i]) + + return False +``` + +```java +public class Solution { + public boolean find132pattern(int[] nums) { + Stack stack = new Stack<>(); + int k = Integer.MIN_VALUE; + + for (int i = nums.length - 1; i >= 0; i--) { + if (nums[i] < k) { + return true; + } + + while (!stack.isEmpty() && stack.peek() < nums[i]) { + k = stack.pop(); + } + stack.push(nums[i]); + } + + return false; + } +} +``` + +```cpp +class Solution { +public: + bool find132pattern(vector& nums) { + stack stack; + int k = INT_MIN; + + for (int i = nums.size() - 1; i >= 0; i--) { + if (nums[i] < k) { + return true; + } + + while (!stack.empty() && stack.top() < nums[i]) { + k = stack.top(); + stack.pop(); + } + stack.push(nums[i]); + } + + return false; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {boolean} + */ + find132pattern(nums) { + const stack = []; + let k = -Infinity; + + for (let i = nums.length - 1; i >= 0; i--) { + if (nums[i] < k) { + return true; + } + + while (stack.length > 0 && stack[stack.length - 1] < nums[i]) { + k = stack.pop(); + } + stack.push(nums[i]); + } + + return false; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ + +--- + +## 4. Two Pointers + +::tabs-start + +```python +class Solution: + def find132pattern(self, nums: List[int]) -> bool: + n = len(nums) + stkTop, k = n, float('-inf') + + for i in range(n - 1, -1, -1): + if nums[i] < k: + return True + + while stkTop < n and nums[i] > nums[stkTop]: + k = nums[stkTop] + stkTop += 1 + + stkTop -= 1 + nums[stkTop] = nums[i] + + return False +``` + +```java +public class Solution { + public boolean find132pattern(int[] nums) { + int n = nums.length; + int stkTop = n; + int k = Integer.MIN_VALUE; + + for (int i = n - 1; i >= 0; i--) { + if (nums[i] < k) { + return true; + } + + while (stkTop < n && nums[i] > nums[stkTop]) { + k = nums[stkTop++]; + } + + nums[--stkTop] = nums[i]; + } + + return false; + } +} +``` + +```cpp +class Solution { +public: + bool find132pattern(vector& nums) { + int n = nums.size(); + int stkTop = n; + int k = INT_MIN; + + for (int i = n - 1; i >= 0; i--) { + if (nums[i] < k) { + return true; + } + + while (stkTop < n && nums[i] > nums[stkTop]) { + k = nums[stkTop++]; + } + + nums[--stkTop] = nums[i]; + } + + return false; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {boolean} + */ + find132pattern(nums) { + const n = nums.length; + let stkTop = n; + let k = -Infinity; + + for (let i = n - 1; i >= 0; i--) { + if (nums[i] < k) { + return true; + } + + while (stkTop < n && nums[i] > nums[stkTop]) { + k = nums[stkTop++]; + } + + nums[--stkTop] = nums[i]; + } + + return false; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(1)$ extra space. \ No newline at end of file diff --git a/articles/flatten-nested-list-iterator.md b/articles/flatten-nested-list-iterator.md new file mode 100644 index 000000000..ca4acc077 --- /dev/null +++ b/articles/flatten-nested-list-iterator.md @@ -0,0 +1,142 @@ +## 1. Recursion + +::tabs-start + +```python + +``` + +```java + +``` + +```cpp + +``` + +```javascript + +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(2 ^ n)$ +* Space complexity: $O(n)$ + +--- + +## 2. Dynamic Programming (Top-Down) + +::tabs-start + +```python + +``` + +```java + +``` + +```cpp + +``` + +```javascript + +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ + +--- + +## 3. Dynamic Programming (Bottom-Up) + +::tabs-start + +```python + +``` + +```java + +``` + +```cpp + +``` + +```javascript + +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ + +--- + +## 4. Dynamic Programming (Space Optimized) + +::tabs-start + +```python + +``` + +```java + +``` + +```cpp + +``` + +```javascript + +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(1)$ + +--- + +## 5. Dynamic Programming (Optimal) + +::tabs-start + +```python + +``` + +```java + +``` + +```cpp + +``` + +```javascript + +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(1)$ \ No newline at end of file diff --git a/articles/make-the-string-great.md b/articles/make-the-string-great.md index 10b297d5c..f8ee712f7 100644 --- a/articles/make-the-string-great.md +++ b/articles/make-the-string-great.md @@ -43,7 +43,7 @@ public: int i = 0; while (i < n) { if (i > 0 && s[i] != s[i - 1] && tolower(s[i]) == tolower(s[i - 1])) { - s.erase(i - 1, 2); + s = s.substr(0, i - 1) + s.substr(i + 1); n -= 2; i -= 2; } diff --git a/articles/remove-all-adjacent-duplicates-in-string-ii.md b/articles/remove-all-adjacent-duplicates-in-string-ii.md new file mode 100644 index 000000000..7c4ae8a82 --- /dev/null +++ b/articles/remove-all-adjacent-duplicates-in-string-ii.md @@ -0,0 +1,467 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def removeDuplicates(self, s: str, k: int) -> str: + while True: + flag = False + cur = s[0] + cnt = 1 + for i in range(1, len(s)): + if cur != s[i]: + cnt = 0 + cur = s[i] + cnt += 1 + if cnt == k: + s = s[:i - cnt + 1] + s[i + 1:] + flag = True + break + + if not flag: + break + + return s +``` + +```java +public class Solution { + public String removeDuplicates(String s, int k) { + while (true) { + boolean flag = false; + char cur = s.charAt(0); + int cnt = 1; + + for (int i = 1; i < s.length(); i++) { + if (cur != s.charAt(i)) { + cnt = 0; + cur = s.charAt(i); + } + cnt++; + if (cnt == k) { + s = s.substring(0, i - cnt + 1) + s.substring(i + 1); + flag = true; + break; + } + } + + if (!flag) { + break; + } + } + + return s; + } +} +``` + +```cpp +class Solution { +public: + string removeDuplicates(string s, int k) { + while (true) { + bool flag = false; + char cur = s[0]; + int cnt = 1; + + for (int i = 1; i < s.size(); i++) { + if (cur != s[i]) { + cnt = 0; + cur = s[i]; + } + cnt++; + if (cnt == k) { + s = s.substr(0, i - cnt + 1) + s.substr(i + 1); + flag = true; + break; + } + } + + if (!flag) { + break; + } + } + + return s; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s + * @param {number} k + * @return {string} + */ + removeDuplicates(s, k) { + while (true) { + let flag = false; + let cur = s[0]; + let cnt = 1; + + for (let i = 1; i < s.length; i++) { + if (cur !== s[i]) { + cnt = 0; + cur = s[i]; + } + cnt++; + if (cnt === k) { + s = s.slice(0, i - cnt + 1) + s.slice(i + 1); + flag = true; + break; + } + } + + if (!flag) { + break; + } + } + + return s; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(\frac {n ^ 2}{k})$ +* Space complexity: $O(n)$ + +--- + +## 2. Stack + +::tabs-start + +```python +class Solution: + def removeDuplicates(self, s: str, k: int) -> str: + stack = [] + n = len(s) + i = 0 + s = list(s) + + while i < n: + if i == 0 or s[i] != s[i - 1]: + stack.append(1) + else: + stack[-1] += 1 + if stack[-1] == k: + stack.pop() + del s[i - k + 1:i + 1] + i -= k + n -= k + + i += 1 + + return ''.join(s) +``` + +```java +public class Solution { + public String removeDuplicates(String s, int k) { + StringBuilder sb = new StringBuilder(s); + Stack stack = new Stack<>(); + int i = 0; + + while (i < sb.length()) { + if (i == 0 || sb.charAt(i) != sb.charAt(i - 1)) { + stack.push(1); + } else { + stack.push(stack.pop() + 1); + if (stack.peek() == k) { + stack.pop(); + sb.delete(i - k + 1, i + 1); + i -= k; + } + } + i++; + } + + return sb.toString(); + } +} +``` + +```cpp +class Solution { +public: + string removeDuplicates(string s, int k) { + vector stack; + int n = s.length(), i = 0; + + while (i < n) { + if (i == 0 || s[i] != s[i - 1]) { + stack.push_back(1); + } else { + stack.back()++; + if (stack.back() == k) { + stack.pop_back(); + s.erase(i - k + 1, k); + i -= k; + n -= k; + } + } + i++; + } + + return s; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s + * @param {number} k + * @return {string} + */ + removeDuplicates(s, k) { + let stack = []; + let arr = s.split(''); + let i = 0; + + while (i < arr.length) { + if (i === 0 || arr[i] !== arr[i - 1]) { + stack.push(1); + } else { + stack[stack.length - 1]++; + if (stack[stack.length - 1] === k) { + stack.pop(); + arr.splice(i - k + 1, k); + i -= k; + } + } + i++; + } + + return arr.join(''); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ + +--- + +## 3. Stack (Optimal) + +::tabs-start + +```python +class Solution: + def removeDuplicates(self, s: str, k: int) -> str: + stack = [] # [char, count] + + for c in s: + if stack and stack[-1][0] == c: + stack[-1][1] += 1 + else: + stack.append([c, 1]) + if stack[-1][1] == k: + stack.pop() + + return ''.join(char * count for char, count in stack) +``` + +```java +public class Solution { + public String removeDuplicates(String s, int k) { + Stack stack = new Stack<>(); // [char, count] + + for (char c : s.toCharArray()) { + if (!stack.isEmpty() && stack.peek()[0] == c) { + stack.peek()[1]++; + } else { + stack.push(new int[] {c, 1}); + } + if (stack.peek()[1] == k) { + stack.pop(); + } + } + + StringBuilder res = new StringBuilder(); + while (!stack.isEmpty()) { + int[] top = stack.pop(); + res.append(String.valueOf((char) top[0]).repeat(top[1])); + } + + return res.reverse().toString(); + } +} +``` + +```cpp +class Solution { +public: + string removeDuplicates(string s, int k) { + vector> stack; + + for (char c : s) { + if (!stack.empty() && stack.back().first == c) { + stack.back().second++; + } else { + stack.push_back({c, 1}); + } + if (stack.back().second == k) { + stack.pop_back(); + } + } + + string res; + for (auto& p : stack) { + res.append(p.second, p.first); + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s + * @param {number} k + * @return {string} + */ + removeDuplicates(s, k) { + const stack = []; // [char, count] + + for (const c of s) { + if (stack.length && stack[stack.length - 1][0] === c) { + stack[stack.length - 1][1]++; + } else { + stack.push([c, 1]); + } + if (stack[stack.length - 1][1] === k) { + stack.pop(); + } + } + + let res = ""; + for (const [char, count] of stack) { + res += char.repeat(count); + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ + +--- + +## 4. Two Pointers + +::tabs-start + +```python +class Solution: + def removeDuplicates(self, s: str, k: int) -> str: + i = 0 + n = len(s) + count = [0] * n + s = list(s) + for j in range(n): + s[i] = s[j] + count[i] = 1 + if i > 0 and s[i - 1] == s[j]: + count[i] += count[i - 1] + if count[i] == k: + i -= k + i += 1 + return ''.join(s[:i]) +``` + +```java +public class Solution { + public String removeDuplicates(String s, int k) { + int i = 0, n = s.length(); + char[] str = s.toCharArray(); + int[] count = new int[n]; + for (int j = 0; j < n; j++) { + str[i] = str[j]; + count[i] = 1; + if (i > 0 && str[i - 1] == str[j]) { + count[i] += count[i - 1]; + } + if (count[i] == k) { + i -= k; + } + i++; + } + return new String(str, 0, i); + } +} +``` + +```cpp +class Solution { +public: + string removeDuplicates(string s, int k) { + int i = 0, n = s.length(); + vector count(n); + for (int j = 0; j < n; i++, j++) { + s[i] = s[j]; + count[i] = 1; + if (i > 0 && s[i - 1] == s[j]) { + count[i] += count[i - 1]; + } + if (count[i] == k) i -= k; + } + return s.substr(0, i); + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s + * @param {number} k + * @return {string} + */ + removeDuplicates(s, k) { + let i = 0; + const n = s.length; + const count = new Array(n).fill(0); + s = s.split(''); + for (let j = 0; j < n; j++) { + s[i] = s[j]; + count[i] = 1; + if (i > 0 && s[i - 1] === s[j]) { + count[i] += count[i - 1]; + } + if (count[i] === k) { + i -= k; + } + i++; + } + return s.slice(0, i).join(''); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ \ No newline at end of file diff --git a/articles/remove-k-digits.md b/articles/remove-k-digits.md new file mode 100644 index 000000000..19ccf59dc --- /dev/null +++ b/articles/remove-k-digits.md @@ -0,0 +1,344 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def removeKdigits(self, num: str, k: int) -> str: + num = list(num) + while k: + i = 1 + while i < len(num) and num[i] >= num[i - 1]: + i += 1 + num.pop(i - 1) + k -= 1 + + i = 0 + while i < len(num) and num[i] == '0': + i += 1 + + num = num[i:] + return ''.join(num) if num else '0' +``` + +```java +public class Solution { + public String removeKdigits(String num, int k) { + StringBuilder sb = new StringBuilder(num); + while (k > 0) { + int i = 1; + while (i < sb.length() && sb.charAt(i) >= sb.charAt(i - 1)) { + i++; + } + sb.deleteCharAt(i - 1); + k--; + } + + int i = 0; + while (i < sb.length() && sb.charAt(i) == '0') { + i++; + } + + sb = new StringBuilder(sb.substring(i)); + return sb.length() == 0 ? "0" : sb.toString(); + } +} +``` + +```cpp +class Solution { +public: + string removeKdigits(string num, int k) { + while (k > 0) { + int i = 1; + while (i < num.size() && num[i] >= num[i - 1]) { + i++; + } + num.erase(i - 1, 1); + k--; + } + + int i = 0; + while (i < num.size() && num[i] == '0') { + i++; + } + + num = num.substr(i); + return num.empty() ? "0" : num; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} num + * @param {number} k + * @return {string} + */ + removeKdigits(num, k) { + num = num.split(''); + while (k > 0) { + let i = 1; + while (i < num.length && num[i] >= num[i - 1]) { + i++; + } + num.splice(i - 1, 1); + k--; + } + + let i = 0; + while (i < num.length && num[i] === '0') { + i++; + } + + num = num.slice(i); + return num.length === 0 ? "0" : num.join(''); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n * k)$ +* Space complexity: $O(1)$ or $O(n)$ depending on the language. + +--- + +## 2. Greedy + Stack + +::tabs-start + +```python +class Solution: + def removeKdigits(self, num: str, k: int) -> str: + stack = [] + for c in num: + while k > 0 and stack and stack[-1] > c: + k -= 1 + stack.pop() + stack.append(c) + + while stack and k: + stack.pop() + k -= 1 + + i = 0 + while i < len(stack) and stack[i] == '0': + i += 1 + + res = stack[i:] + return ''.join(res) if res else "0" +``` + +```java +public class Solution { + public String removeKdigits(String num, int k) { + StringBuilder stack = new StringBuilder(); + for (char c : num.toCharArray()) { + while (k > 0 && stack.length() > 0 && stack.charAt(stack.length() - 1) > c) { + stack.deleteCharAt(stack.length() - 1); + k--; + } + stack.append(c); + } + + while (k > 0 && stack.length() > 0) { + stack.deleteCharAt(stack.length() - 1); + k--; + } + + int i = 0; + while (i < stack.length() && stack.charAt(i) == '0') { + i++; + } + + String res = stack.substring(i); + return res.isEmpty() ? "0" : res; + } +} +``` + +```cpp +class Solution { +public: + string removeKdigits(string num, int k) { + string stack; + for (char c : num) { + while (k > 0 && !stack.empty() && stack.back() > c) { + stack.pop_back(); + k--; + } + stack.push_back(c); + } + + while (k > 0 && !stack.empty()) { + stack.pop_back(); + k--; + } + + int i = 0; + while (i < stack.size() && stack[i] == '0') { + i++; + } + + string res = stack.substr(i); + return res.empty() ? "0" : res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} num + * @param {number} k + * @return {string} + */ + removeKdigits(num, k) { + let stack = []; + for (let c of num) { + while (k > 0 && stack.length > 0 && stack[stack.length - 1] > c) { + stack.pop(); + k--; + } + stack.push(c); + } + + while (k > 0 && stack.length > 0) { + stack.pop(); + k--; + } + + let i = 0; + while (i < stack.length && stack[i] === '0') { + i++; + } + + let res = stack.slice(i).join(''); + return res === '' ? "0" : res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ + +--- + +## 3. Two Pointers + +::tabs-start + +```python +class Solution: + def removeKdigits(self, num: str, k: int) -> str: + l = 0 + num = list(num) + + for r in range(len(num)): + while l > 0 and k > 0 and num[l - 1] > num[r]: + l -= 1 + k -= 1 + num[l] = num[r] + l += 1 + + l -= k + i = 0 + while i < l and num[i] == '0': + i += 1 + res = ''.join(num[i:l]) + return res if res else '0' +``` + +```java +public class Solution { + public String removeKdigits(String num, int k) { + char[] numArray = num.toCharArray(); + int l = 0; + + for (int r = 0; r < numArray.length; r++) { + while (l > 0 && k > 0 && numArray[l - 1] > numArray[r]) { + l--; + k--; + } + numArray[l++] = numArray[r]; + } + + l -= k; + int i = 0; + while (i < l && numArray[i] == '0') { + i++; + } + String res = new String(numArray, i, l - i); + return res.isEmpty() ? "0" : res; + } +} +``` + +```cpp +class Solution { +public: + string removeKdigits(string num, int k) { + int l = 0; + for (int r = 0; r < num.size(); r++) { + while (l > 0 && k > 0 && num[l - 1] > num[r]) { + l--; + k--; + } + num[l++] = num[r]; + } + + l -= k; + int i = 0; + while (i < l && num[i] == '0') { + i++; + } + if (i == l) return "0"; + return num.substr(i, l - i); + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} num + * @param {number} k + * @return {string} + */ + removeKdigits(num, k) { + let numArray = num.split(''); + let l = 0; + + for (let r = 0; r < numArray.length; r++) { + while (l > 0 && k > 0 && numArray[l - 1] > numArray[r]) { + l--; + k--; + } + numArray[l++] = numArray[r]; + } + + l -= k; + let i = 0; + while (i < l && numArray[i] === '0') { + i++; + } + let res = numArray.slice(i, l).join(''); + return res.length === 0 ? "0" : res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(1)$ or $O(n)$ depending on the language. \ No newline at end of file diff --git a/articles/removing-stars-from-a-string.md b/articles/removing-stars-from-a-string.md new file mode 100644 index 000000000..108454bae --- /dev/null +++ b/articles/removing-stars-from-a-string.md @@ -0,0 +1,357 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def removeStars(self, s: str) -> str: + while True: + flag = False + for i in range(1, len(s)): + if s[i] == '*' and s[i - 1] != '*': + s = s[:i - 1] + s[i + 1:] + flag = True + break + if not flag: + break + return s +``` + +```java +public class Solution { + public String removeStars(String s) { + while (true) { + boolean flag = false; + StringBuilder sb = new StringBuilder(s); + for (int i = 1; i < sb.length(); i++) { + if (sb.charAt(i) == '*' && sb.charAt(i - 1) != '*') { + sb.delete(i - 1, i + 1); + flag = true; + break; + } + } + s = sb.toString(); + if (!flag) { + break; + } + } + return s; + } +} +``` + +```cpp +class Solution { +public: + string removeStars(string s) { + while (true) { + bool flag = false; + for (int i = 1; i < s.size(); ++i) { + if (s[i] == '*' && s[i - 1] != '*') { + s = s.substr(0, i - 1) + s.substr(i + 1); + flag = true; + break; + } + } + if (!flag) { + break; + } + } + return s; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s + * @return {string} + */ + removeStars(s) { + while (true) { + let flag = false; + for (let i = 1; i < s.length; i++) { + if (s[i] === '*' && s[i - 1] !== '*') { + s = s.slice(0, i - 1) + s.slice(i + 1); + flag = true; + break; + } + } + if (!flag) { + break; + } + } + return s; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 2)$ +* Space complexity: $O(n)$ + +--- + +## 2. Brute Force (Optimized) + +::tabs-start + +```python +class Solution: + def removeStars(self, s: str) -> str: + n = len(s) + i = 0 + while i < n: + if i and s[i] == '*' and s[i - 1] != '*': + s = s[:i - 1] + s[i + 1:] + n -= 2 + i -= 2 + i += 1 + return s +``` + +```java +public class Solution { + public String removeStars(String s) { + int n = s.length(); + int i = 0; + while (i < n) { + if (i > 0 && s.charAt(i) == '*' && s.charAt(i - 1) != '*') { + s = s.substring(0, i - 1) + s.substring(i + 1); + n -= 2; + i -= 2; + } + i++; + } + return s; + } +} +``` + +```cpp +class Solution { +public: + string removeStars(string s) { + int n = s.length(); + int i = 0; + while (i < n) { + if (i > 0 && s[i] == '*' && s[i - 1] != '*') { + s = s.substr(0, i - 1) + s.substr(i + 1); + n -= 2; + i -= 2; + } + i++; + } + return s; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s + * @return {string} + */ + removeStars(s) { + let n = s.length; + let i = 0; + while (i < n) { + if (i > 0 && s[i] === '*' && s[i - 1] !== '*') { + s = s.slice(0, i - 1) + s.slice(i + 1); + n -= 2; + i -= 2; + } + i++; + } + return s; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 2)$ +* Space complexity: $O(n)$ + +--- + +## 3. Stack + +::tabs-start + +```python +class Solution: + def removeStars(self, s: str) -> str: + stack = [] + for c in s: + if c == "*": + stack and stack.pop() + else: + stack.append(c) + return "".join(stack) +``` + +```java +public class Solution { + public String removeStars(String s) { + Stack stack = new Stack<>(); + for (char c : s.toCharArray()) { + if (c == '*') { + if (!stack.isEmpty()) stack.pop(); + } else { + stack.push(c); + } + } + StringBuilder res = new StringBuilder(); + for (char c : stack) res.append(c); + return res.toString(); + } +} +``` + +```cpp +class Solution { +public: + string removeStars(string s) { + stack stack; + for (char c : s) { + if (c == '*') { + if (!stack.empty()) stack.pop(); + } else { + stack.push(c); + } + } + string res; + while (!stack.empty()) { + res += stack.top(); + stack.pop(); + } + reverse(res.begin(), res.end()); + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s + * @return {string} + */ + removeStars(s) { + const stack = []; + for (const c of s) { + if (c === "*") { + if (stack.length > 0) stack.pop(); + } else { + stack.push(c); + } + } + return stack.join(""); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ + +--- + +## 4. Two Pointers + +::tabs-start + +```python +class Solution: + def removeStars(self, s: str) -> str: + l = 0 + s = list(s) + + for r in range(len(s)): + if s[r] == '*': + l -= 1 + else: + s[l] = s[r] + l += 1 + + return ''.join(s[:l]) +``` + +```java +public class Solution { + public String removeStars(String s) { + char[] arr = s.toCharArray(); + int l = 0; + + for (int r = 0; r < arr.length; r++) { + if (arr[r] == '*') { + l--; + } else { + arr[l] = arr[r]; + l++; + } + } + return new String(arr, 0, l); + } +} +``` + +```cpp +class Solution { +public: + string removeStars(string s) { + int l = 0; + + for (int r = 0; r < s.size(); r++) { + if (s[r] == '*') { + l--; + } else { + s[l] = s[r]; + l++; + } + } + return s.substr(0, l); + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s + * @return {string} + */ + removeStars(s) { + const arr = s.split(''); + let l = 0; + + for (let r = 0; r < arr.length; r++) { + if (arr[r] === '*') { + l--; + } else { + arr[l] = arr[r]; + l++; + } + } + return arr.slice(0, l).join(''); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(1)$ or $O(n)$ depending on the language. \ No newline at end of file diff --git a/articles/validate-stack-sequences.md b/articles/validate-stack-sequences.md new file mode 100644 index 000000000..00867b541 --- /dev/null +++ b/articles/validate-stack-sequences.md @@ -0,0 +1,160 @@ +## 1. Stack + +::tabs-start + +```python +class Solution: + def validateStackSequences(self, pushed: List[int], popped: List[int]) -> bool: + i = 0 + stack = [] + for n in pushed: + stack.append(n) + while i < len(popped) and stack and popped[i] == stack[-1]: + stack.pop() + i += 1 + return not stack +``` + +```java +public class Solution { + public boolean validateStackSequences(int[] pushed, int[] popped) { + Stack stack = new Stack<>(); + int i = 0; + for (int n : pushed) { + stack.push(n); + while (i < popped.length && !stack.isEmpty() && popped[i] == stack.peek()) { + stack.pop(); + i++; + } + } + return stack.isEmpty(); + } +} +``` + +```cpp +class Solution { +public: + bool validateStackSequences(vector& pushed, vector& popped) { + stack stk; + int i = 0; + for (int n : pushed) { + stk.push(n); + while (i < popped.size() && !stk.empty() && popped[i] == stk.top()) { + stk.pop(); + i++; + } + } + return stk.empty(); + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} pushed + * @param {number[]} popped + * @return {boolean} + */ + validateStackSequences(pushed, popped) { + const stack = []; + let i = 0; + for (const n of pushed) { + stack.push(n); + while (i < popped.length && stack.length > 0 && popped[i] === stack[stack.length - 1]) { + stack.pop(); + i++; + } + } + return stack.length === 0; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ + +--- + +## 2. Two Pointers + +::tabs-start + +```python +class Solution: + def validateStackSequences(self, pushed: List[int], popped: List[int]) -> bool: + l = r = 0 + for num in pushed: + pushed[l] = num + l += 1 + while l > 0 and pushed[l - 1] == popped[r]: + r += 1 + l -= 1 + return l == 0 +``` + +```java +public class Solution { + public boolean validateStackSequences(int[] pushed, int[] popped) { + int l = 0, r = 0; + for (int num : pushed) { + pushed[l++] = num; + while (l > 0 && pushed[l - 1] == popped[r]) { + r++; + l--; + } + } + return l == 0; + } +} +``` + +```cpp +class Solution { +public: + bool validateStackSequences(vector& pushed, vector& popped) { + int l = 0, r = 0; + for (int& num : pushed) { + pushed[l++] = num; + while (l > 0 && pushed[l - 1] == popped[r]) { + r++; + l--; + } + } + return l == 0; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} pushed + * @param {number[]} popped + * @return {boolean} + */ + validateStackSequences(pushed, popped) { + let l = 0, r = 0; + for (const num of pushed) { + pushed[l++] = num; + while (l > 0 && pushed[l - 1] === popped[r]) { + r++; + l--; + } + } + return l === 0; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(1)$ extra space. \ No newline at end of file From a7fed08cb6cc57a618b4b3e3e36b21a5440687c1 Mon Sep 17 00:00:00 2001 From: Sri Hari Date: Tue, 28 Jan 2025 19:33:44 +0530 Subject: [PATCH 2/7] Batch-5/Neetcode-ALL/Added-articles --- articles/find-peak-element.md | 341 ++++++++++ articles/flatten-nested-list-iterator.md | 549 ++++++++++++++-- articles/single-element-in-a-sorted-array.md | 438 +++++++++++++ .../successful-pairs-of-spells-and-potions.md | 461 ++++++++++++++ articles/sum-of-subarray-minimums.md | 596 ++++++++++++++++++ articles/valid-perfect-square.md | 447 +++++++++++++ 6 files changed, 2776 insertions(+), 56 deletions(-) create mode 100644 articles/find-peak-element.md create mode 100644 articles/single-element-in-a-sorted-array.md create mode 100644 articles/successful-pairs-of-spells-and-potions.md create mode 100644 articles/sum-of-subarray-minimums.md create mode 100644 articles/valid-perfect-square.md diff --git a/articles/find-peak-element.md b/articles/find-peak-element.md new file mode 100644 index 000000000..9d341f185 --- /dev/null +++ b/articles/find-peak-element.md @@ -0,0 +1,341 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def findPeakElement(self, nums: List[int]) -> int: + for i in range(len(nums) - 1): + if nums[i] > nums[i + 1]: + return i + + return len(nums) - 1 +``` + +```java +public class Solution { + public int findPeakElement(int[] nums) { + for (int i = 0; i < nums.length - 1; i++) { + if (nums[i] > nums[i + 1]) { + return i; + } + } + return nums.length - 1; + } +} +``` + +```cpp +class Solution { +public: + int findPeakElement(vector& nums) { + for (int i = 0; i < nums.size() - 1; i++) { + if (nums[i] > nums[i + 1]) { + return i; + } + } + return nums.size() - 1; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number} + */ + findPeakElement(nums) { + for (let i = 0; i < nums.length - 1; i++) { + if (nums[i] > nums[i + 1]) { + return i; + } + } + return nums.length - 1; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(1)$ + +--- + +## 2. Binary Search + +::tabs-start + +```python +class Solution: + def findPeakElement(self, nums: List[int]) -> int: + l, r = 0, len(nums) - 1 + + while l <= r: + m = l + (r - l) // 2 + if m > 0 and nums[m] < nums[m - 1]: + r = m - 1 + elif m < len(nums) - 1 and nums[m] < nums[m + 1]: + l = m + 1 + else: + return m +``` + +```java +public class Solution { + public int findPeakElement(int[] nums) { + int l = 0, r = nums.length - 1; + + while (l <= r) { + int m = l + (r - l) / 2; + if (m > 0 && nums[m] < nums[m - 1]) { + r = m - 1; + } else if (m < nums.length - 1 && nums[m] < nums[m + 1]) { + l = m + 1; + } else { + return m; + } + } + + return -1; + } +} +``` + +```cpp +class Solution { +public: + int findPeakElement(vector& nums) { + int l = 0, r = nums.size() - 1; + + while (l <= r) { + int m = l + (r - l) / 2; + if (m > 0 && nums[m] < nums[m - 1]) { + r = m - 1; + } else if (m < nums.size() - 1 && nums[m] < nums[m + 1]) { + l = m + 1; + } else { + return m; + } + } + + return -1; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number} + */ + findPeakElement(nums) { + let l = 0, r = nums.length - 1; + + while (l <= r) { + let m = Math.floor(l + (r - l) / 2); + if (m > 0 && nums[m] < nums[m - 1]) { + r = m - 1; + } else if (m < nums.length - 1 && nums[m] < nums[m + 1]) { + l = m + 1; + } else { + return m; + } + } + + return -1; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(\log n)$ +* Space complexity: $O(1)$ + +--- + +## 3. Recursive Binary Search + +::tabs-start + +```python +class Solution: + def findPeakElement(self, nums: List[int]) -> int: + def binary_search(l, r): + if l == r: + return l + m = l + (r - l) // 2 + if nums[m] > nums[m + 1]: + return binary_search(l, m) + return binary_search(m + 1, r) + + return binary_search(0, len(nums) - 1) +``` + +```java +public class Solution { + public int findPeakElement(int[] nums) { + return binarySearch(nums, 0, nums.length - 1); + } + + private int binarySearch(int[] nums, int l, int r) { + if (l == r) { + return l; + } + int m = l + (r - l) / 2; + if (nums[m] > nums[m + 1]) { + return binarySearch(nums, l, m); + } + return binarySearch(nums, m + 1, r); + } +} +``` + +```cpp +class Solution { +public: + int findPeakElement(vector& nums) { + return binarySearch(nums, 0, nums.size() - 1); + } + +private: + int binarySearch(vector& nums, int l, int r) { + if (l == r) { + return l; + } + int m = l + (r - l) / 2; + if (nums[m] > nums[m + 1]) { + return binarySearch(nums, l, m); + } + return binarySearch(nums, m + 1, r); + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number} + */ + findPeakElement(nums) { + const binarySearch = (l, r) => { + if (l === r) { + return l; + } + let m = Math.floor((l + r) / 2); + if (nums[m] > nums[m + 1]) { + return binarySearch(l, m); + } else { + return binarySearch(m + 1, r); + } + }; + + return binarySearch(0, nums.length - 1); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(\log n)$ +* Space complexity: $O(\log n)$ for recursion stack. + +--- + +## 4. Binary Search (Optimal) + +::tabs-start + +```python +class Solution: + def findPeakElement(self, nums: List[int]) -> int: + l, r = 0, len(nums) - 1 + + while l < r: + m = (l + r) >> 1 + if nums[m] > nums[m + 1]: + r = m + else: + l = m + 1 + + return l +``` + +```java +public class Solution { + public int findPeakElement(int[] nums) { + int l = 0, r = nums.length - 1; + + while (l < r) { + int m = (l + r) >> 1; + if (nums[m] > nums[m + 1]) { + r = m; + } else { + l = m + 1; + } + } + + return l; + } +} +``` + +```cpp +class Solution { +public: + int findPeakElement(vector& nums) { + int l = 0, r = nums.size() - 1; + + while (l < r) { + int m = (l + r) >> 1; + if (nums[m] > nums[m + 1]) { + r = m; + } else { + l = m + 1; + } + } + + return l; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number} + */ + findPeakElement(nums) { + let l = 0, r = nums.length - 1; + + while (l < r) { + let m = (l + r) >> 1; + if (nums[m] > nums[m + 1]) { + r = m; + } else { + l = m + 1; + } + } + + return l; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(\log n)$ +* Space complexity: $O(1)$ \ No newline at end of file diff --git a/articles/flatten-nested-list-iterator.md b/articles/flatten-nested-list-iterator.md index ca4acc077..6ac2342a2 100644 --- a/articles/flatten-nested-list-iterator.md +++ b/articles/flatten-nested-list-iterator.md @@ -1,142 +1,579 @@ -## 1. Recursion +## 1. Recursion (Flatten And Store Into Global List ) ::tabs-start ```python - +class NestedIterator: + def __init__(self, nestedList): + self.arr = [] + self.ptr = 0 + self.dfs(nestedList) + + def next(self): + val = self.arr[self.ptr] + self.ptr += 1 + return val + + def hasNext(self): + return self.ptr < len(self.arr) + + def dfs(self, nestedArr): + for num in nestedArr: + if num.isInteger(): + self.arr.append(num.getInteger()) + else: + self.dfs(num.getList()) ``` ```java - +public class NestedIterator implements Iterator { + + private List arr; + private int ptr; + + public NestedIterator(List nestedList) { + arr = new ArrayList<>(); + ptr = 0; + dfs(nestedList); + } + + @Override + public Integer next() { + return arr.get(ptr++); + } + + @Override + public boolean hasNext() { + return ptr < arr.size(); + } + + private void dfs(List nestedArr) { + for (NestedInteger num : nestedArr) { + if (num.isInteger()) { + arr.add(num.getInteger()); + } else { + dfs(num.getList()); + } + } + } +} ``` ```cpp - +class NestedIterator { +private: + vector arr; + int ptr; + + void dfs(const vector &nestedArr) { + for (const auto &num : nestedArr) { + if (num.isInteger()) { + arr.push_back(num.getInteger()); + } else { + dfs(num.getList()); + } + } + } + +public: + NestedIterator(vector &nestedList) { + ptr = 0; + dfs(nestedList); + } + + int next() { + return arr[ptr++]; + } + + bool hasNext() { + return ptr < arr.size(); + } +}; ``` ```javascript - +class NestedIterator { + /** + * @constructor + * @param {NestedInteger[]} nestedList + */ + constructor(nestedList) { + this.arr = []; + this.ptr = 0; + this.dfs(nestedList); + } + + /** + * @param {NestedInteger[]} nestedArr + */ + dfs(nestedArr) { + for (let num of nestedArr) { + if (num.isInteger()) { + this.arr.push(num.getInteger()); + } else { + this.dfs(num.getList()); + } + } + } + + /** + * @this NestedIterator + * @returns {integer} + */ + next() { + return this.arr[this.ptr++]; + } + + /** + * @this NestedIterator + * @returns {boolean} + */ + hasNext() { + return this.ptr < this.arr.length; + } +} ``` ::tabs-end ### Time & Space Complexity -* Time complexity: $O(2 ^ n)$ -* Space complexity: $O(n)$ - ---- - -## 2. Dynamic Programming (Top-Down) - -::tabs-start - -```python - -``` - -```java - -``` - -```cpp - -``` - -```javascript - -``` - -::tabs-end - -### Time & Space Complexity +* Time complexity: $O(n + d)$ +* Space complexity: $O(n + d)$ -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +> Where $n$ is the number of integers and $d$ is the nesting depth. --- -## 3. Dynamic Programming (Bottom-Up) +## 2. Recursion (Flatten And Return) ::tabs-start ```python - +class NestedIterator: + def __init__(self, nestedList): + self.arr = self.dfs(nestedList) + self.ptr = 0 + + def dfs(self, nestedArr): + res = [] + for num in nestedArr: + if num.isInteger(): + res.append(num.getInteger()) + else: + res.extend(self.dfs(num.getList())) + return res + + def next(self): + val = self.arr[self.ptr] + self.ptr += 1 + return val + + def hasNext(self): + return self.ptr < len(self.arr) ``` ```java - +public class NestedIterator implements Iterator { + private List arr; + private int ptr; + + public NestedIterator(List nestedList) { + arr = dfs(nestedList); + ptr = 0; + } + + private List dfs(List nestedArr) { + List res = new ArrayList<>(); + for (NestedInteger num : nestedArr) { + if (num.isInteger()) { + res.add(num.getInteger()); + } else { + res.addAll(dfs(num.getList())); + } + } + return res; + } + + @Override + public Integer next() { + return arr.get(ptr++); + } + + @Override + public boolean hasNext() { + return ptr < arr.size(); + } +} ``` ```cpp - +class NestedIterator { +private: + vector arr; + int ptr; + + vector dfs(const vector &nestedArr) { + vector res; + for (const auto &num : nestedArr) { + if (num.isInteger()) { + res.push_back(num.getInteger()); + } else { + vector temp = dfs(num.getList()); + res.insert(res.end(), temp.begin(), temp.end()); + } + } + return res; + } + +public: + NestedIterator(vector &nestedList) { + arr = dfs(nestedList); + ptr = 0; + } + + int next() { + return arr[ptr++]; + } + + bool hasNext() { + return ptr < arr.size(); + } +}; ``` ```javascript - +class NestedIterator { + /** + * @constructor + * @param {NestedInteger[]} nestedList + */ + constructor(nestedList) { + this.arr = this.dfs(nestedList); + this.ptr = 0; + } + + /** + * @param {NestedInteger[]} nestedArr + */ + dfs(nestedArr) { + let res = []; + for (let num of nestedArr) { + if (num.isInteger()) { + res.push(num.getInteger()); + } else { + res.push(...this.dfs(num.getList())); + } + } + return res; + } + + /** + * @this NestedIterator + * @returns {integer} + */ + next() { + return this.arr[this.ptr++]; + } + + /** + * @this NestedIterator + * @returns {boolean} + */ + hasNext() { + return this.ptr < this.arr.length; + } +} ``` ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +* Time complexity: $O(n + d)$ +* Space complexity: $O(n + d)$ + +> Where $n$ is the number of integers and $d$ is the nesting depth. --- -## 4. Dynamic Programming (Space Optimized) +## 3. Recursion + Stack ::tabs-start ```python - +class NestedIterator: + def __init__(self, nestedList: [NestedInteger]): + self.stack = [] + self.dfs(nestedList) + self.stack.reverse() + + def next(self) -> int: + return self.stack.pop() + + def hasNext(self) -> bool: + return len(self.stack) > 0 + + def dfs(self, nested): + for num in nested: + if num.isInteger(): + self.stack.append(num.getInteger()) + else: + self.dfs(num.getList()) ``` ```java - +public class NestedIterator implements Iterator { + private Stack stack; + + public NestedIterator(List nestedList) { + stack = new Stack<>(); + dfs(nestedList); + Collections.reverse(stack); + } + + private void dfs(List nested) { + for (NestedInteger num : nested) { + if (num.isInteger()) { + stack.push(num.getInteger()); + } else { + dfs(num.getList()); + } + } + } + + @Override + public Integer next() { + return stack.pop(); + } + + @Override + public boolean hasNext() { + return !stack.isEmpty(); + } +} ``` ```cpp - +class NestedIterator { +private: + vector stack; + + void dfs(const vector &nested) { + for (const auto &num : nested) { + if (num.isInteger()) { + stack.push_back(num.getInteger()); + } else { + dfs(num.getList()); + } + } + } + +public: + NestedIterator(vector &nestedList) { + dfs(nestedList); + reverse(stack.begin(), stack.end()); + } + + int next() { + int val = stack.back(); + stack.pop_back(); + return val; + } + + bool hasNext() { + return !stack.empty(); + } +}; ``` ```javascript - +class NestedIterator { + /** + * @constructor + * @param {NestedInteger[]} nestedList + */ + constructor(nestedList) { + this.stack = []; + this.dfs(nestedList); + this.stack.reverse(); + } + + /** + * @param {NestedInteger[]} nested + */ + dfs(nested) { + for (let num of nested) { + if (num.isInteger()) { + this.stack.push(num.getInteger()); + } else { + this.dfs(num.getList()); + } + } + } + + /** + * @this NestedIterator + * @returns {number} + */ + next() { + return this.stack.pop(); + } + + /** + * @this NestedIterator + * @returns {boolean} + */ + hasNext() { + return this.stack.length > 0; + } +} ``` ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ +* Time complexity: $O(n + d)$ +* Space complexity: $O(n + d)$ + +> Where $n$ is the number of integers and $d$ is the nesting depth. --- -## 5. Dynamic Programming (Optimal) +## 4. Stack ::tabs-start ```python - +class NestedIterator: + def __init__(self, nestedList: [NestedInteger]): + self.stack = nestedList + self.stack.reverse() + + def next(self) -> int: + return self.stack.pop().getInteger() + + def hasNext(self) -> bool: + while self.stack: + top = self.stack[-1] + if top.isInteger(): + return True + + self.stack.pop() + self.stack.extend(reversed(top.getList())) + return False ``` ```java - +public class NestedIterator implements Iterator { + private List stack; + + public NestedIterator(List nestedList) { + stack = new ArrayList<>(nestedList); + Collections.reverse(stack); + } + + @Override + public Integer next() { + return stack.remove(stack.size() - 1).getInteger(); + } + + @Override + public boolean hasNext() { + while (!stack.isEmpty()) { + NestedInteger top = stack.get(stack.size() - 1); + if (top.isInteger()) { + return true; + } + stack.remove(stack.size() - 1); + List nestedList = top.getList(); + Collections.reverse(nestedList); + stack.addAll(nestedList); + } + return false; + } +} ``` ```cpp - +class NestedIterator { +private: + vector stack; + +public: + NestedIterator(vector &nestedList) { + stack = nestedList; + reverse(stack.begin(), stack.end()); + } + + int next() { + int val = stack.back().getInteger(); + stack.pop_back(); + return val; + } + + bool hasNext() { + while (!stack.empty()) { + NestedInteger top = stack.back(); + if (top.isInteger()) { + return true; + } + stack.pop_back(); + vector nestedList = top.getList(); + for (auto it = nestedList.rbegin(); it != nestedList.rend(); ++it) { + stack.push_back(*it); + } + } + return false; + } +}; ``` ```javascript - +class NestedIterator { + /** + * @constructor + * @param {NestedInteger[]} nestedList + */ + constructor(nestedList) { + this.stack = nestedList; + this.stack.reverse(); + } + + /** + * @this NestedIterator + * @returns {number} + */ + next() { + return this.stack.pop().getInteger(); + } + + /** + * @this NestedIterator + * @returns {boolean} + */ + hasNext() { + while (this.stack.length > 0) { + const top = this.stack[this.stack.length - 1]; + if (top.isInteger()) { + return true; + } + this.stack.pop(); + const nestedList = top.getList(); + nestedList.reverse(); + this.stack.push(...nestedList); + } + return false; + } +} ``` ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ \ No newline at end of file +* Time complexity: $O(n + d)$ +* Space complexity: $O(n)$ + +> Where $n$ is the number of integers and $d$ is the nesting depth. \ No newline at end of file diff --git a/articles/single-element-in-a-sorted-array.md b/articles/single-element-in-a-sorted-array.md new file mode 100644 index 000000000..e2a5a8b0e --- /dev/null +++ b/articles/single-element-in-a-sorted-array.md @@ -0,0 +1,438 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def singleNonDuplicate(self, nums: List[int]) -> int: + n = len(nums) + for i in range(n): + if ((i and nums[i] == nums[i - 1]) or + (i < n - 1 and nums[i] == nums[i + 1]) + ): + continue + return nums[i] +``` + +```java +public class Solution { + public int singleNonDuplicate(int[] nums) { + int n = nums.length; + for (int i = 0; i < n; i++) { + if ((i > 0 && nums[i] == nums[i - 1]) || + (i < n - 1 && nums[i] == nums[i + 1])) { + continue; + } + return nums[i]; + } + return -1; + } +} +``` + +```cpp +class Solution { +public: + int singleNonDuplicate(vector& nums) { + int n = nums.size(); + for (int i = 0; i < n; i++) { + if ((i > 0 && nums[i] == nums[i - 1]) || + (i < n - 1 && nums[i] == nums[i + 1])) { + continue; + } + return nums[i]; + } + return -1; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number} + */ + singleNonDuplicate(nums) { + const n = nums.length; + for (let i = 0; i < n; i++) { + if ((i > 0 && nums[i] === nums[i - 1]) || + (i < n - 1 && nums[i] === nums[i + 1])) { + continue; + } + return nums[i]; + } + return -1; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(1)$ + +--- + +## 2. Brute Force (Bitwise Xor) + +::tabs-start + +```python +class Solution: + def singleNonDuplicate(self, nums: List[int]) -> int: + xorr = 0 + for num in nums: + xorr ^= num + return xorr +``` + +```java +public class Solution { + public int singleNonDuplicate(int[] nums) { + int xorr = 0; + for (int num : nums) { + xorr ^= num; + } + return xorr; + } +} +``` + +```cpp +class Solution { +public: + int singleNonDuplicate(vector& nums) { + int xorr = 0; + for (int num : nums) { + xorr ^= num; + } + return xorr; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number} + */ + singleNonDuplicate(nums) { + let xorr = 0; + for (const num of nums) { + xorr ^= num; + } + return xorr; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(1)$ + +--- + +## 3. Binary Search + +::tabs-start + +```python +class Solution: + def singleNonDuplicate(self, nums: List[int]) -> int: + l, r = 0, len(nums) - 1 + + while l <= r: + m = l + ((r - l) // 2) + if ((m - 1 < 0 or nums[m - 1] != nums[m]) and + (m + 1 == len(nums) or nums[m] != nums[m + 1])): + return nums[m] + + leftSize = m - 1 if nums[m - 1] == nums[m] else m + if leftSize % 2: + r = m - 1 + else: + l = m + 1 +``` + +```java +public class Solution { + public int singleNonDuplicate(int[] nums) { + int l = 0, r = nums.length - 1; + + while (l <= r) { + int m = l + (r - l) / 2; + if ((m - 1 < 0 || nums[m - 1] != nums[m]) && + (m + 1 == nums.length || nums[m] != nums[m + 1])) { + return nums[m]; + } + + int leftSize = (m - 1 >= 0 && nums[m - 1] == nums[m]) ? m - 1 : m; + if (leftSize % 2 == 1) { + r = m - 1; + } else { + l = m + 1; + } + } + + return -1; + } +} +``` + +```cpp +class Solution { +public: + int singleNonDuplicate(vector& nums) { + int l = 0, r = nums.size() - 1; + + while (l <= r) { + int m = l + (r - l) / 2; + if ((m - 1 < 0 || nums[m - 1] != nums[m]) && + (m + 1 == nums.size() || nums[m] != nums[m + 1])) { + return nums[m]; + } + + int leftSize = (m - 1 >= 0 && nums[m - 1] == nums[m]) ? m - 1 : m; + if (leftSize % 2 == 1) { + r = m - 1; + } else { + l = m + 1; + } + } + + return -1; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number} + */ + singleNonDuplicate(nums) { + let l = 0, r = nums.length - 1; + + while (l <= r) { + let m = l + Math.floor((r - l) / 2); + if ((m - 1 < 0 || nums[m - 1] !== nums[m]) && + (m + 1 === nums.length || nums[m] !== nums[m + 1])) { + return nums[m]; + } + + let leftSize = (m - 1 >= 0 && nums[m - 1] === nums[m]) ? m - 1 : m; + if (leftSize % 2 === 1) { + r = m - 1; + } else { + l = m + 1; + } + } + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(\log n)$ +* Space complexity: $O(1)$ + +--- + +## 4. Binary Search On Even Indexes + +::tabs-start + +```python +class Solution: + def singleNonDuplicate(self, nums: List[int]) -> int: + l, r = 0, len(nums) - 1 + + while l < r: + m = l + (r - l) // 2 + if m & 1: + m -= 1 + if nums[m] != nums[m + 1]: + r = m + else: + l = m + 2 + + return nums[l] +``` + +```java +public class Solution { + public int singleNonDuplicate(int[] nums) { + int l = 0, r = nums.length - 1; + + while (l < r) { + int m = l + (r - l) / 2; + if ((m & 1) == 1) { + m--; + } + if (nums[m] != nums[m + 1]) { + r = m; + } else { + l = m + 2; + } + } + + return nums[l]; + } +} +``` + +```cpp +class Solution { +public: + int singleNonDuplicate(vector& nums) { + int l = 0, r = nums.size() - 1; + + while (l < r) { + int m = l + (r - l) / 2; + if (m & 1) { + m--; + } + if (nums[m] != nums[m + 1]) { + r = m; + } else { + l = m + 2; + } + } + + return nums[l]; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number} + */ + singleNonDuplicate(nums) { + let l = 0, r = nums.length - 1; + + while (l < r) { + let m = Math.floor(l + (r - l) / 2); + if (m & 1) { + m--; + } + if (nums[m] !== nums[m + 1]) { + r = m; + } else { + l = m + 2; + } + } + + return nums[l]; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(\log n)$ +* Space complexity: $O(1)$ + +--- + +## 5. Binary Search + Bit Manipulation + +::tabs-start + +```python +class Solution: + def singleNonDuplicate(self, nums: List[int]) -> int: + l, r = 0, len(nums) - 1 + + while l < r: + m = (l + r) >> 1 + if nums[m] != nums[m ^ 1]: + r = m + else: + l = m + 1 + + return nums[l] +``` + +```java +public class Solution { + public int singleNonDuplicate(int[] nums) { + int l = 0, r = nums.length - 1; + + while (l < r) { + int m = (l + r) >> 1; + if (nums[m] != nums[m ^ 1]) { + r = m; + } else { + l = m + 1; + } + } + + return nums[l]; + } +} +``` + +```cpp +class Solution { +public: + int singleNonDuplicate(vector& nums) { + int l = 0, r = nums.size() - 1; + + while (l < r) { + int m = (l + r) >> 1; + if (nums[m] != nums[m ^ 1]) { + r = m; + } else { + l = m + 1; + } + } + + return nums[l]; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number} + */ + singleNonDuplicate(nums) { + let l = 0, r = nums.length - 1; + + while (l < r) { + let m = (l + r) >> 1; + if (nums[m] !== nums[m ^ 1]) { + r = m; + } else { + l = m + 1; + } + } + + return nums[l]; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(\log n)$ +* Space complexity: $O(1)$ \ No newline at end of file diff --git a/articles/successful-pairs-of-spells-and-potions.md b/articles/successful-pairs-of-spells-and-potions.md new file mode 100644 index 000000000..87faf3177 --- /dev/null +++ b/articles/successful-pairs-of-spells-and-potions.md @@ -0,0 +1,461 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def successfulPairs(self, spells: List[int], potions: List[int], success: int) -> List[int]: + res = [] + + for s in spells: + cnt = 0 + for p in potions: + if s * p >= success: + cnt += 1 + res.append(cnt) + + return res +``` + +```java +public class Solution { + public int[] successfulPairs(int[] spells, int[] potions, long success) { + int[] res = new int[spells.length]; + + for (int i = 0; i < spells.length; i++) { + int cnt = 0; + for (int p : potions) { + if ((long) spells[i] * p >= success) { + cnt++; + } + } + res[i] = cnt; + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + vector successfulPairs(vector& spells, vector& potions, long long success) { + vector res(spells.size()); + + for (int i = 0; i < spells.size(); i++) { + int cnt = 0; + for (int p : potions) { + if ((long long) spells[i] * p >= success) { + cnt++; + } + } + res[i] = cnt; + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} spells + * @param {number[]} potions + * @param {number} success + * @return {number[]} + */ + successfulPairs(spells, potions, success) { + let res = []; + + for (let s of spells) { + let cnt = 0; + for (let p of potions) { + if (s * p >= success) { + cnt++; + } + } + res.push(cnt); + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n * m)$ +* Space complexity: $O(1)$ + +> Where $n$ and $m$ are the sizes of the arrays $spells$ and $potions$ respectively. + +--- + +## 2. Sorting + Binary Search + +::tabs-start + +```python +class Solution: + def successfulPairs(self, spells: List[int], potions: List[int], success: int) -> List[int]: + potions.sort() + res = [] + + for s in spells: + l, r = 0, len(potions) - 1 + idx = len(potions) + + while l <= r: + m = (l + r) // 2 + if s * potions[m] >= success: + r = m - 1 + idx = m + else: + l = m + 1 + + res.append(len(potions) - idx) + + return res +``` + +```java +public class Solution { + public int[] successfulPairs(int[] spells, int[] potions, long success) { + Arrays.sort(potions); + int[] res = new int[spells.length]; + + for (int i = 0; i < spells.length; i++) { + int l = 0, r = potions.length - 1, idx = potions.length; + + while (l <= r) { + int m = (l + r) / 2; + if ((long) spells[i] * potions[m] >= success) { + r = m - 1; + idx = m; + } else { + l = m + 1; + } + } + + res[i] = potions.length - idx; + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + vector successfulPairs(vector& spells, vector& potions, long long success) { + sort(potions.begin(), potions.end()); + vector res(spells.size()); + + for (int i = 0; i < spells.size(); i++) { + int l = 0, r = potions.size() - 1, idx = potions.size(); + + while (l <= r) { + int m = (l + r) / 2; + if ((long long) spells[i] * potions[m] >= success) { + r = m - 1; + idx = m; + } else { + l = m + 1; + } + } + + res[i] = potions.size() - idx; + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} spells + * @param {number[]} potions + * @param {number} success + * @return {number[]} + */ + successfulPairs(spells, potions, success) { + potions.sort((a, b) => a - b); + let res = []; + + for (let s of spells) { + let l = 0, r = potions.length - 1, idx = potions.length; + + while (l <= r) { + let m = Math.floor((l + r) / 2); + if (s * potions[m] >= success) { + r = m - 1; + idx = m; + } else { + l = m + 1; + } + } + + res.push(potions.length - idx); + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O((m + n) * \log m)$ +* Space complexity: + * $O(1)$ or $O(m)$ extra space depending on the sorting algorithm. + * $O(n)$ space for the output array. + +> Where $n$ and $m$ are the sizes of the arrays $spells$ and $potions$ respectively. + +--- + +## 3. Sorting + Two Pointers + +::tabs-start + +```python +class Solution: + def successfulPairs(self, spells: List[int], potions: List[int], success: int) -> List[int]: + n, m = len(spells), len(potions) + S = spells[:] + count = defaultdict(int) + spells.sort() + potions.sort() + + j = m - 1 + for i in range(n): + while j >= 0 and spells[i] * potions[j] >= success: + j -= 1 + count[spells[i]] = m - j - 1 + + res = [0] * n + for i in range(n): + res[i] = count[S[i]] + + return res +``` + +```java +public class Solution { + public int[] successfulPairs(int[] spells, int[] potions, long success) { + int n = spells.length, m = potions.length; + int[] S = Arrays.copyOf(spells, n); + Map count = new HashMap<>(); + Arrays.sort(spells); + Arrays.sort(potions); + + int j = m - 1; + for (int i = 0; i < n; i++) { + while (j >= 0 && (long) spells[i] * potions[j] >= success) { + j--; + } + count.put(spells[i], m - j - 1); + } + + int[] res = new int[n]; + for (int i = 0; i < n; i++) { + res[i] = count.get(S[i]); + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + vector successfulPairs(vector& spells, vector& potions, long long success) { + int n = spells.size(), m = potions.size(); + vector S = spells; + unordered_map count; + sort(spells.begin(), spells.end()); + sort(potions.begin(), potions.end()); + + int j = m - 1; + for (int i = 0; i < n; i++) { + while (j >= 0 && (long long) spells[i] * potions[j] >= success) { + j--; + } + count[spells[i]] = m - j - 1; + } + + vector res(n); + for (int i = 0; i < n; i++) { + res[i] = count[S[i]]; + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} spells + * @param {number[]} potions + * @param {number} success + * @return {number[]} + */ + successfulPairs(spells, potions, success) { + const n = spells.length, m = potions.length; + const S = [...spells]; + const count = new Map(); + spells.sort((a, b) => a - b); + potions.sort((a, b) => a - b); + + let j = m - 1; + for (let i = 0; i < n; i++) { + while (j >= 0 && spells[i] * potions[j] >= success) { + j--; + } + count.set(spells[i], m - j - 1); + } + + return S.map(s => count.get(s)); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n \log n + m\log m)$ +* Space complexity: + * $O(1)$ or $O(m + n)$ extra space depending on the sorting algorithm. + * $O(n)$ space for the output array. + +> Where $n$ and $m$ are the sizes of the arrays $spells$ and $potions$ respectively. + +--- + +## 4. Sorting + Two Pointers (Optimal) + +::tabs-start + +```python +class Solution: + def successfulPairs(self, spells: List[int], potions: List[int], success: int) -> List[int]: + n, m = len(spells), len(potions) + sIdx = list(range(n)) + sIdx.sort(key=lambda x: spells[x]) + potions.sort() + + j = m - 1 + res = [0] * n + for i in range(n): + while j >= 0 and spells[sIdx[i]] * potions[j] >= success: + j -= 1 + res[sIdx[i]] = m - j - 1 + + return res +``` + +```java +public class Solution { + public int[] successfulPairs(int[] spells, int[] potions, long success) { + int n = spells.length, m = potions.length; + Integer[] sIdx = new Integer[n]; + for (int i = 0; i < n; i++) sIdx[i] = i; + + Arrays.sort(sIdx, Comparator.comparingInt(i -> spells[i])); + Arrays.sort(potions); + + int j = m - 1; + int[] res = new int[n]; + for (int i = 0; i < n; i++) { + while (j >= 0 && (long) spells[sIdx[i]] * potions[j] >= success) { + j--; + } + res[sIdx[i]] = m - j - 1; + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + vector successfulPairs(vector& spells, vector& potions, long long success) { + int n = spells.size(), m = potions.size(); + vector sIdx(n); + for (int i = 0; i < n; i++) sIdx[i] = i; + + sort(sIdx.begin(), sIdx.end(), [&](int a, int b) { + return spells[a] < spells[b]; + }); + + sort(potions.begin(), potions.end()); + + int j = m - 1; + vector res(n); + for (int i = 0; i < n; i++) { + while (j >= 0 && (long long) spells[sIdx[i]] * potions[j] >= success) { + j--; + } + res[sIdx[i]] = m - j - 1; + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} spells + * @param {number[]} potions + * @param {number} success + * @return {number[]} + */ + successfulPairs(spells, potions, success) { + const n = spells.length, m = potions.length; + const sIdx = Array.from({ length: n }, (_, i) => i); + + sIdx.sort((a, b) => spells[a] - spells[b]); + potions.sort((a, b) => a - b); + + let j = m - 1; + const res = new Array(n).fill(0); + + for (let i = 0; i < n; i++) { + while (j >= 0 && spells[sIdx[i]] * potions[j] >= success) { + j--; + } + res[sIdx[i]] = m - j - 1; + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n \log n + m\log m)$ +* Space complexity: + * $O(1)$ or $O(m + n)$ extra space depending on the sorting algorithm. + * $O(n)$ space for the output array. + +> Where $n$ and $m$ are the sizes of the arrays $spells$ and $potions$ respectively. \ No newline at end of file diff --git a/articles/sum-of-subarray-minimums.md b/articles/sum-of-subarray-minimums.md new file mode 100644 index 000000000..f1103db9b --- /dev/null +++ b/articles/sum-of-subarray-minimums.md @@ -0,0 +1,596 @@ +## 1. Brute FOrce + +::tabs-start + +```python +class Solution: + def sumSubarrayMins(self, arr: List[int]) -> int: + n, res = len(arr), 0 + MOD = 1000000007 + + for i in range(n): + minVal = arr[i] + for j in range(i, n): + minVal = min(minVal, arr[j]) + res = (res + minVal) % MOD + + return res +``` + +```java +public class Solution { + public int sumSubarrayMins(int[] arr) { + int n = arr.length, res = 0; + int MOD = 1000000007; + + for (int i = 0; i < n; i++) { + int minVal = arr[i]; + for (int j = i; j < n; j++) { + minVal = Math.min(minVal, arr[j]); + res = (res + minVal) % MOD; + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int sumSubarrayMins(vector& arr) { + int n = arr.size(), res = 0; + const int MOD = 1000000007; + + for (int i = 0; i < n; i++) { + int minVal = arr[i]; + for (int j = i; j < n; j++) { + minVal = min(minVal, arr[j]); + res = (res + minVal) % MOD; + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} arr + * @return {number} + */ + sumSubarrayMins(arr) { + const n = arr.length; + let res = 0; + const MOD = 1000000007; + + for (let i = 0; i < n; i++) { + let minVal = arr[i]; + for (let j = i; j < n; j++) { + minVal = Math.min(minVal, arr[j]); + res = (res + minVal) % MOD; + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 2)$ +* Space complexity: $O(1)$ + +--- + +## 2. Monotonically Increasing Stack (Two Pass) + +::tabs-start + +```python +class Solution: + def sumSubarrayMins(self, arr: List[int]) -> int: + MOD = 10**9 + 7 + n = len(arr) + + # Compute previous smaller + prev_smaller = [-1] * n + stack = [] + for i in range(n): + while stack and arr[stack[-1]] > arr[i]: + stack.pop() + prev_smaller[i] = stack[-1] if stack else -1 + stack.append(i) + + # Compute next smaller + next_smaller = [n] * n + stack = [] + for i in range(n - 1, -1, -1): + while stack and arr[stack[-1]] >= arr[i]: + stack.pop() + next_smaller[i] = stack[-1] if stack else n + stack.append(i) + + res = 0 + for i in range(n): + left = i - prev_smaller[i] + right = next_smaller[i] - i + res = (res + arr[i] * left * right) % MOD + + return res +``` + +```java +public class Solution { + public int sumSubarrayMins(int[] arr) { + int MOD = 1000000007; + int n = arr.length; + + // Compute previous smaller + int[] prevSmaller = new int[n]; + Stack stack = new Stack<>(); + for (int i = 0; i < n; i++) { + while (!stack.isEmpty() && arr[stack.peek()] > arr[i]) { + stack.pop(); + } + prevSmaller[i] = stack.isEmpty() ? -1 : stack.peek(); + stack.push(i); + } + + // Compute next smaller + int[] nextSmaller = new int[n]; + stack = new Stack<>(); + for (int i = n - 1; i >= 0; i--) { + while (!stack.isEmpty() && arr[stack.peek()] >= arr[i]) { + stack.pop(); + } + nextSmaller[i] = stack.isEmpty() ? n : stack.peek(); + stack.push(i); + } + + // Calculate result + long res = 0; + for (int i = 0; i < n; i++) { + long left = i - prevSmaller[i]; + long right = nextSmaller[i] - i; + res = (res + arr[i] * left * right) % MOD; + } + + return (int) res; + } +} +``` + +```cpp +class Solution { +public: + int sumSubarrayMins(vector& arr) { + const int MOD = 1e9 + 7; + int n = arr.size(); + + // Compute previous smaller + vector prevSmaller(n, -1); + stack stack; + for (int i = 0; i < n; i++) { + while (!stack.empty() && arr[stack.top()] > arr[i]) { + stack.pop(); + } + prevSmaller[i] = stack.empty() ? -1 : stack.top(); + stack.push(i); + } + + // Compute next smaller + vector nextSmaller(n, n); + stack = {}; + for (int i = n - 1; i >= 0; i--) { + while (!stack.empty() && arr[stack.top()] >= arr[i]) { + stack.pop(); + } + nextSmaller[i] = stack.empty() ? n : stack.top(); + stack.push(i); + } + + // Calculate result + long long res = 0; + for (int i = 0; i < n; i++) { + long long left = i - prevSmaller[i]; + long long right = nextSmaller[i] - i; + res = (res + arr[i] * left * right) % MOD; + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} arr + * @return {number} + */ + sumSubarrayMins(arr) { + const MOD = 1e9 + 7; + const n = arr.length; + + // Compute previous smaller + const prevSmaller = new Array(n).fill(-1); + const stack = []; + for (let i = 0; i < n; i++) { + while (stack.length > 0 && arr[stack[stack.length - 1]] > arr[i]) { + stack.pop(); + } + prevSmaller[i] = stack.length > 0 ? stack[stack.length - 1] : -1; + stack.push(i); + } + + // Compute next smaller + const nextSmaller = new Array(n).fill(n); + stack.length = 0; + for (let i = n - 1; i >= 0; i--) { + while (stack.length > 0 && arr[stack[stack.length - 1]] >= arr[i]) { + stack.pop(); + } + nextSmaller[i] = stack.length > 0 ? stack[stack.length - 1] : n; + stack.push(i); + } + + // Calculate result + let res = 0; + for (let i = 0; i < n; i++) { + const left = i - prevSmaller[i]; + const right = nextSmaller[i] - i; + res = (res + arr[i] * left * right) % MOD; + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ + +--- + +## 3. Monotonically Increasing Stack (One Pass) + +::tabs-start + +```python +class Solution: + def sumSubarrayMins(self, arr: List[int]) -> int: + MOD = 10 ** 9 + 7 + res = 0 + arr = [float("-inf")] + arr + [float("-inf")] + stack = [] # (index, num) + + for i, n in enumerate(arr): + while stack and n < stack[-1][1]: + j, m = stack.pop() + left = j - stack[-1][0] if stack else j + 1 + right = i - j + res = (res + m * left * right) % MOD + stack.append((i, n)) + + return res +``` + +```java +public class Solution { + public int sumSubarrayMins(int[] arr) { + int MOD = 1000000007; + int res = 0; + int[] newArr = new int[arr.length + 2]; + newArr[0] = Integer.MIN_VALUE; + newArr[newArr.length - 1] = Integer.MIN_VALUE; + System.arraycopy(arr, 0, newArr, 1, arr.length); + + Stack stack = new Stack<>(); + + for (int i = 0; i < newArr.length; i++) { + while (!stack.isEmpty() && newArr[i] < stack.peek()[1]) { + int[] top = stack.pop(); + int j = top[0], m = top[1]; + int left = stack.isEmpty() ? j + 1 : j - stack.peek()[0]; + int right = i - j; + res = (int) ((res + (long) m * left * right) % MOD); + } + stack.push(new int[]{i, newArr[i]}); + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int sumSubarrayMins(vector& arr) { + const int MOD = 1e9 + 7; + int res = 0; + vector newArr(arr.size() + 2, INT_MIN); + copy(arr.begin(), arr.end(), newArr.begin() + 1); + + stack> stack; + + for (int i = 0; i < newArr.size(); i++) { + while (!stack.empty() && newArr[i] < stack.top().second) { + auto [j, m] = stack.top(); + stack.pop(); + int left = stack.empty() ? j + 1 : j - stack.top().first; + int right = i - j; + res = (res + (long long) m * left * right % MOD) % MOD; + } + stack.emplace(i, newArr[i]); + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} arr + * @return {number} + */ + sumSubarrayMins(arr) { + const MOD = 1e9 + 7; + let res = 0; + arr = [-Infinity, ...arr, -Infinity]; + let stack = []; + + for (let i = 0; i < arr.length; i++) { + while (stack.length > 0 && arr[i] < stack[stack.length - 1][1]) { + let [j, m] = stack.pop(); + let left = stack.length > 0 ? j - stack[stack.length - 1][0] : j + 1; + let right = i - j; + res = (res + m * left * right) % MOD; + } + stack.push([i, arr[i]]); + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ + +--- + +## 4. Monotonically Increasing Stack (Optimal) + +::tabs-start + +```python +class Solution: + def sumSubarrayMins(self, arr: List[int]) -> int: + MOD = 10**9 + 7 + stack = [] + res, n = 0, len(arr) + + for i in range(n + 1): + while stack and (i == n or arr[i] < arr[stack[-1]]): + j = stack.pop() + left = j - (stack[-1] if stack else -1) + right = i - j + res = (res + arr[j] * left * right) % MOD + stack.append(i) + + return res +``` + +```java +public class Solution { + public int sumSubarrayMins(int[] arr) { + int MOD = 1000000007; + int n = arr.length; + Stack stack = new Stack<>(); + long res = 0; + + for (int i = 0; i <= n; i++) { + while (!stack.isEmpty() && (i == n || arr[i] < arr[stack.peek()])) { + int j = stack.pop(); + int left = j - (stack.isEmpty() ? -1 : stack.peek()); + int right = i - j; + res = (res + (long) arr[j] * left * right) % MOD; + } + stack.push(i); + } + + return (int) res; + } +} +``` + +```cpp +class Solution { +public: + int sumSubarrayMins(vector& arr) { + const int MOD = 1e9 + 7; + int n = arr.size(); + stack stack; + long long res = 0; + + for (int i = 0; i <= n; i++) { + while (!stack.empty() && (i == n || arr[i] < arr[stack.top()])) { + int j = stack.top(); + stack.pop(); + int left = j - (stack.empty() ? -1 : stack.top()); + int right = i - j; + res = (res + (long long) arr[j] * left * right) % MOD; + } + stack.push(i); + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} arr + * @return {number} + */ + sumSubarrayMins(arr) { + const MOD = 1e9 + 7; + const n = arr.length; + const stack = []; + let res = 0; + + for (let i = 0; i <= n; i++) { + while (stack.length > 0 && (i === n || arr[i] < arr[stack[stack.length - 1]])) { + const j = stack.pop(); + const left = j - (stack.length > 0 ? stack[stack.length - 1] : -1); + const right = i - j; + res = (res + arr[j] * left * right) % MOD; + } + stack.push(i); + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ + +--- + +## 5. Dynamic Programming + Stack + +::tabs-start + +```python +class Solution: + def sumSubarrayMins(self, arr: List[int]) -> int: + MOD = 10**9 + 7 + n = len(arr) + dp = [0] * n + stack, res = [], 0 + + for i in range(n): + while stack and arr[stack[-1]] > arr[i]: + stack.pop() + + j = stack[-1] if stack else -1 + dp[i] = (dp[j] if j != -1 else 0) + arr[i] * (i - j) + dp[i] %= MOD + res = (res + dp[i]) % MOD + stack.append(i) + + return res +``` + +```java +public class Solution { + public int sumSubarrayMins(int[] arr) { + int MOD = 1000000007; + int n = arr.length; + int[] dp = new int[n]; + Stack stack = new Stack<>(); + long res = 0; + + for (int i = 0; i < n; i++) { + while (!stack.isEmpty() && arr[stack.peek()] > arr[i]) { + stack.pop(); + } + + int j = stack.isEmpty() ? -1 : stack.peek(); + dp[i] = ((j != -1 ? dp[j] : 0) + arr[i] * (i - j)) % MOD; + res = (res + dp[i]) % MOD; + stack.push(i); + } + + return (int) res; + } +} +``` + +```cpp +class Solution { +public: + int sumSubarrayMins(vector& arr) { + const int MOD = 1e9 + 7; + int n = arr.size(); + vector dp(n, 0); + stack stack; + long long res = 0; + + for (int i = 0; i < n; i++) { + while (!stack.empty() && arr[stack.top()] > arr[i]) { + stack.pop(); + } + + int j = stack.empty() ? -1 : stack.top(); + dp[i] = ((j != -1 ? dp[j] : 0) + arr[i] * (i - j)) % MOD; + res = (res + dp[i]) % MOD; + stack.push(i); + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} arr + * @return {number} + */ + sumSubarrayMins(arr) { + const MOD = 1e9 + 7; + const n = arr.length; + const dp = new Array(n).fill(0); + const stack = []; + let res = 0; + + for (let i = 0; i < n; i++) { + while (stack.length > 0 && arr[stack[stack.length - 1]] > arr[i]) { + stack.pop(); + } + + const j = stack.length > 0 ? stack[stack.length - 1] : -1; + dp[i] = ((j !== -1 ? dp[j] : 0) + arr[i] * (i - j)) % MOD; + res = (res + dp[i]) % MOD; + stack.push(i); + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ \ No newline at end of file diff --git a/articles/valid-perfect-square.md b/articles/valid-perfect-square.md new file mode 100644 index 000000000..c5682c5d4 --- /dev/null +++ b/articles/valid-perfect-square.md @@ -0,0 +1,447 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def isPerfectSquare(self, num: int) -> bool: + for i in range(1, num + 1): + sq = i * i + if sq > num: + return False + if sq == num: + return True +``` + +```java +public class Solution { + public boolean isPerfectSquare(int num) { + for (long i = 1; i <= num; i++) { + long sq = i * i; + if (sq > num) { + return false; + } + if (sq == num) { + return true; + } + } + return false; + } +} +``` + +```cpp +class Solution { +public: + bool isPerfectSquare(int num) { + for (long long i = 1; i <= num; i++) { + long long sq = i * i; + if (sq > num) { + return false; + } + if (sq == num) { + return true; + } + } + return false; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} num + * @return {boolean} + */ + isPerfectSquare(num) { + for (let i = 1; i <= num; i++) { + let sq = i * i; + if (sq > num) { + return false; + } + if (sq === num) { + return true; + } + } + return false; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(\sqrt {n})$ +* Space complexity: $O(1)$ + +--- + +## 2. In-Built Function + +::tabs-start + +```python +class Solution: + def isPerfectSquare(self, num: int) -> bool: + sqRoot = int(sqrt(num)) + return sqRoot * sqRoot == num +``` + +```java +public class Solution { + public boolean isPerfectSquare(int num) { + int sqRoot = (int) Math.sqrt(num); + return sqRoot * sqRoot == num; + } +} +``` + +```cpp +class Solution { +public: + bool isPerfectSquare(int num) { + int sqRoot = (int) sqrt(num); + return sqRoot * sqRoot == num; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} num + * @return {boolean} + */ + isPerfectSquare(num) { + let sqRoot = Math.floor(Math.sqrt(num)); + return sqRoot * sqRoot === num; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(1)$ +* Space complexity: $O(1)$ + +--- + +## 3. Binary Search + +::tabs-start + +```python +class Solution: + def isPerfectSquare(self, num: int) -> bool: + l, r = 1, num + + while l <= r: + m = l + (r - l) // 2 + sq = m * m + if sq > num: + r = m - 1 + elif sq < num: + l = m + 1 + else: + return True + + return False +``` + +```java +public class Solution { + public boolean isPerfectSquare(int num) { + long l = 1, r = num; + + while (l <= r) { + long m = l + (r - l) / 2; + long sq = m * m; + if (sq > num) { + r = m - 1; + } else if (sq < num) { + l = m + 1; + } else { + return true; + } + } + + return false; + } +} +``` + +```cpp +class Solution { +public: + bool isPerfectSquare(int num) { + long long l = 1, r = num; + + while (l <= r) { + long long m = l + (r - l) / 2; + long long sq = m * m; + if (sq > num) { + r = m - 1; + } else if (sq < num) { + l = m + 1; + } else { + return true; + } + } + + return false; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} num + * @return {boolean} + */ + isPerfectSquare(num) { + let l = 1, r = num; + + while (l <= r) { + let m = Math.floor(l + (r - l) / 2); + let sq = m * m; + if (sq > num) { + r = m - 1; + } else if (sq < num) { + l = m + 1; + } else { + return true; + } + } + + return false; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(\log n)$ +* Space complexity: $O(1)$ + +--- + +## 4. Math + +::tabs-start + +```python +class Solution: + def isPerfectSquare(self, num: int) -> bool: + i = 1 + while num > 0: + num -= i + i += 2 + return num == 0 +``` + +```java +public class Solution { + public boolean isPerfectSquare(int num) { + int i = 1; + while (num > 0) { + num -= i; + i += 2; + } + return num == 0; + } +} +``` + +```cpp +class Solution { +public: + bool isPerfectSquare(int num) { + int i = 1; + while (num > 0) { + num -= i; + i += 2; + } + return num == 0; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} num + * @return {boolean} + */ + isPerfectSquare(num) { + let i = 1; + while (num > 0) { + num -= i; + i += 2; + } + return num === 0; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(\sqrt {n})$ +* Space complexity: $O(1)$ + +--- + +## 5. Newton's Method + +::tabs-start + +```python +class Solution: + def isPerfectSquare(self, num: int) -> bool: + r = num + while r * r > num: + r = (r + (num // r)) // 2 + return r * r == num +``` + +```java +public class Solution { + public boolean isPerfectSquare(int num) { + long r = num; + while (r * r > num) { + r = (r + num / r) / 2; + } + return r * r == num; + } +} +``` + +```cpp +class Solution { +public: + bool isPerfectSquare(int num) { + long long r = num; + while (r * r > num) { + r = (r + num / r) / 2; + } + return r * r == num; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} num + * @return {boolean} + */ + isPerfectSquare(num) { + let r = num; + while (r * r > num) { + r = Math.floor((r + Math.floor(num / r)) / 2); + } + return r * r === num; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(\log n)$ +* Space complexity: $O(1)$ + +--- + +## 6. Bit Manipulation + +::tabs-start + +```python +class Solution: + def isPerfectSquare(self, num: int) -> bool: + r, mask = 0, 1 << 15 + + while mask > 0: + r |= mask + if r > (num // r): + r ^= mask + mask >>= 1 + + return r * r == num +``` + +```java +public class Solution { + public boolean isPerfectSquare(int num) { + int r = 0, mask = 1 << 15; + + while (mask > 0) { + r |= mask; + if (r > (num / r)) { + r ^= mask; + } + mask >>= 1; + } + + return r * r == num; + } +} +``` + +```cpp +class Solution { +public: + bool isPerfectSquare(int num) { + int r = 0, mask = 1 << 15; + + while (mask > 0) { + r |= mask; + if (r > (num / r)) { + r ^= mask; + } + mask >>= 1; + } + + return r * r == num; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} num + * @return {boolean} + */ + isPerfectSquare(num) { + let r = 0, mask = 1 << 15; + + while (mask > 0) { + r |= mask; + if (r > Math.floor(num / r)) { + r ^= mask; + } + mask >>= 1; + } + + return r * r === num; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(1)$ since we iterate at most $15$ times. +* Space complexity: $O(1)$ \ No newline at end of file From b1e1ec008d8eff9901bf9a4a9425aaee404149a4 Mon Sep 17 00:00:00 2001 From: Sri Hari Date: Wed, 29 Jan 2025 18:05:47 +0530 Subject: [PATCH 3/7] Batch-5/Neetcode-ALL/Added-articles --- ...ast-position-of-element-in-sorted-array.md | 449 +++++++++++ .../maximum-number-of-removable-characters.md | 451 +++++++++++ ...inimize-the-maximum-difference-of-pairs.md | 561 ++++++++++++++ ...lating-next-right-pointers-in-each-node.md | 700 ++++++++++++++++++ articles/search-suggestions-system.md | 589 +++++++++++++++ 5 files changed, 2750 insertions(+) create mode 100644 articles/find-first-and-last-position-of-element-in-sorted-array.md create mode 100644 articles/maximum-number-of-removable-characters.md create mode 100644 articles/minimize-the-maximum-difference-of-pairs.md create mode 100644 articles/populating-next-right-pointers-in-each-node.md create mode 100644 articles/search-suggestions-system.md diff --git a/articles/find-first-and-last-position-of-element-in-sorted-array.md b/articles/find-first-and-last-position-of-element-in-sorted-array.md new file mode 100644 index 000000000..e2d66f092 --- /dev/null +++ b/articles/find-first-and-last-position-of-element-in-sorted-array.md @@ -0,0 +1,449 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def searchRange(self, nums: List[int], target: int) -> List[int]: + res = [-1, -1] + + for i, num in enumerate(nums): + if num == target: + if res[0] == -1: + res[0] = res[1] = i + else: + res[1] = i + + return res +``` + +```java +public class Solution { + public int[] searchRange(int[] nums, int target) { + int[] res = {-1, -1}; + + for (int i = 0; i < nums.length; i++) { + if (nums[i] == target) { + if (res[0] == -1) { + res[0] = res[1] = i; + } else { + res[1] = i; + } + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + vector searchRange(vector& nums, int target) { + vector res = {-1, -1}; + + for (int i = 0; i < nums.size(); i++) { + if (nums[i] == target) { + if (res[0] == -1) { + res[0] = res[1] = i; + } else { + res[1] = i; + } + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} target + * @return {number[]} + */ + searchRange(nums, target) { + let res = [-1, -1]; + + for (let i = 0; i < nums.length; i++) { + if (nums[i] === target) { + if (res[0] === -1) { + res[0] = res[1] = i; + } else { + res[1] = i; + } + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(1)$ + +--- + +## 2. Binary Search - I + +::tabs-start + +```python +class Solution: + def searchRange(self, nums: List[int], target: int) -> List[int]: + left = self.binarySearch(nums, target, True) + right = self.binarySearch(nums, target, False) + return [left, right] + + def binarySearch(self, nums, target, leftBias): + l, r = 0, len(nums) - 1 + i = -1 + while l <= r: + m = (l + r) // 2 + if target > nums[m]: + l = m + 1 + elif target < nums[m]: + r = m - 1 + else: + i = m + if leftBias: + r = m - 1 + else: + l = m + 1 + return i +``` + +```java +public class Solution { + public int[] searchRange(int[] nums, int target) { + int left = binarySearch(nums, target, true); + int right = binarySearch(nums, target, false); + return new int[]{left, right}; + } + + private int binarySearch(int[] nums, int target, boolean leftBias) { + int l = 0, r = nums.length - 1, i = -1; + while (l <= r) { + int m = (l + r) / 2; + if (target > nums[m]) { + l = m + 1; + } else if (target < nums[m]) { + r = m - 1; + } else { + i = m; + if (leftBias) { + r = m - 1; + } else { + l = m + 1; + } + } + } + return i; + } +} +``` + +```cpp +class Solution { +public: + vector searchRange(vector& nums, int target) { + int left = binarySearch(nums, target, true); + int right = binarySearch(nums, target, false); + return {left, right}; + } + +private: + int binarySearch(vector& nums, int target, bool leftBias) { + int l = 0, r = nums.size() - 1, i = -1; + while (l <= r) { + int m = (l + r) / 2; + if (target > nums[m]) { + l = m + 1; + } else if (target < nums[m]) { + r = m - 1; + } else { + i = m; + if (leftBias) { + r = m - 1; + } else { + l = m + 1; + } + } + } + return i; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} target + * @return {number[]} + */ + searchRange(nums, target) { + let left = this.binarySearch(nums, target, true); + let right = this.binarySearch(nums, target, false); + return [left, right]; + } + + /** + * @param {number[]} nums + * @param {number} target + * @param {boolean} leftBias + * @return {number} + */ + binarySearch(nums, target, leftBias) { + let l = 0, r = nums.length - 1, i = -1; + while (l <= r) { + let m = Math.floor((l + r) / 2); + if (target > nums[m]) { + l = m + 1; + } else if (target < nums[m]) { + r = m - 1; + } else { + i = m; + if (leftBias) { + r = m - 1; + } else { + l = m + 1; + } + } + } + return i; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(\log n)$ +* Space complexity: $O(1)$ + +--- + +## 3. Binary Search - II + +::tabs-start + +```python +class Solution: + def searchRange(self, nums: List[int], target: int) -> List[int]: + n = len(nums) + + def binarySearch(target): + l, r = 0, n + while l < r: + m = l + (r - l) // 2 + if nums[m] >= target: + r = m + else: + l = m + 1 + return l + + start = binarySearch(target) + if start == n or nums[start] != target: + return [-1, -1] + + return [start, binarySearch(target + 1) - 1] +``` + +```java +public class Solution { + public int[] searchRange(int[] nums, int target) { + int n = nums.length; + + int start = binarySearch(nums, target, n); + if (start == n || nums[start] != target) { + return new int[]{-1, -1}; + } + + return new int[]{start, binarySearch(nums, target + 1, n) - 1}; + } + + private int binarySearch(int[] nums, int target, int n) { + int l = 0, r = n; + while (l < r) { + int m = l + (r - l) / 2; + if (nums[m] >= target) { + r = m; + } else { + l = m + 1; + } + } + return l; + } +} +``` + +```cpp +class Solution { +public: + vector searchRange(vector& nums, int target) { + int n = nums.size(); + + int start = binarySearch(nums, target, n); + if (start == n || nums[start] != target) { + return {-1, -1}; + } + + return {start, binarySearch(nums, target + 1, n) - 1}; + } + +private: + int binarySearch(vector& nums, int target, int n) { + int l = 0, r = n; + while (l < r) { + int m = l + (r - l) / 2; + if (nums[m] >= target) { + r = m; + } else { + l = m + 1; + } + } + return l; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} target + * @return {number[]} + */ + searchRange(nums, target) { + const n = nums.length; + + const binarySearch = (target) => { + let l = 0, r = n; + while (l < r) { + let m = Math.floor(l + (r - l) / 2); + if (nums[m] >= target) { + r = m; + } else { + l = m + 1; + } + } + return l; + }; + + let start = binarySearch(target); + if (start === n || nums[start] !== target) { + return [-1, -1]; + } + + return [start, binarySearch(target + 1) - 1]; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(\log n)$ +* Space complexity: $O(1)$ + +--- + +## 4. In-Built Function + +::tabs-start + +```python +class Solution: + def searchRange(self, nums: List[int], target: int) -> List[int]: + left = bisect.bisect_left(nums, target) + if left >= len(nums) or nums[left] != target: + return [-1, -1] + + right = bisect.bisect_right(nums, target) - 1 + return [left, right] +``` + +```java +public class Solution { + public int[] searchRange(int[] nums, int target) { + int left = findLeft(nums, target); + if (left == -1) { + return new int[]{-1, -1}; + } + + int right = findRight(nums, target); + return new int[]{left, right}; + } + + private int findLeft(int[] nums, int target) { + // O(n) time in worst case + int index = Arrays.binarySearch(nums, target); + if (index < 0) return -1; + + while (index > 0 && nums[index - 1] == target) { + index--; + } + return index; + } + + private int findRight(int[] nums, int target) { + // O(n) time in worst case + int index = Arrays.binarySearch(nums, target); + if (index < 0) return -1; + + while (index < nums.length - 1 && nums[index + 1] == target) { + index++; + } + return index; + } +} +``` + +```cpp +class Solution { +public: + vector searchRange(vector& nums, int target) { + int left = lower_bound(nums.begin(), nums.end(), target) - nums.begin(); + if (left == nums.size() || nums[left] != target) { + return {-1, -1}; + } + + int right = upper_bound(nums.begin(), nums.end(), target) - nums.begin() - 1; + return {left, right}; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} target + * @return {number[]} + */ + searchRange(nums, target) { + let left = nums.indexOf(target); + let right = nums.lastIndexOf(target); + + return left === -1 ? [-1, -1] : [left, right]; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(\log n)$ +* Space complexity: $O(1)$ \ No newline at end of file diff --git a/articles/maximum-number-of-removable-characters.md b/articles/maximum-number-of-removable-characters.md new file mode 100644 index 000000000..bc22c959f --- /dev/null +++ b/articles/maximum-number-of-removable-characters.md @@ -0,0 +1,451 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def maximumRemovals(self, s: str, p: str, removable: List[int]) -> int: + n, m = len(s), len(p) + marked = set() + res = 0 + + for removeIdx in removable: + marked.add(removeIdx) + + sIdx = pIdx = 0 + while pIdx < m and sIdx < n: + if sIdx not in marked and s[sIdx] == p[pIdx]: + pIdx += 1 + sIdx += 1 + if pIdx != m: + break + res += 1 + + return res +``` + +```java +public class Solution { + public int maximumRemovals(String s, String p, int[] removable) { + int n = s.length(), m = p.length(); + Set marked = new HashSet<>(); + int res = 0; + + for (int removeIdx : removable) { + marked.add(removeIdx); + + int sIdx = 0, pIdx = 0; + while (pIdx < m && sIdx < n) { + if (!marked.contains(sIdx) && s.charAt(sIdx) == p.charAt(pIdx)) { + pIdx++; + } + sIdx++; + } + + if (pIdx != m) break; + res++; + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int maximumRemovals(string s, string p, vector& removable) { + int n = s.size(), m = p.size(); + unordered_set marked; + int res = 0; + + for (int removeIdx : removable) { + marked.insert(removeIdx); + + int sIdx = 0, pIdx = 0; + while (pIdx < m && sIdx < n) { + if (marked.find(sIdx) == marked.end() && s[sIdx] == p[pIdx]) { + pIdx++; + } + sIdx++; + } + + if (pIdx != m) break; + res++; + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s + * @param {string} p + * @param {number[]} removable + * @return {number} + */ + maximumRemovals(s, p, removable) { + let n = s.length, m = p.length; + let marked = new Set(); + let res = 0; + + for (let removeIdx of removable) { + marked.add(removeIdx); + + let sIdx = 0, pIdx = 0; + while (pIdx < m && sIdx < n) { + if (!marked.has(sIdx) && s[sIdx] === p[pIdx]) { + pIdx++; + } + sIdx++; + } + + if (pIdx !== m) break; + res++; + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(k * (n + m))$ +* Space complexity: $O(k)$ + +> Where $n$ and $m$ are the lengths of the given strings $s$ and $p$ respectively. $k$ is the size of the array $removable$. + +--- + +## 2. Binary Search + Hash Set + +::tabs-start + +```python +class Solution: + def maximumRemovals(self, s: str, p: str, removable: List[int]) -> int: + def isSubseq(s, subseq, removed): + i1 = i2 = 0 + while i1 < len(s) and i2 < len(subseq): + if i1 in removed or s[i1] != subseq[i2]: + i1 += 1 + continue + i1 += 1 + i2 += 1 + return i2 == len(subseq) + + res = 0 + l, r = 0, len(removable) - 1 + while l <= r: + m = (l + r) // 2 + removed = set(removable[:m + 1]) + if isSubseq(s, p, removed): + res = max(res, m + 1) + l = m + 1 + else: + r = m - 1 + + return res +``` + +```java +public class Solution { + public int maximumRemovals(String s, String p, int[] removable) { + int res = 0, l = 0, r = removable.length - 1; + + while (l <= r) { + int m = (l + r) / 2; + Set removed = new HashSet<>(); + for (int i = 0; i <= m; i++) { + removed.add(removable[i]); + } + + if (isSubseq(s, p, removed)) { + res = Math.max(res, m + 1); + l = m + 1; + } else { + r = m - 1; + } + } + + return res; + } + + private boolean isSubseq(String s, String subseq, Set removed) { + int i1 = 0, i2 = 0; + while (i1 < s.length() && i2 < subseq.length()) { + if (removed.contains(i1) || s.charAt(i1) != subseq.charAt(i2)) { + i1++; + continue; + } + i1++; + i2++; + } + return i2 == subseq.length(); + } +} +``` + +```cpp +class Solution { +public: + int maximumRemovals(string s, string p, vector& removable) { + int res = 0, l = 0, r = removable.size() - 1; + + while (l <= r) { + int m = (l + r) / 2; + unordered_set removed(removable.begin(), removable.begin() + m + 1); + + if (isSubseq(s, p, removed)) { + res = max(res, m + 1); + l = m + 1; + } else { + r = m - 1; + } + } + + return res; + } + +private: + bool isSubseq(string& s, string& subseq, unordered_set& removed) { + int i1 = 0, i2 = 0; + while (i1 < s.size() && i2 < subseq.size()) { + if (removed.count(i1) || s[i1] != subseq[i2]) { + i1++; + continue; + } + i1++; + i2++; + } + return i2 == subseq.size(); + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s + * @param {string} p + * @param {number[]} removable + * @return {number} + */ + maximumRemovals(s, p, removable) { + let res = 0, l = 0, r = removable.length - 1; + + while (l <= r) { + let m = Math.floor((l + r) / 2); + let removed = new Set(removable.slice(0, m + 1)); + + if (this.isSubseq(s, p, removed)) { + res = Math.max(res, m + 1); + l = m + 1; + } else { + r = m - 1; + } + } + + return res; + } + + /** + * @param {string} s + * @param {string} subseq + * @param {Set} removed + * @return {boolean} + */ + isSubseq(s, subseq, removed) { + let i1 = 0, i2 = 0; + while (i1 < s.length && i2 < subseq.length) { + if (removed.has(i1) || s[i1] !== subseq[i2]) { + i1++; + continue; + } + i1++; + i2++; + } + return i2 === subseq.length; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O((n + m) * \log k)$ +* Space complexity: $O(k)$ + +> Where $n$ and $m$ are the lengths of the given strings $s$ and $p$ respectively. $k$ is the size of the array $removable$. + +--- + +## 3. Binary Search + +::tabs-start + +```python +class Solution: + def maximumRemovals(self, s: str, p: str, removable: List[int]) -> int: + l, r = 0, len(removable) + n, m = len(s), len(p) + + def isSubseq(tmpS): + i1 = i2 = 0 + while i1 < n and i2 < m: + if tmpS[i1] == p[i2]: + i2 += 1 + i1 += 1 + return i2 == m + + while l < r: + mid = l + (r - l) // 2 + tmpS = list(s) + + for i in range(mid + 1): + tmpS[removable[i]] = '#' + + if isSubseq(tmpS): + l = mid + 1 + else: + r = mid + + return l +``` + +```java +public class Solution { + public int maximumRemovals(String s, String p, int[] removable) { + int l = 0, r = removable.length; + int n = s.length(), m = p.length(); + + while (l < r) { + int mid = l + (r - l) / 2; + char[] tmpS = s.toCharArray(); + + for (int i = 0; i <= mid; i++) { + tmpS[removable[i]] = '#'; + } + + if (isSubseq(tmpS, p)) { + l = mid + 1; + } else { + r = mid; + } + } + + return l; + } + + private boolean isSubseq(char[] s, String p) { + int i1 = 0, i2 = 0, n = s.length, m = p.length(); + + while (i1 < n && i2 < m) { + if (s[i1] == p.charAt(i2)) { + i2++; + } + i1++; + } + return i2 == m; + } +} +``` + +```cpp +class Solution { +public: + int maximumRemovals(string s, string p, vector& removable) { + int l = 0, r = removable.size(); + int n = s.size(), m = p.size(); + + while (l < r) { + int mid = l + (r - l) / 2; + string tmpS = s; + + for (int i = 0; i <= mid; i++) { + tmpS[removable[i]] = '#'; + } + + if (isSubseq(tmpS, p)) { + l = mid + 1; + } else { + r = mid; + } + } + + return l; + } + +private: + bool isSubseq(const string& s, const string& p) { + int i1 = 0, i2 = 0, n = s.size(), m = p.size(); + + while (i1 < n && i2 < m) { + if (s[i1] == p[i2]) { + i2++; + } + i1++; + } + return i2 == m; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s + * @param {string} p + * @param {number[]} removable + * @return {number} + */ + maximumRemovals(s, p, removable) { + let l = 0, r = removable.length; + let n = s.length, m = p.length; + + const isSubseq = (tmpS) => { + let i1 = 0, i2 = 0; + while (i1 < n && i2 < m) { + if (tmpS[i1] === p[i2]) { + i2++; + } + i1++; + } + return i2 === m; + }; + + while (l < r) { + let mid = Math.floor(l + (r - l) / 2); + let tmpS = s.split(""); + + for (let i = 0; i <= mid; i++) { + tmpS[removable[i]] = "#"; + } + + if (isSubseq(tmpS)) { + l = mid + 1; + } else { + r = mid; + } + } + + return l; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O((n + m) * \log k)$ +* Space complexity: $O(n)$ + +> Where $n$ and $m$ are the lengths of the given strings $s$ and $p$ respectively. $k$ is the size of the array $removable$. \ No newline at end of file diff --git a/articles/minimize-the-maximum-difference-of-pairs.md b/articles/minimize-the-maximum-difference-of-pairs.md new file mode 100644 index 000000000..5ad0f31b1 --- /dev/null +++ b/articles/minimize-the-maximum-difference-of-pairs.md @@ -0,0 +1,561 @@ +## 1. Greedy + Dynamic Programming (Top-Down) + +::tabs-start + +```python +class Solution: + def minimizeMax(self, nums: List[int], p: int) -> int: + n = len(nums) + nums.sort() + dp = {} + + def dfs(i, pairs): + if pairs == p: + return 0 + if i >= n - 1: + return float('inf') + if (i, pairs) in dp: + return dp[(i, pairs)] + + take = max(nums[i + 1] - nums[i], dfs(i + 2, pairs + 1)) + skip = dfs(i + 1, pairs) + dp[(i, pairs)] = min(take, skip) + return dp[(i, pairs)] + + return dfs(0, 0) +``` + +```java +public class Solution { + private Map dp; + + public int minimizeMax(int[] nums, int p) { + Arrays.sort(nums); + dp = new HashMap<>(); + return dfs(0, 0, nums, p); + } + + private int dfs(int i, int pairs, int[] nums, int p) { + if (pairs == p) return 0; + if (i >= nums.length - 1) return Integer.MAX_VALUE; + + String key = i + "," + pairs; + if (dp.containsKey(key)) return dp.get(key); + + int take = Math.max(nums[i + 1] - nums[i], dfs(i + 2, pairs + 1, nums, p)); + int skip = dfs(i + 1, pairs, nums, p); + + int res = Math.min(take, skip); + dp.put(key, res); + return res; + } +} +``` + +```cpp +class Solution { + unordered_map dp; + +public: + int minimizeMax(vector& nums, int p) { + int n = nums.size(); + sort(nums.begin(), nums.end()); + return dfs(0, 0, nums, p); + } + +private: + int dfs(int i, int pairs, vector& nums, int p) { + if (pairs == p) return 0; + if (i >= nums.size() - 1) return INT_MAX; + long long key = i; + key = (key << 31) | pairs; + if (dp.count(key)) return dp[key]; + + int take = max(nums[i + 1] - nums[i], dfs(i + 2, pairs + 1, nums, p)); + int skip = dfs(i + 1, pairs, nums, p); + + return dp[key] = min(take, skip); + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} p + * @return {number} + */ + minimizeMax(nums, p) { + nums.sort((a, b) => a - b); + const dp = new Map(); + + const dfs = (i, pairs) => { + if (pairs === p) return 0; + if (i >= nums.length - 1) return Infinity; + + let key = `${i},${pairs}`; + if (dp.has(key)) return dp.get(key); + + let take = Math.max(nums[i + 1] - nums[i], dfs(i + 2, pairs + 1)); + let skip = dfs(i + 1, pairs); + + let result = Math.min(take, skip); + dp.set(key, result); + return result; + }; + + return dfs(0, 0); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n * p)$ +* Space complexity: $O(n * p)$ + +> Where $n$ is the size of the input array and $p$ is the number of pairs to select. + +--- + +## 2. Greesy + Dynamic Programming (Bottom-Up) + +::tabs-start + +```python +class Solution: + def minimizeMax(self, nums: List[int], p: int) -> int: + n = len(nums) + nums.sort() + + dp = [[float('inf')] * (p + 1) for _ in range(n + 1)] + for i in range(n + 1): + dp[i][0] = 0 + + for i in range(n - 2, -1, -1): + for pairs in range(1, p + 1): + take = float('inf') + if i + 1 < n: + take = max(nums[i + 1] - nums[i], dp[i + 2][pairs - 1]) + + skip = dp[i + 1][pairs] + dp[i][pairs] = min(take, skip) + + return dp[0][p] +``` + +```java +public class Solution { + public int minimizeMax(int[] nums, int p) { + int n = nums.length; + Arrays.sort(nums); + + int[][] dp = new int[n + 1][p + 1]; + for (int i = 0; i <= n; i++) { + Arrays.fill(dp[i], Integer.MAX_VALUE); + dp[i][0] = 0; + } + + for (int i = n - 2; i >= 0; i--) { + for (int pairs = 1; pairs <= p; pairs++) { + int take = Integer.MAX_VALUE; + if (i + 1 < n) { + take = Math.max(nums[i + 1] - nums[i], dp[i + 2][pairs - 1]); + } + int skip = dp[i + 1][pairs]; + dp[i][pairs] = Math.min(take, skip); + } + } + + return dp[0][p]; + } +} +``` + +```cpp +class Solution { +public: + int minimizeMax(vector& nums, int p) { + int n = nums.size(); + sort(nums.begin(), nums.end()); + + vector> dp(n + 1, vector(p + 1, INT_MAX)); + for (int i = 0; i <= n; i++) { + dp[i][0] = 0; + } + + for (int i = n - 2; i >= 0; i--) { + for (int pairs = 1; pairs <= p; pairs++) { + int take = INT_MAX; + if (i + 1 < n) { + take = max(nums[i + 1] - nums[i], dp[i + 2][pairs - 1]); + } + int skip = dp[i + 1][pairs]; + dp[i][pairs] = min(take, skip); + } + } + + return dp[0][p]; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} p + * @return {number} + */ + minimizeMax(nums, p) { + const n = nums.length; + nums.sort((a, b) => a - b); + + const dp = Array.from({ length: n + 1 }, () => + new Array(p + 1).fill(Infinity) + ); + for (let i = 0; i <= n; i++) { + dp[i][0] = 0; + } + + for (let i = n - 2; i >= 0; i--) { + for (let pairs = 1; pairs <= p; pairs++) { + let take = Infinity; + if (i + 1 < n) { + take = Math.max(nums[i + 1] - nums[i], dp[i + 2][pairs - 1]); + } + const skip = dp[i + 1][pairs]; + dp[i][pairs] = Math.min(take, skip); + } + } + + return dp[0][p]; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n * p)$ +* Space complexity: $O(n * p)$ + +> Where $n$ is the size of the input array and $p$ is the number of pairs to select. + +--- + +## 3. Greesy + Dynamic Programming (Space Optimized) + +::tabs-start + +```python +class Solution: + def minimizeMax(self, nums: List[int], p: int) -> int: + n = len(nums) + nums.sort() + + dp = [float('inf')] * (p + 1) + dp1 = [float('inf')] * (p + 1) + dp2 = [float('inf')] * (p + 1) + + dp[0] = dp1[0] = dp2[0] = 0 + for i in range(n - 1, -1, -1): + for pairs in range(1, p + 1): + take = float('inf') + if i + 1 < n: + take = max(nums[i + 1] - nums[i], dp2[pairs - 1]) + skip = dp1[pairs] + dp[pairs] = min(take, skip) + + dp2 = dp1[:] + dp1 = dp[:] + dp = [float('inf')] * (p + 1) + dp[0] = 0 + + return dp1[p] +``` + +```java +public class Solution { + public int minimizeMax(int[] nums, int p) { + int n = nums.length; + Arrays.sort(nums); + + int[] dp = new int[p + 1]; + int[] dp1 = new int[p + 1]; + int[] dp2 = new int[p + 1]; + Arrays.fill(dp, Integer.MAX_VALUE); + Arrays.fill(dp1, Integer.MAX_VALUE); + Arrays.fill(dp2, Integer.MAX_VALUE); + dp[0] = dp1[0] = dp2[0] = 0; + + for (int i = n - 1; i >= 0; i--) { + for (int pairs = 1; pairs <= p; pairs++) { + int take = Integer.MAX_VALUE; + if (i + 1 < n) { + take = Math.max(nums[i + 1] - nums[i], dp2[pairs - 1]); + } + int skip = dp1[pairs]; + dp[pairs] = Math.min(take, skip); + } + dp2 = dp1.clone(); + dp1 = dp.clone(); + Arrays.fill(dp, Integer.MAX_VALUE); + dp[0] = 0; + } + + return dp1[p]; + } +} +``` + +```cpp +class Solution { +public: + int minimizeMax(vector& nums, int p) { + int n = nums.size(); + sort(nums.begin(), nums.end()); + + vector dp(p + 1, INT_MAX); + vector dp1(p + 1, INT_MAX); + vector dp2(p + 1, INT_MAX); + + dp[0] = dp1[0] = dp2[0] = 0; + + for (int i = n - 1; i >= 0; i--) { + for (int pairs = 1; pairs <= p; pairs++) { + int take = INT_MAX; + if (i + 1 < n) { + take = max(nums[i + 1] - nums[i], dp2[pairs - 1]); + } + int skip = dp1[pairs]; + dp[pairs] = min(take, skip); + } + dp2 = dp1; + dp1 = dp; + fill(dp.begin(), dp.end(), INT_MAX); + dp[0] = 0; + } + + return dp1[p]; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} p + * @return {number} + */ + minimizeMax(nums, p) { + const n = nums.length; + nums.sort((a, b) => a - b); + + let dp = new Array(p + 1).fill(Infinity); + let dp1 = new Array(p + 1).fill(Infinity); + let dp2 = new Array(p + 1).fill(Infinity); + + dp[0] = dp1[0] = dp2[0] = 0; + + for (let i = n - 1; i >= 0; i--) { + for (let pairs = 1; pairs <= p; pairs++) { + let take = Infinity; + if (i + 1 < n) { + take = Math.max(nums[i + 1] - nums[i], dp2[pairs - 1]); + } + let skip = dp1[pairs]; + dp[pairs] = Math.min(take, skip); + } + dp2 = dp1.slice(); + dp1 = dp.slice(); + dp.fill(Infinity); + dp[0] = 0; + } + + return dp1[p]; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n * p)$ +* Space complexity: $O(p)$ + +> Where $n$ is the size of the input array and $p$ is the number of pairs to select. + +--- + +## 4. Greedy + Binary Search + +::tabs-start + +```python +class Solution: + def minimizeMax(self, nums: List[int], p: int) -> int: + if p == 0: + return 0 + + def isValid(threshold): + i, cnt = 0, 0 + while i < len(nums) - 1: + if abs(nums[i] - nums[i + 1]) <= threshold: + cnt += 1 + i += 2 + else: + i += 1 + if cnt == p: + return True + return False + + nums.sort() + l, r = 0, nums[-1] - nums[0] + res = nums[-1] - nums[0] + + while l <= r: + m = l + (r - l) // 2 + if isValid(m): + res = m + r = m - 1 + else: + l = m + 1 + + return res +``` + +```java +public class Solution { + public int minimizeMax(int[] nums, int p) { + if (p == 0) return 0; + + Arrays.sort(nums); + int left = 0, right = nums[nums.length - 1] - nums[0]; + int result = right; + + while (left <= right) { + int mid = left + (right - left) / 2; + if (isValid(nums, mid, p)) { + result = mid; + right = mid - 1; + } else { + left = mid + 1; + } + } + + return result; + } + + private boolean isValid(int[] nums, int threshold, int p) { + int i = 0, count = 0; + while (i < nums.length - 1) { + if (Math.abs(nums[i] - nums[i + 1]) <= threshold) { + count++; + i += 2; + } else { + i++; + } + if (count == p) return true; + } + return false; + } +} +``` + +```cpp +class Solution { +public: + int minimizeMax(vector& nums, int p) { + if (p == 0) return 0; + + sort(nums.begin(), nums.end()); + int left = 0, right = nums.back() - nums[0]; + int result = right; + + while (left <= right) { + int mid = left + (right - left) / 2; + if (isValid(nums, mid, p)) { + result = mid; + right = mid - 1; + } else { + left = mid + 1; + } + } + + return result; + } + +private: + bool isValid(vector& nums, int threshold, int p) { + int i = 0, count = 0; + while (i < nums.size() - 1) { + if (abs(nums[i] - nums[i + 1]) <= threshold) { + count++; + i += 2; + } else { + i++; + } + if (count == p) return true; + } + return false; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} p + * @return {number} + */ + minimizeMax(nums, p) { + if (p === 0) return 0; + + nums.sort((a, b) => a - b); + let l = 0, r = nums[nums.length - 1] - nums[0], res = r; + + const isValid = (threshold) => { + let i = 0, cnt = 0; + while (i < nums.length - 1) { + if (Math.abs(nums[i] - nums[i + 1]) <= threshold) { + cnt++; + i += 2; + } else { + i++; + } + if (cnt === p) return true; + } + return false; + }; + + while (l <= r) { + let m = Math.floor(l + (r - l) / 2); + if (isValid(m)) { + res = m; + r = m - 1; + } else { + l = m + 1; + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n\log n + n\log m)$ +* Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm. + +> Where $n$ is the size of the input array and $m$ is the maximum value in the array. \ No newline at end of file diff --git a/articles/populating-next-right-pointers-in-each-node.md b/articles/populating-next-right-pointers-in-each-node.md new file mode 100644 index 000000000..1f7339287 --- /dev/null +++ b/articles/populating-next-right-pointers-in-each-node.md @@ -0,0 +1,700 @@ +## 1. Breadth First Search + +::tabs-start + +```python +""" +# Definition for a Node. +class Node: + def __init__(self, val: int = 0, left: 'Node' = None, right: 'Node' = None, next: 'Node' = None): + self.val = val + self.left = left + self.right = right + self.next = next +""" + +class Solution: + def connect(self, root: 'Optional[Node]') -> 'Optional[Node]': + if not root: + return None + + q = deque([root]) + while q: + levelSize = len(q) + while levelSize: + node = q.popleft() + if levelSize > 1: + node.next = q[0] + if node.left: + q.append(node.left) + if node.right: + q.append(node.right) + levelSize -= 1 + + return root +``` + +```java +/* +// Definition for a Node. +class Node { + public int val; + public Node left; + public Node right; + public Node next; + + public Node() {} + + public Node(int _val) { + val = _val; + } + + public Node(int _val, Node _left, Node _right, Node _next) { + val = _val; + left = _left; + right = _right; + next = _next; + } +}; +*/ + +public class Solution { + public Node connect(Node root) { + if (root == null) return null; + + Queue q = new LinkedList<>(); + q.add(root); + + while (!q.isEmpty()) { + int levelSize = q.size(); + while (levelSize > 0) { + Node node = q.poll(); + if (levelSize > 1) { + node.next = q.peek(); + } + if (node.left != null) { + q.add(node.left); + } + if (node.right != null) { + q.add(node.right); + } + levelSize--; + } + } + + return root; + } +} +``` + +```cpp +/* +// Definition for a Node. +class Node { +public: + int val; + Node* left; + Node* right; + Node* next; + + Node() : val(0), left(NULL), right(NULL), next(NULL) {} + + Node(int _val) : val(_val), left(NULL), right(NULL), next(NULL) {} + + Node(int _val, Node* _left, Node* _right, Node* _next) + : val(_val), left(_left), right(_right), next(_next) {} +}; +*/ + +class Solution { +public: + Node* connect(Node* root) { + if (!root) return nullptr; + + queue q; + q.push(root); + + while (!q.empty()) { + int levelSize = q.size(); + while (levelSize > 0) { + Node* node = q.front(); + q.pop(); + if (levelSize > 1) { + node->next = q.front(); + } + if (node->left) { + q.push(node->left); + } + if (node->right) { + q.push(node->right); + } + levelSize--; + } + } + + return root; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null, next = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * this.next = next; + * } + * } + */ + +class Solution { + /** + * @param {Node} root + * @return {Node} + */ + connect(root) { + if (!root) return null; + + const q = new Queue(); + q.push(root); + + while (!q.isEmpty()) { + let levelSize = q.size(); + while (levelSize > 0) { + let node = q.pop(); + if (levelSize > 1) { + node.next = q.front(); + } + if (node.left) { + q.push(node.left); + } + if (node.right) { + q.push(node.right); + } + levelSize--; + } + } + + return root; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(\log n)$ + +--- + +## 2. Depth First Search + +::tabs-start + +```python +""" +# Definition for a Node. +class Node: + def __init__(self, val: int = 0, left: 'Node' = None, right: 'Node' = None, next: 'Node' = None): + self.val = val + self.left = left + self.right = right + self.next = next +""" + +class Solution: + def connect(self, root: 'Optional[Node]') -> 'Optional[Node]': + mp = {} + + def dfs(node, depth): + if not node: + return + + if depth not in mp: + mp[depth] = node + else: + mp[depth].next = node + mp[depth] = node + + dfs(node.left, depth + 1) + dfs(node.right, depth + 1) + + dfs(root, 0) + return root +``` + +```java +/* +// Definition for a Node. +class Node { + public int val; + public Node left; + public Node right; + public Node next; + + public Node() {} + + public Node(int _val) { + val = _val; + } + + public Node(int _val, Node _left, Node _right, Node _next) { + val = _val; + left = _left; + right = _right; + next = _next; + } +}; +*/ + +public class Solution { + public Node connect(Node root) { + Map mp = new HashMap<>(); + dfs(root, 0, mp); + return root; + } + + private void dfs(Node node, int depth, Map mp) { + if (node == null) return; + + if (!mp.containsKey(depth)) { + mp.put(depth, node); + } else { + mp.get(depth).next = node; + mp.put(depth, node); + } + + dfs(node.left, depth + 1, mp); + dfs(node.right, depth + 1, mp); + } +} +``` + +```cpp +/* +// Definition for a Node. +class Node { +public: + int val; + Node* left; + Node* right; + Node* next; + + Node() : val(0), left(NULL), right(NULL), next(NULL) {} + + Node(int _val) : val(_val), left(NULL), right(NULL), next(NULL) {} + + Node(int _val, Node* _left, Node* _right, Node* _next) + : val(_val), left(_left), right(_right), next(_next) {} +}; +*/ + +class Solution { +public: + Node* connect(Node* root) { + unordered_map mp; + dfs(root, 0, mp); + return root; + } + +private: + void dfs(Node* node, int depth, unordered_map& mp) { + if (!node) return; + + if (mp.find(depth) == mp.end()) { + mp[depth] = node; + } else { + mp[depth]->next = node; + mp[depth] = node; + } + + dfs(node->left, depth + 1, mp); + dfs(node->right, depth + 1, mp); + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null, next = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * this.next = next; + * } + * } + */ + +class Solution { + /** + * @param {Node} root + * @return {Node} + */ + connect(root) { + let mp = new Map(); + + const dfs = (node, depth) => { + if (!node) return; + + if (!mp.has(depth)) { + mp.set(depth, node); + } else { + mp.get(depth).next = node; + mp.set(depth, node); + } + + dfs(node.left, depth + 1); + dfs(node.right, depth + 1); + }; + + dfs(root, 0); + return root; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(\log n)$ + +--- + +## 3. Depth First Search (Optimal) + +::tabs-start + +```python +""" +# Definition for a Node. +class Node: + def __init__(self, val: int = 0, left: 'Node' = None, right: 'Node' = None, next: 'Node' = None): + self.val = val + self.left = left + self.right = right + self.next = next +""" + +class Solution: + def connect(self, root: 'Optional[Node]') -> 'Optional[Node]': + if not root: + return root + + if root.left: + root.left.next = root.right + if root.next: + root.right.next = root.next.left + + self.connect(root.left) + self.connect(root.right) + + return root +``` + +```java +/* +// Definition for a Node. +class Node { + public int val; + public Node left; + public Node right; + public Node next; + + public Node() {} + + public Node(int _val) { + val = _val; + } + + public Node(int _val, Node _left, Node _right, Node _next) { + val = _val; + left = _left; + right = _right; + next = _next; + } +}; +*/ + +public class Solution { + public Node connect(Node root) { + if (root == null) return root; + + if (root.left != null) { + root.left.next = root.right; + if (root.next != null) { + root.right.next = root.next.left; + } + + connect(root.left); + connect(root.right); + } + + return root; + } +} +``` + +```cpp +/* +// Definition for a Node. +class Node { +public: + int val; + Node* left; + Node* right; + Node* next; + + Node() : val(0), left(NULL), right(NULL), next(NULL) {} + + Node(int _val) : val(_val), left(NULL), right(NULL), next(NULL) {} + + Node(int _val, Node* _left, Node* _right, Node* _next) + : val(_val), left(_left), right(_right), next(_next) {} +}; +*/ + +class Solution { +public: + Node* connect(Node* root) { + if (!root) return root; + + if (root->left) { + root->left->next = root->right; + if (root->next) { + root->right->next = root->next->left; + } + + connect(root->left); + connect(root->right); + } + + return root; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null, next = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * this.next = next; + * } + * } + */ + +class Solution { + /** + * @param {Node} root + * @return {Node} + */ + connect(root) { + if (!root) return root; + + if (root.left) { + root.left.next = root.right; + if (root.next) { + root.right.next = root.next.left; + } + + this.connect(root.left); + this.connect(root.right); + } + + return root; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(\log n)$ for the recursion stack. + +--- + +## 4. Breadth First Search (Optimal) + +::tabs-start + +```python +""" +# Definition for a Node. +class Node: + def __init__(self, val: int = 0, left: 'Node' = None, right: 'Node' = None, next: 'Node' = None): + self.val = val + self.left = left + self.right = right + self.next = next +""" + +class Solution: + def connect(self, root: 'Optional[Node]') -> 'Optional[Node]': + cur, nxt = root, root.left if root else None + + while cur and nxt: + cur.left.next = cur.right + if cur.next: + cur.right.next = cur.next.left + + cur = cur.next + if not cur: + cur = nxt + nxt = cur.left + + return root +``` + +```java +/* +// Definition for a Node. +class Node { + public int val; + public Node left; + public Node right; + public Node next; + + public Node() {} + + public Node(int _val) { + val = _val; + } + + public Node(int _val, Node _left, Node _right, Node _next) { + val = _val; + left = _left; + right = _right; + next = _next; + } +}; +*/ + +public class Solution { + public Node connect(Node root) { + if (root == null) return null; + + Node cur = root, nxt = root.left; + + while (cur != null && nxt != null) { + cur.left.next = cur.right; + if (cur.next != null) { + cur.right.next = cur.next.left; + } + + cur = cur.next; + if (cur == null) { + cur = nxt; + nxt = cur.left; + } + } + + return root; + } +} +``` + +```cpp +/* +// Definition for a Node. +class Node { +public: + int val; + Node* left; + Node* right; + Node* next; + + Node() : val(0), left(NULL), right(NULL), next(NULL) {} + + Node(int _val) : val(_val), left(NULL), right(NULL), next(NULL) {} + + Node(int _val, Node* _left, Node* _right, Node* _next) + : val(_val), left(_left), right(_right), next(_next) {} +}; +*/ + +class Solution { +public: + Node* connect(Node* root) { + if (!root) return nullptr; + + Node* cur = root, *nxt = root->left; + + while (cur && nxt) { + cur->left->next = cur->right; + if (cur->next) { + cur->right->next = cur->next->left; + } + + cur = cur->next; + if (!cur) { + cur = nxt; + nxt = cur->left; + } + } + + return root; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null, next = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * this.next = next; + * } + * } + */ + +class Solution { + /** + * @param {Node} root + * @return {Node} + */ + connect(root) { + if (!root) return null; + + let cur = root, nxt = root.left; + + while (cur && nxt) { + cur.left.next = cur.right; + if (cur.next) { + cur.right.next = cur.next.left; + } + + cur = cur.next; + if (!cur) { + cur = nxt; + nxt = cur.left; + } + } + + return root; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(1)$ \ No newline at end of file diff --git a/articles/search-suggestions-system.md b/articles/search-suggestions-system.md new file mode 100644 index 000000000..87325be56 --- /dev/null +++ b/articles/search-suggestions-system.md @@ -0,0 +1,589 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def suggestedProducts(self, products: List[str], searchWord: str) -> List[List[str]]: + res = [] + m = len(searchWord) + products.sort() + + for i in range(m): + cur = [] + for w in products: + if len(w) <= i: + continue + + flag = True + for j in range(i + 1): + if w[j] != searchWord[j]: + flag = False + break + + if flag: + cur.append(w) + if len(cur) == 3: + break + + if not cur: + for j in range(i, m): + res.append([]) + break + res.append(cur) + + return res +``` + +```java +public class Solution { + public List> suggestedProducts(String[] products, String searchWord) { + List> res = new ArrayList<>(); + int m = searchWord.length(); + Arrays.sort(products); + + for (int i = 0; i < m; i++) { + List cur = new ArrayList<>(); + for (String w : products) { + if (w.length() <= i) continue; + + boolean flag = true; + for (int j = 0; j <= i; j++) { + if (w.charAt(j) != searchWord.charAt(j)) { + flag = false; + break; + } + } + + if (flag) { + cur.add(w); + if (cur.size() == 3) break; + } + } + + if (cur.isEmpty()) { + while (i < m) { + res.add(new ArrayList<>()); + i++; + } + break; + } + + res.add(cur); + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + vector> suggestedProducts(vector& products, string searchWord) { + vector> res; + int m = searchWord.size(); + sort(products.begin(), products.end()); + + for (int i = 0; i < m; i++) { + vector cur; + for (const string& w : products) { + if (w.size() <= i) continue; + + bool flag = true; + for (int j = 0; j <= i; j++) { + if (w[j] != searchWord[j]) { + flag = false; + break; + } + } + + if (flag) { + cur.push_back(w); + if (cur.size() == 3) break; + } + } + + if (cur.empty()) { + while (i < m) { + res.push_back({}); + i++; + } + break; + } + + res.push_back(cur); + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} products + * @param {string} searchWord + * @return {string[][]} + */ + suggestedProducts(products, searchWord) { + let res = []; + let m = searchWord.length; + products.sort(); + + for (let i = 0; i < m; i++) { + let cur = []; + for (let w of products) { + if (w.length <= i) continue; + + let flag = true; + for (let j = 0; j <= i; j++) { + if (w[j] !== searchWord[j]) { + flag = false; + break; + } + } + + if (flag) { + cur.push(w); + if (cur.length === 3) break; + } + } + + if (cur.length === 0) { + while (i < m) { + res.push([]); + i++; + } + break; + } + + res.push(cur); + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n \log n + m * n)$ +* Space complexity: + * $O(n)$ or $O(1)$ space for the sorting algorithm. + * $O(m * w)$ space for the output array. + +> Where $n$ is the total number of characters in the string array $products$, $m$ is the length of the string $searchWord$, and $w$ is the average length of each word in the given string array. + +--- + +## 2. Sorting + Binary Search + +::tabs-start + +```python +class Solution: + def suggestedProducts(self, products: List[str], searchWord: str) -> List[List[str]]: + res = [] + m = len(searchWord) + products.sort() + + prefix = [] + start = 0 + + def binary_search(target, start): + l, r = start, len(products) + while l < r: + mid = l + (r - l) // 2 + if products[mid] >= target: + r = mid + else: + l = mid + 1 + return l + + for i in range(m): + prefix.append(searchWord[i]) + start = binary_search("".join(prefix), start) + + cur = [] + for j in range(start, min(start + 3, len(products))): + if products[j].startswith("".join(prefix)): + cur.append(products[j]) + else: + break + + res.append(cur) + + return res +``` + +```java +public class Solution { + public List> suggestedProducts(String[] products, String searchWord) { + List> res = new ArrayList<>(); + int m = searchWord.length(); + Arrays.sort(products); + + StringBuilder prefix = new StringBuilder(); + int start = 0; + + for (int i = 0; i < m; i++) { + prefix.append(searchWord.charAt(i)); + start = binarySearch(products, prefix.toString(), start); + + List cur = new ArrayList<>(); + for (int j = start; j < Math.min(start + 3, products.length); j++) { + if (products[j].startsWith(prefix.toString())) { + cur.add(products[j]); + } else { + break; + } + } + + res.add(cur); + } + + return res; + } + + private int binarySearch(String[] products, String target, int start) { + int l = start, r = products.length; + while (l < r) { + int mid = l + (r - l) / 2; + if (products[mid].compareTo(target) >= 0) { + r = mid; + } else { + l = mid + 1; + } + } + return l; + } +} +``` + +```cpp +class Solution { +public: + vector> suggestedProducts(vector& products, string searchWord) { + vector> res; + int m = searchWord.size(); + sort(products.begin(), products.end()); + + string prefix = ""; + int start = 0; + + for (int i = 0; i < m; i++) { + prefix += searchWord[i]; + start = binarySearch(products, prefix, start); + + vector cur; + for (int j = start; j < min(start + 3, (int)products.size()); j++) { + if (products[j].substr(0, prefix.size()) == prefix) { + cur.push_back(products[j]); + } else { + break; + } + } + + res.push_back(cur); + } + + return res; + } + +private: + int binarySearch(vector& products, string target, int start) { + int l = start, r = products.size(); + while (l < r) { + int mid = l + (r - l) / 2; + if (products[mid] >= target) { + r = mid; + } else { + l = mid + 1; + } + } + return l; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} products + * @param {string} searchWord + * @return {string[][]} + */ + suggestedProducts(products, searchWord) { + let res = []; + let m = searchWord.length; + products.sort(); + + let prefix = []; + let start = 0; + + for (let i = 0; i < m; i++) { + prefix.push(searchWord[i]); + start = this.binarySearch(products, prefix.join(""), start); + + let cur = []; + for (let j = start; j < Math.min(start + 3, products.length); j++) { + if (products[j].startsWith(prefix.join(""))) { + cur.push(products[j]); + } else { + break; + } + } + + res.push(cur); + } + + return res; + } + + /** + * @param {string[]} products + * @param {string} target + * @param {number} start + * @return {number} + */ + binarySearch(products, target, start) { + let l = start, r = products.length; + while (l < r) { + let mid = Math.floor(l + (r - l) / 2); + if (products[mid] >= target) { + r = mid; + } else { + l = mid + 1; + } + } + return l; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n \log n + m * w * \log N)$ +* Space complexity: + * $O(n)$ or $O(1)$ space for the sorting algorithm. + * $O(m * w)$ space for the output array. + +> Where $n$ is the total number of characters in the string array $products$, $N$ is the size of the array $products$, $m$ is the length of the string $searchWord$, and $w$ is the average length of each word in the given string array. + +--- + +## 3. Sorting + Binary Search (Built-In Function) + +::tabs-start + +```python +class Solution: + def suggestedProducts(self, products: List[str], searchWord: str) -> List[List[str]]: + res = [] + m = len(searchWord) + products.sort() + + prefix = "" + start = 0 + for i in range(m): + prefix += searchWord[i] + start = bisect_left(products, prefix, start) + + cur = [] + for j in range(start, min(start + 3, len(products))): + if products[j].startswith(prefix): + cur.append(products[j]) + else: + break + + res.append(cur) + + return res +``` + +```cpp +class Solution { +public: + vector> suggestedProducts(vector& products, string searchWord) { + vector> res; + int m = searchWord.size(); + sort(products.begin(), products.end()); + + string prefix = ""; + int start = 0; + for (int i = 0; i < m; i++) { + prefix += searchWord[i]; + start = lower_bound(products.begin() + start, products.end(), prefix) - products.begin(); + + vector cur; + for (int j = start; j < min(start + 3, (int)products.size()); j++) { + if (products[j].find(prefix) == 0) { + cur.push_back(products[j]); + } else { + break; + } + } + + res.push_back(cur); + } + + return res; + } +}; +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n \log n + m * w * \log N)$ +* Space complexity: + * $O(n)$ or $O(1)$ space for the sorting algorithm. + * $O(m * w)$ space for the output array. + +> Where $n$ is the total number of characters in the string array $products$, $N$ is the size of the array $products$, $m$ is the length of the string $searchWord$, and $w$ is the average length of each word in the given string array. + +--- + +## 4. Sorting + Two Pointers + +::tabs-start + +```python +class Solution: + def suggestedProducts(self, products: List[str], searchWord: str) -> List[List[str]]: + res = [] + products.sort() + + l, r = 0, len(products) - 1 + for i in range(len(searchWord)): + c = searchWord[i] + + while l <= r and (len(products[l]) <= i or products[l][i] != c): + l += 1 + while l <= r and (len(products[r]) <= i or products[r][i] != c): + r -= 1 + + res.append([]) + remain = r - l + 1 + for j in range(min(3, remain)): + res[-1].append(products[l + j]) + + return res +``` + +```java +public class Solution { + public List> suggestedProducts(String[] products, String searchWord) { + List> res = new ArrayList<>(); + Arrays.sort(products); + + int l = 0, r = products.length - 1; + for (int i = 0; i < searchWord.length(); i++) { + char c = searchWord.charAt(i); + + while (l <= r && (products[l].length() <= i || products[l].charAt(i) != c)) { + l++; + } + while (l <= r && (products[r].length() <= i || products[r].charAt(i) != c)) { + r--; + } + + List cur = new ArrayList<>(); + int remain = r - l + 1; + for (int j = 0; j < Math.min(3, remain); j++) { + cur.add(products[l + j]); + } + + res.add(cur); + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + vector> suggestedProducts(vector& products, string searchWord) { + vector> res; + sort(products.begin(), products.end()); + + int l = 0, r = products.size() - 1; + for (int i = 0; i < searchWord.size(); i++) { + char c = searchWord[i]; + + while (l <= r && (products[l].size() <= i || products[l][i] != c)) { + l++; + } + while (l <= r && (products[r].size() <= i || products[r][i] != c)) { + r--; + } + + vector cur; + int remain = r - l + 1; + for (int j = 0; j < min(3, remain); j++) { + cur.push_back(products[l + j]); + } + + res.push_back(cur); + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} products + * @param {string} searchWord + * @return {string[][]} + */ + suggestedProducts(products, searchWord) { + let res = []; + products.sort(); + + let l = 0, r = products.length - 1; + for (let i = 0; i < searchWord.length; i++) { + let c = searchWord[i]; + + while (l <= r && (products[l].length <= i || products[l][i] !== c)) { + l++; + } + while (l <= r && (products[r].length <= i || products[r][i] !== c)) { + r--; + } + + let cur = []; + let remain = r - l + 1; + for (let j = 0; j < Math.min(3, remain); j++) { + cur.push(products[l + j]); + } + + res.push(cur); + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n \log n + m * w + N)$ +* Space complexity: + * $O(n)$ or $O(1)$ space for the sorting algorithm. + * $O(m * w)$ space for the output array. + +> Where $n$ is the total number of characters in the string array $products$, $N$ is the size of the array $products$, $m$ is the length of the string $searchWord$, and $w$ is the average length of each word in the given string array. \ No newline at end of file From 0343c8044585451b45b2ce3c38571351fd7d5998 Mon Sep 17 00:00:00 2001 From: Sri Hari Date: Wed, 29 Jan 2025 22:52:12 +0530 Subject: [PATCH 4/7] Batch-5/Neetcode-ALL/Added-articles --- articles/maximum-twin-sum-of-a-linked-list.md | 450 ++++++++++ articles/partition-list.md | 324 ++++++++ articles/sort-list.md | 730 ++++++++++++++++ articles/swap-nodes-in-pairs.md | 419 ++++++++++ articles/swapping-nodes-in-a-linked-list.md | 785 ++++++++++++++++++ 5 files changed, 2708 insertions(+) create mode 100644 articles/maximum-twin-sum-of-a-linked-list.md create mode 100644 articles/partition-list.md create mode 100644 articles/sort-list.md create mode 100644 articles/swap-nodes-in-pairs.md create mode 100644 articles/swapping-nodes-in-a-linked-list.md diff --git a/articles/maximum-twin-sum-of-a-linked-list.md b/articles/maximum-twin-sum-of-a-linked-list.md new file mode 100644 index 000000000..b896b8cae --- /dev/null +++ b/articles/maximum-twin-sum-of-a-linked-list.md @@ -0,0 +1,450 @@ +## 1. Convert To Array + +::tabs-start + +```python +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, val=0, next=None): +# self.val = val +# self.next = next +class Solution: + def pairSum(self, head: Optional[ListNode]) -> int: + arr = [] + cur = head + while cur: + arr.append(cur.val) + cur = cur.next + + i, j = 0, len(arr) - 1 + res = 0 + while i < j: + res = max(res, arr[i] + arr[j]) + i, j = i + 1, j - 1 + + return res +``` + +```java +/** + * Definition for singly-linked list. + * public class ListNode { + * int val; + * ListNode next; + * ListNode() {} + * ListNode(int val) { this.val = val; } + * ListNode(int val, ListNode next) { this.val = val; this.next = next; } + * } + */ +public class Solution { + public int pairSum(ListNode head) { + List arr = new ArrayList<>(); + ListNode cur = head; + + while (cur != null) { + arr.add(cur.val); + cur = cur.next; + } + + int i = 0, j = arr.size() - 1, res = 0; + while (i < j) { + res = Math.max(res, arr.get(i) + arr.get(j)); + i++; + j--; + } + + return res; + } +} +``` + +```cpp +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode() : val(0), next(nullptr) {} + * ListNode(int x) : val(x), next(nullptr) {} + * ListNode(int x, ListNode *next) : val(x), next(next) {} + * }; + */ +class Solution { +public: + int pairSum(ListNode* head) { + vector arr; + ListNode* cur = head; + + while (cur) { + arr.push_back(cur->val); + cur = cur->next; + } + + int i = 0, j = arr.size() - 1, res = 0; + while (i < j) { + res = max(res, arr[i] + arr[j]); + i++; + j--; + } + + return res; + } +}; +``` + +```javascript +/** + * Definition for singly-linked list. + * class ListNode { + * constructor(val = 0, next = null) { + * this.val = val; + * this.next = next; + * } + * } + */ +class Solution { + /** + * @param {ListNode} head + * @return {number} + */ + pairSum(head) { + let arr = []; + let cur = head; + + while (cur) { + arr.push(cur.val); + cur = cur.next; + } + + let i = 0, j = arr.length - 1, res = 0; + while (i < j) { + res = Math.max(res, arr[i] + arr[j]); + i++; + j--; + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ + +--- + +## 2. Reverse the Second Half + +::tabs-start + +```python +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, val=0, next=None): +# self.val = val +# self.next = next +class Solution: + def pairSum(self, head: Optional[ListNode]) -> int: + slow, fast = head, head + while fast and fast.next: + slow = slow.next + fast = fast.next.next + + prev, cur = None, slow + while cur: + nxt = cur.next + cur.next = prev + prev = cur + cur = nxt + + res = 0 + first, second = head, prev + while second: + res = max(res, first.val + second.val) + first, second = first.next, second.next + + return res +``` + +```java +/** + * Definition for singly-linked list. + * public class ListNode { + * int val; + * ListNode next; + * ListNode() {} + * ListNode(int val) { this.val = val; } + * ListNode(int val, ListNode next) { this.val = val; this.next = next; } + * } + */ +public class Solution { + public int pairSum(ListNode head) { + ListNode slow = head, fast = head; + while (fast != null && fast.next != null) { + slow = slow.next; + fast = fast.next.next; + } + + ListNode prev = null, cur = slow; + while (cur != null) { + ListNode nxt = cur.next; + cur.next = prev; + prev = cur; + cur = nxt; + } + + int res = 0; + ListNode first = head, second = prev; + while (second != null) { + res = Math.max(res, first.val + second.val); + first = first.next; + second = second.next; + } + + return res; + } +} +``` + +```cpp +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode() : val(0), next(nullptr) {} + * ListNode(int x) : val(x), next(nullptr) {} + * ListNode(int x, ListNode *next) : val(x), next(next) {} + * }; + */ +class Solution { +public: + int pairSum(ListNode* head) { + ListNode* slow = head, *fast = head; + while (fast && fast->next) { + slow = slow->next; + fast = fast->next->next; + } + + ListNode* prev = nullptr, *cur = slow; + while (cur) { + ListNode* nxt = cur->next; + cur->next = prev; + prev = cur; + cur = nxt; + } + + int res = 0; + ListNode* first = head, *second = prev; + while (second) { + res = max(res, first->val + second->val); + first = first->next; + second = second->next; + } + + return res; + } +}; +``` + +```javascript +/** + * Definition for singly-linked list. + * class ListNode { + * constructor(val = 0, next = null) { + * this.val = val; + * this.next = next; + * } + * } + */ +class Solution { + /** + * @param {ListNode} head + * @return {number} + */ + pairSum(head) { + let slow = head, fast = head; + while (fast && fast.next) { + slow = slow.next; + fast = fast.next.next; + } + + let prev = null, cur = slow; + while (cur) { + let nxt = cur.next; + cur.next = prev; + prev = cur; + cur = nxt; + } + + let res = 0, first = head, second = prev; + while (second) { + res = Math.max(res, first.val + second.val); + first = first.next; + second = second.next; + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(1)$ extra space. + +--- + +## 3. Reverse the First Half + +::tabs-start + +```python +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, val=0, next=None): +# self.val = val +# self.next = next +class Solution: + def pairSum(self, head: Optional[ListNode]) -> int: + slow, fast = head, head + prev = None + + while fast and fast.next: + fast = fast.next.next + tmp = slow.next + slow.next = prev + prev = slow + slow = tmp + + res = 0 + while slow: + res = max(res, prev.val + slow.val) + prev = prev.next + slow = slow.next + + return res +``` + +```java +/** + * Definition for singly-linked list. + * public class ListNode { + * int val; + * ListNode next; + * ListNode() {} + * ListNode(int val) { this.val = val; } + * ListNode(int val, ListNode next) { this.val = val; this.next = next; } + * } + */ +public class Solution { + public int pairSum(ListNode head) { + ListNode slow = head, fast = head, prev = null; + + while (fast != null && fast.next != null) { + fast = fast.next.next; + ListNode tmp = slow.next; + slow.next = prev; + prev = slow; + slow = tmp; + } + + int res = 0; + while (slow != null) { + res = Math.max(res, prev.val + slow.val); + prev = prev.next; + slow = slow.next; + } + + return res; + } +} +``` + +```cpp +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode() : val(0), next(nullptr) {} + * ListNode(int x) : val(x), next(nullptr) {} + * ListNode(int x, ListNode *next) : val(x), next(next) {} + * }; + */ +class Solution { +public: + int pairSum(ListNode* head) { + ListNode* slow = head, *fast = head, *prev = nullptr; + + while (fast && fast->next) { + fast = fast->next->next; + ListNode* tmp = slow->next; + slow->next = prev; + prev = slow; + slow = tmp; + } + + int res = 0; + while (slow) { + res = max(res, prev->val + slow->val); + prev = prev->next; + slow = slow->next; + } + + return res; + } +}; +``` + +```javascript +/** + * Definition for singly-linked list. + * class ListNode { + * constructor(val = 0, next = null) { + * this.val = val; + * this.next = next; + * } + * } + */ +class Solution { + /** + * @param {ListNode} head + * @return {number} + */ + pairSum(head) { + let slow = head, fast = head, prev = null; + + while (fast && fast.next) { + fast = fast.next.next; + let tmp = slow.next; + slow.next = prev; + prev = slow; + slow = tmp; + } + + let res = 0; + while (slow) { + res = Math.max(res, prev.val + slow.val); + prev = prev.next; + slow = slow.next; + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(1)$ extra space. \ No newline at end of file diff --git a/articles/partition-list.md b/articles/partition-list.md new file mode 100644 index 000000000..d3e69dd52 --- /dev/null +++ b/articles/partition-list.md @@ -0,0 +1,324 @@ +## 1. Brute Force + +::tabs-start + +```python +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, val=0, next=None): +# self.val = val +# self.next = next +class Solution: + def partition(self, head: Optional[ListNode], x: int) -> Optional[ListNode]: + if not head: + return None + + less, greater = [], [] + cur = head + while cur: + if cur.val < x: + less.append(cur.val) + else: + greater.append(cur.val) + cur = cur.next + + cur = head + for val in less: + cur.val = val + cur = cur.next + + for val in greater: + cur.val = val + cur = cur.next + + return head +``` + +```java +/** + * Definition for singly-linked list. + * public class ListNode { + * int val; + * ListNode next; + * ListNode() {} + * ListNode(int val) { this.val = val; } + * ListNode(int val, ListNode next) { this.val = val; this.next = next; } + * } + */ +public class Solution { + public ListNode partition(ListNode head, int x) { + if (head == null) { + return null; + } + + List less = new ArrayList<>(); + List greater = new ArrayList<>(); + ListNode cur = head; + + while (cur != null) { + if (cur.val < x) { + less.add(cur.val); + } else { + greater.add(cur.val); + } + cur = cur.next; + } + + cur = head; + for (int val : less) { + cur.val = val; + cur = cur.next; + } + + for (int val : greater) { + cur.val = val; + cur = cur.next; + } + + return head; + } +} +``` + +```cpp +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode() : val(0), next(nullptr) {} + * ListNode(int x) : val(x), next(nullptr) {} + * ListNode(int x, ListNode *next) : val(x), next(next) {} + * }; + */ +class Solution { +public: + ListNode* partition(ListNode* head, int x) { + if (!head) return nullptr; + + vector less, greater; + ListNode* cur = head; + + while (cur) { + if (cur->val < x) { + less.push_back(cur->val); + } else { + greater.push_back(cur->val); + } + cur = cur->next; + } + + cur = head; + for (int val : less) { + cur->val = val; + cur = cur->next; + } + + for (int val : greater) { + cur->val = val; + cur = cur->next; + } + + return head; + } +}; +``` + +```javascript +/** + * Definition for singly-linked list. + * class ListNode { + * constructor(val = 0, next = null) { + * this.val = val; + * this.next = next; + * } + * } + */ +class Solution { + /** + * @param {ListNode} head + * @param {number} x + * @return {ListNode} + */ + partition(head, x) { + if (!head) return null; + + let less = [], greater = []; + let cur = head; + + while (cur) { + if (cur.val < x) { + less.push(cur.val); + } else { + greater.push(cur.val); + } + cur = cur.next; + } + + cur = head; + for (let val of less) { + cur.val = val; + cur = cur.next; + } + + for (let val of greater) { + cur.val = val; + cur = cur.next; + } + + return head; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ + +--- + +## 2. Two Pointers + +::tabs-start + +```python +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, val=0, next=None): +# self.val = val +# self.next = next +class Solution: + def partition(self, head: Optional[ListNode], x: int) -> Optional[ListNode]: + left, right = ListNode(), ListNode() + ltail, rtail = left, right + + while head: + if head.val < x: + ltail.next = head + ltail = ltail.next + else: + rtail.next = head + rtail = rtail.next + head = head.next + + ltail.next = right.next + rtail.next = None + return left.next +``` + +```java +/** + * Definition for singly-linked list. + * public class ListNode { + * int val; + * ListNode next; + * ListNode() {} + * ListNode(int val) { this.val = val; } + * ListNode(int val, ListNode next) { this.val = val; this.next = next; } + * } + */ +public class Solution { + public ListNode partition(ListNode head, int x) { + ListNode left = new ListNode(0), right = new ListNode(0); + ListNode ltail = left, rtail = right; + + while (head != null) { + if (head.val < x) { + ltail.next = head; + ltail = ltail.next; + } else { + rtail.next = head; + rtail = rtail.next; + } + head = head.next; + } + + ltail.next = right.next; + rtail.next = null; + return left.next; + } +} +``` + +```cpp +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode() : val(0), next(nullptr) {} + * ListNode(int x) : val(x), next(nullptr) {} + * ListNode(int x, ListNode *next) : val(x), next(next) {} + * }; + */ +class Solution { +public: + ListNode* partition(ListNode* head, int x) { + ListNode leftDummy(0), rightDummy(0); + ListNode *ltail = &leftDummy, *rtail = &rightDummy; + + while (head) { + if (head->val < x) { + ltail->next = head; + ltail = ltail->next; + } else { + rtail->next = head; + rtail = rtail->next; + } + head = head->next; + } + + ltail->next = rightDummy.next; + rtail->next = nullptr; + return leftDummy.next; + } +}; +``` + +```javascript +/** + * Definition for singly-linked list. + * class ListNode { + * constructor(val = 0, next = null) { + * this.val = val; + * this.next = next; + * } + * } + */ +class Solution { + /** + * @param {ListNode} head + * @param {number} x + * @return {ListNode} + */ + partition(head, x) { + let left = new ListNode(0), right = new ListNode(0); + let ltail = left, rtail = right; + + while (head) { + if (head.val < x) { + ltail.next = head; + ltail = ltail.next; + } else { + rtail.next = head; + rtail = rtail.next; + } + head = head.next; + } + + ltail.next = right.next; + rtail.next = null; + return left.next; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(1)$ \ No newline at end of file diff --git a/articles/sort-list.md b/articles/sort-list.md new file mode 100644 index 000000000..768ec1c4c --- /dev/null +++ b/articles/sort-list.md @@ -0,0 +1,730 @@ +## 1. Convert To Array + +::tabs-start + +```python +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, val=0, next=None): +# self.val = val +# self.next = next +class Solution: + def sortList(self, head: Optional[ListNode]) -> Optional[ListNode]: + arr = [] + cur = head + + while cur: + arr.append(cur.val) + cur = cur.next + + arr.sort() + cur = head + for val in arr: + cur.val = val + cur = cur.next + + return head +``` + +```java +/** + * Definition for singly-linked list. + * public class ListNode { + * int val; + * ListNode next; + * ListNode() {} + * ListNode(int val) { this.val = val; } + * ListNode(int val, ListNode next) { this.val = val; this.next = next; } + * } + */ +public class Solution { + public ListNode sortList(ListNode head) { + if (head == null) return null; + + List arr = new ArrayList<>(); + ListNode cur = head; + + while (cur != null) { + arr.add(cur.val); + cur = cur.next; + } + + Collections.sort(arr); + cur = head; + for (int val : arr) { + cur.val = val; + cur = cur.next; + } + + return head; + } +} +``` + +```cpp +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode() : val(0), next(nullptr) {} + * ListNode(int x) : val(x), next(nullptr) {} + * ListNode(int x, ListNode *next) : val(x), next(next) {} + * }; + */ +class Solution { +public: + ListNode* sortList(ListNode* head) { + if (!head) return nullptr; + + vector arr; + ListNode* cur = head; + + while (cur) { + arr.push_back(cur->val); + cur = cur->next; + } + + sort(arr.begin(), arr.end()); + cur = head; + for (int val : arr) { + cur->val = val; + cur = cur->next; + } + + return head; + } +}; +``` + +```javascript +/** + * Definition for singly-linked list. + * class ListNode { + * constructor(val = 0, next = null) { + * this.val = val; + * this.next = next; + * } + * } + */ +class Solution { + /** + * @param {ListNode} head + * @return {ListNode} + */ + sortList(head) { + if (!head) return null; + + let arr = []; + let cur = head; + + while (cur) { + arr.push(cur.val); + cur = cur.next; + } + + arr.sort((a, b) => a - b); + cur = head; + for (let val of arr) { + cur.val = val; + cur = cur.next; + } + + return head; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n \log n)$ +* Space complexity: $O(n)$ + +--- + +## 2. Recursive Merge Sort + +::tabs-start + +```python +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, val=0, next=None): +# self.val = val +# self.next = next +class Solution: + def sortList(self, head: Optional[ListNode]) -> Optional[ListNode]: + if not head or not head.next: + return head + + left = head + right = self.getMid(head) + tmp = right.next + right.next = None + right = tmp + + left = self.sortList(left) + right = self.sortList(right) + return self.merge(left, right) + + def getMid(self, head): + slow, fast = head, head.next + while fast and fast.next: + slow = slow.next + fast = fast.next.next + return slow + + def merge(self, list1, list2): + tail = dummy = ListNode() + while list1 and list2: + if list1.val < list2.val: + tail.next = list1 + list1 = list1.next + else: + tail.next = list2 + list2 = list2.next + tail = tail.next + + if list1: + tail.next = list1 + if list2: + tail.next = list2 + + return dummy.next +``` + +```java +/** + * Definition for singly-linked list. + * public class ListNode { + * int val; + * ListNode next; + * ListNode() {} + * ListNode(int val) { this.val = val; } + * ListNode(int val, ListNode next) { this.val = val; this.next = next; } + * } + */ +public class Solution { + public ListNode sortList(ListNode head) { + if (head == null || head.next == null) { + return head; + } + + ListNode left = head; + ListNode right = getMid(head); + ListNode temp = right.next; + right.next = null; + right = temp; + + left = sortList(left); + right = sortList(right); + return merge(left, right); + } + + private ListNode getMid(ListNode head) { + ListNode slow = head, fast = head.next; + while (fast != null && fast.next != null) { + slow = slow.next; + fast = fast.next.next; + } + return slow; + } + + private ListNode merge(ListNode list1, ListNode list2) { + ListNode dummy = new ListNode(0); + ListNode tail = dummy; + + while (list1 != null && list2 != null) { + if (list1.val < list2.val) { + tail.next = list1; + list1 = list1.next; + } else { + tail.next = list2; + list2 = list2.next; + } + tail = tail.next; + } + + if (list1 != null) { + tail.next = list1; + } + if (list2 != null) { + tail.next = list2; + } + + return dummy.next; + } +} +``` + +```cpp +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode() : val(0), next(nullptr) {} + * ListNode(int x) : val(x), next(nullptr) {} + * ListNode(int x, ListNode *next) : val(x), next(next) {} + * }; + */ +class Solution { +public: + ListNode* sortList(ListNode* head) { + if (!head || !head->next) { + return head; + } + + ListNode* left = head; + ListNode* right = getMid(head); + ListNode* temp = right->next; + right->next = nullptr; + right = temp; + + left = sortList(left); + right = sortList(right); + return merge(left, right); + } + +private: + ListNode* getMid(ListNode* head) { + ListNode* slow = head; + ListNode* fast = head->next; + while (fast && fast->next) { + slow = slow->next; + fast = fast->next->next; + } + return slow; + } + + ListNode* merge(ListNode* list1, ListNode* list2) { + ListNode dummy(0); + ListNode* tail = &dummy; + + while (list1 && list2) { + if (list1->val < list2->val) { + tail->next = list1; + list1 = list1->next; + } else { + tail->next = list2; + list2 = list2->next; + } + tail = tail->next; + } + + if (list1) { + tail->next = list1; + } + if (list2) { + tail->next = list2; + } + + return dummy.next; + } +}; +``` + +```javascript +/** + * Definition for singly-linked list. + * class ListNode { + * constructor(val = 0, next = null) { + * this.val = val; + * this.next = next; + * } + * } + */ +class Solution { + /** + * @param {ListNode} head + * @return {ListNode} + */ + sortList(head) { + if (!head || !head.next) { + return head; + } + + let left = head; + let right = this.getMid(head); + let temp = right.next; + right.next = null; + right = temp; + + left = this.sortList(left); + right = this.sortList(right); + return this.merge(left, right); + } + + /** + * @param {ListNode} head + * @return {ListNode} + */ + getMid(head) { + let slow = head, fast = head.next; + while (fast && fast.next) { + slow = slow.next; + fast = fast.next.next; + } + return slow; + } + + /** + * @param {ListNode} list1 + * @param {ListNode} list2 + * @return {ListNode} + */ + merge(list1, list2) { + let dummy = new ListNode(0); + let tail = dummy; + + while (list1 && list2) { + if (list1.val < list2.val) { + tail.next = list1; + list1 = list1.next; + } else { + tail.next = list2; + list2 = list2.next; + } + tail = tail.next; + } + + if (list1) { + tail.next = list1; + } + if (list2) { + tail.next = list2; + } + + return dummy.next; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n \log n)$ +* Space complexity: $O(\log n)$ for recursion stack. + +--- + +## 3. Iterative Merge Sort + +::tabs-start + +```python +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, val=0, next=None): +# self.val = val +# self.next = next +class Solution: + def sortList(self, head: Optional[ListNode]) -> Optional[ListNode]: + if not head or not head.next: + return head + + length = 0 + cur = head + while cur: + length += 1 + cur = cur.next + + dummy = ListNode(0) + dummy.next = head + step = 1 + + while step < length: + prev, curr = dummy, dummy.next + while curr: + left = curr + right = self.split(left, step) + curr = self.split(right, step) + merged = self.merge(left, right) + prev.next = merged + while prev.next: + prev = prev.next + step *= 2 + + return dummy.next + + def split(self, head, step): + if not head: + return None + for _ in range(step - 1): + if not head.next: + break + head = head.next + next_part = head.next + head.next = None + return next_part + + def merge(self, list1, list2): + tail = dummy = ListNode(0) + while list1 and list2: + if list1.val < list2.val: + tail.next = list1 + list1 = list1.next + else: + tail.next = list2 + list2 = list2.next + tail = tail.next + + tail.next = list1 or list2 + return dummy.next +``` + +```java +/** + * Definition for singly-linked list. + * public class ListNode { + * int val; + * ListNode next; + * ListNode() {} + * ListNode(int val) { this.val = val; } + * ListNode(int val, ListNode next) { this.val = val; this.next = next; } + * } + */ +public class Solution { + public ListNode sortList(ListNode head) { + if (head == null || head.next == null) { + return head; + } + + int length = 0; + ListNode cur = head; + while (cur != null) { + length++; + cur = cur.next; + } + + ListNode dummy = new ListNode(0); + dummy.next = head; + int step = 1; + + while (step < length) { + ListNode prev = dummy, curr = dummy.next; + while (curr != null) { + ListNode left = curr; + ListNode right = split(left, step); + curr = split(right, step); + ListNode merged = merge(left, right); + prev.next = merged; + while (prev.next != null) { + prev = prev.next; + } + } + step *= 2; + } + + return dummy.next; + } + + private ListNode split(ListNode head, int step) { + if (head == null) return null; + for (int i = 0; i < step - 1 && head.next != null; i++) { + head = head.next; + } + ListNode nextPart = head.next; + head.next = null; + return nextPart; + } + + private ListNode merge(ListNode list1, ListNode list2) { + ListNode dummy = new ListNode(0); + ListNode tail = dummy; + + while (list1 != null && list2 != null) { + if (list1.val < list2.val) { + tail.next = list1; + list1 = list1.next; + } else { + tail.next = list2; + list2 = list2.next; + } + tail = tail.next; + } + + tail.next = (list1 != null) ? list1 : list2; + return dummy.next; + } +} +``` + +```cpp +/** + * Definition for singly-linked list. + * public class ListNode { + * int val; + * ListNode next; + * ListNode() {} + * ListNode(int val) { this.val = val; } + * ListNode(int val, ListNode next) { this.val = val; this.next = next; } + * } + */ +class Solution { +public: + ListNode* sortList(ListNode* head) { + if (!head || !head->next) { + return head; + } + + int length = 0; + ListNode* cur = head; + while (cur) { + length++; + cur = cur->next; + } + + ListNode dummy(0); + dummy.next = head; + int step = 1; + + while (step < length) { + ListNode* prev = &dummy, *curr = dummy.next; + while (curr) { + ListNode* left = curr; + ListNode* right = split(left, step); + curr = split(right, step); + ListNode* merged = merge(left, right); + prev->next = merged; + while (prev->next) { + prev = prev->next; + } + } + step *= 2; + } + + return dummy.next; + } + +private: + ListNode* split(ListNode* head, int step) { + if (!head) return nullptr; + for (int i = 0; i < step - 1 && head->next; i++) { + head = head->next; + } + ListNode* nextPart = head->next; + head->next = nullptr; + return nextPart; + } + + ListNode* merge(ListNode* list1, ListNode* list2) { + ListNode dummy(0); + ListNode* tail = &dummy; + + while (list1 && list2) { + if (list1->val < list2->val) { + tail->next = list1; + list1 = list1->next; + } else { + tail->next = list2; + list2 = list2->next; + } + tail = tail->next; + } + + tail->next = list1 ? list1 : list2; + return dummy.next; + } +}; +``` + +```javascript +/** + * Definition for singly-linked list. + * class ListNode { + * constructor(val = 0, next = null) { + * this.val = val; + * this.next = next; + * } + * } + */ +class Solution { + /** + * @param {ListNode} head + * @return {ListNode} + */ + sortList(head) { + if (!head || !head.next) { + return head; + } + + let length = 0; + let cur = head; + while (cur) { + length++; + cur = cur.next; + } + + let dummy = new ListNode(0); + dummy.next = head; + let step = 1; + + while (step < length) { + let prev = dummy, curr = dummy.next; + while (curr) { + let left = curr; + let right = this.split(left, step); + curr = this.split(right, step); + let merged = this.merge(left, right); + prev.next = merged; + while (prev.next) { + prev = prev.next; + } + } + step *= 2; + } + + return dummy.next; + } + + /** + * @param {ListNode} head + * @param {number} step + * @return {ListNode} + */ + split(head, step) { + if (!head) return null; + for (let i = 0; i < step - 1 && head.next; i++) { + head = head.next; + } + let nextPart = head.next; + head.next = null; + return nextPart; + } + + /** + * @param {ListNode} list1 + * @param {ListNode} list2 + * @return {ListNode} + */ + merge(list1, list2) { + let dummy = new ListNode(0); + let tail = dummy; + + while (list1 && list2) { + if (list1.val < list2.val) { + tail.next = list1; + list1 = list1.next; + } else { + tail.next = list2; + list2 = list2.next; + } + tail = tail.next; + } + + tail.next = list1 || list2; + return dummy.next; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n \log n)$ +* Space complexity: $O(1)$ \ No newline at end of file diff --git a/articles/swap-nodes-in-pairs.md b/articles/swap-nodes-in-pairs.md new file mode 100644 index 000000000..89edd0eee --- /dev/null +++ b/articles/swap-nodes-in-pairs.md @@ -0,0 +1,419 @@ +## 1. Convert TO Array + +::tabs-start + +```python +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, val=0, next=None): +# self.val = val +# self.next = next +class Solution: + def swapPairs(self, head: Optional[ListNode]) -> Optional[ListNode]: + if not head: + return None + arr = [] + cur = head + + while cur: + arr.append(cur) + cur = cur.next + + for i in range(0, len(arr) - 1, 2): + arr[i], arr[i + 1] = arr[i + 1], arr[i] + + for i in range(len(arr) - 1): + arr[i].next = arr[i + 1] + + arr[-1].next = None + return arr[0] +``` + +```java +/** + * Definition for singly-linked list. + * public class ListNode { + * int val; + * ListNode next; + * ListNode() {} + * ListNode(int val) { this.val = val; } + * ListNode(int val, ListNode next) { this.val = val; this.next = next; } + * } + */ +public class Solution { + public ListNode swapPairs(ListNode head) { + if (head == null) return null; + + List arr = new ArrayList<>(); + ListNode cur = head; + + while (cur != null) { + arr.add(cur); + cur = cur.next; + } + + for (int i = 0; i < arr.size() - 1; i += 2) { + ListNode temp = arr.get(i); + arr.set(i, arr.get(i + 1)); + arr.set(i + 1, temp); + } + + for (int i = 0; i < arr.size() - 1; i++) { + arr.get(i).next = arr.get(i + 1); + } + + arr.get(arr.size() - 1).next = null; + return arr.get(0); + } +} +``` + +```cpp +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode() : val(0), next(nullptr) {} + * ListNode(int x) : val(x), next(nullptr) {} + * ListNode(int x, ListNode *next) : val(x), next(next) {} + * }; + */ +class Solution { +public: + ListNode* swapPairs(ListNode* head) { + if (!head) return nullptr; + + vector arr; + ListNode* cur = head; + + while (cur) { + arr.push_back(cur); + cur = cur->next; + } + + for (size_t i = 0; i + 1 < arr.size(); i += 2) { + swap(arr[i], arr[i + 1]); + } + + for (size_t i = 0; i + 1 < arr.size(); i++) { + arr[i]->next = arr[i + 1]; + } + + arr.back()->next = nullptr; + return arr[0]; + } +}; +``` + +```javascript +/** + * Definition for singly-linked list. + * class ListNode { + * constructor(val = 0, next = null) { + * this.val = val; + * this.next = next; + * } + * } + */ +class Solution { + /** + * @param {ListNode} head + * @return {ListNode} + */ + swapPairs(head) { + if (!head) return null; + + let arr = []; + let cur = head; + + while (cur) { + arr.push(cur); + cur = cur.next; + } + + for (let i = 0; i + 1 < arr.length; i += 2) { + [arr[i], arr[i + 1]] = [arr[i + 1], arr[i]]; + } + + for (let i = 0; i + 1 < arr.length; i++) { + arr[i].next = arr[i + 1]; + } + + arr[arr.length - 1].next = null; + return arr[0]; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ + +--- + +## 2. Recursion + +::tabs-start + +```python +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, val=0, next=None): +# self.val = val +# self.next = next +class Solution: + def swapPairs(self, head: Optional[ListNode]) -> Optional[ListNode]: + if not head or not head.next: + return head + + cur = head + nxt = head.next + cur.next = self.swapPairs(nxt.next) + nxt.next = cur + return nxt +``` + +```java +/** + * Definition for singly-linked list. + * public class ListNode { + * int val; + * ListNode next; + * ListNode() {} + * ListNode(int val) { this.val = val; } + * ListNode(int val, ListNode next) { this.val = val; this.next = next; } + * } + */ +public class Solution { + public ListNode swapPairs(ListNode head) { + if (head == null || head.next == null) { + return head; + } + + ListNode cur = head; + ListNode nxt = head.next; + cur.next = swapPairs(nxt.next); + nxt.next = cur; + + return nxt; + } +} +``` + +```cpp +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode() : val(0), next(nullptr) {} + * ListNode(int x) : val(x), next(nullptr) {} + * ListNode(int x, ListNode *next) : val(x), next(next) {} + * }; + */ +class Solution { +public: + ListNode* swapPairs(ListNode* head) { + if (!head || !head->next) { + return head; + } + + ListNode* cur = head; + ListNode* nxt = head->next; + cur->next = swapPairs(nxt->next); + nxt->next = cur; + + return nxt; + } +}; +``` + +```javascript +/** + * Definition for singly-linked list. + * class ListNode { + * constructor(val = 0, next = null) { + * this.val = val; + * this.next = next; + * } + * } + */ +class Solution { + /** + * @param {ListNode} head + * @return {ListNode} + */ + swapPairs(head) { + if (!head || !head.next) { + return head; + } + + let cur = head; + let nxt = head.next; + cur.next = this.swapPairs(nxt.next); + nxt.next = cur; + + return nxt; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ for recursion stack. + +--- + +## 3. Iteration + +::tabs-start + +```python +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, val=0, next=None): +# self.val = val +# self.next = next +class Solution: + def swapPairs(self, head: Optional[ListNode]) -> Optional[ListNode]: + dummy = ListNode(0, head) + prev, curr = dummy, head + + while curr and curr.next: + nxtPair = curr.next.next + second = curr.next + + # Reverse this pair + second.next = curr + curr.next = nxtPair + prev.next = second + + # Update pointers + prev = curr + curr = nxtPair + + return dummy.next +``` + +```java +/** + * Definition for singly-linked list. + * public class ListNode { + * int val; + * ListNode next; + * ListNode() {} + * ListNode(int val) { this.val = val; } + * ListNode(int val, ListNode next) { this.val = val; this.next = next; } + * } + */ +public class Solution { + public ListNode swapPairs(ListNode head) { + ListNode dummy = new ListNode(0, head); + ListNode prev = dummy, curr = head; + + while (curr != null && curr.next != null) { + ListNode nxtPair = curr.next.next; + ListNode second = curr.next; + + // Reverse this pair + second.next = curr; + curr.next = nxtPair; + prev.next = second; + + // Update pointers + prev = curr; + curr = nxtPair; + } + + return dummy.next; + } +} +``` + +```cpp +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode() : val(0), next(nullptr) {} + * ListNode(int x) : val(x), next(nullptr) {} + * ListNode(int x, ListNode *next) : val(x), next(next) {} + * }; + */ +class Solution { +public: + ListNode* swapPairs(ListNode* head) { + ListNode dummy(0, head); + ListNode* prev = &dummy, *curr = head; + + while (curr && curr->next) { + ListNode* nxtPair = curr->next->next; + ListNode* second = curr->next; + + // Reverse this pair + second->next = curr; + curr->next = nxtPair; + prev->next = second; + + // Update pointers + prev = curr; + curr = nxtPair; + } + + return dummy.next; + } +}; +``` + +```javascript +/** + * Definition for singly-linked list. + * class ListNode { + * constructor(val = 0, next = null) { + * this.val = val; + * this.next = next; + * } + * } + */ +class Solution { + /** + * @param {ListNode} head + * @return {ListNode} + */ + swapPairs(head) { + let dummy = new ListNode(0, head); + let prev = dummy, curr = head; + + while (curr && curr.next) { + let nxtPair = curr.next.next; + let second = curr.next; + + // Reverse this pair + second.next = curr; + curr.next = nxtPair; + prev.next = second; + + // Update pointers + prev = curr; + curr = nxtPair; + } + + return dummy.next; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(1)$ \ No newline at end of file diff --git a/articles/swapping-nodes-in-a-linked-list.md b/articles/swapping-nodes-in-a-linked-list.md new file mode 100644 index 000000000..8a0267213 --- /dev/null +++ b/articles/swapping-nodes-in-a-linked-list.md @@ -0,0 +1,785 @@ +## 1. Convert To Array + +::tabs-start + +```python +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, val=0, next=None): +# self.val = val +# self.next = next +class Solution: + def swapNodes(self, head: Optional[ListNode], k: int) -> Optional[ListNode]: + arr = [] + cur = head + while cur: + arr.append(cur.val) + cur = cur.next + + n = len(arr) + arr[k - 1], arr[n - k] = arr[n - k], arr[k - 1] + + cur, i = head, 0 + while cur: + cur.val = arr[i] + cur = cur.next + i += 1 + + return head +``` + +```java +/** + * Definition for singly-linked list. + * public class ListNode { + * int val; + * ListNode next; + * ListNode() {} + * ListNode(int val) { this.val = val; } + * ListNode(int val, ListNode next) { this.val = val; this.next = next; } + * } + */ +public class Solution { + public ListNode swapNodes(ListNode head, int k) { + List arr = new ArrayList<>(); + ListNode cur = head; + + while (cur != null) { + arr.add(cur.val); + cur = cur.next; + } + + int n = arr.size(); + int temp = arr.get(k - 1); + arr.set(k - 1, arr.get(n - k)); + arr.set(n - k, temp); + + cur = head; + int i = 0; + while (cur != null) { + cur.val = arr.get(i); + cur = cur.next; + i++; + } + + return head; + } +} +``` + +```cpp +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode() : val(0), next(nullptr) {} + * ListNode(int x) : val(x), next(nullptr) {} + * ListNode(int x, ListNode *next) : val(x), next(next) {} + * }; + */ +class Solution { +public: + ListNode* swapNodes(ListNode* head, int k) { + vector arr; + ListNode* cur = head; + + while (cur) { + arr.push_back(cur->val); + cur = cur->next; + } + + int n = arr.size(); + swap(arr[k - 1], arr[n - k]); + + cur = head; + int i = 0; + while (cur) { + cur->val = arr[i]; + cur = cur->next; + i++; + } + + return head; + } +}; +``` + +```javascript +/** + * Definition for singly-linked list. + * class ListNode { + * constructor(val = 0, next = null) { + * this.val = val; + * this.next = next; + * } + * } + */ +class Solution { + /** + * @param {ListNode} head + * @param {number} k + * @return {ListNode} + */ + swapNodes(head, k) { + let arr = []; + let cur = head; + + while (cur) { + arr.push(cur.val); + cur = cur.next; + } + + let n = arr.length; + [arr[k - 1], arr[n - k]] = [arr[n - k], arr[k - 1]]; + + cur = head; + let i = 0; + while (cur) { + cur.val = arr[i]; + cur = cur.next; + i++; + } + + return head; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ + +--- + +## 2. Recursion + +::tabs-start + +```python +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, val=0, next=None): +# self.val = val +# self.next = next +class Solution: + def swapNodes(self, head: Optional[ListNode], k: int) -> Optional[ListNode]: + left, right, startIdx = None, None, 0 + + def dfs(node): + nonlocal left, right, startIdx + if not node: + return 0 + + startIdx += 1 + if startIdx == k: + left = node + + endIdx = dfs(node.next) + 1 + if endIdx == k: + right = node + + return endIdx + + dfs(head) + if left and right: + left.val, right.val = right.val, left.val + + return head +``` + +```java +/** + * Definition for singly-linked list. + * public class ListNode { + * int val; + * ListNode next; + * ListNode() {} + * ListNode(int val) { this.val = val; } + * ListNode(int val, ListNode next) { this.val = val; this.next = next; } + * } + */ +public class Solution { + public ListNode swapNodes(ListNode head, int k) { + ListNode[] left = new ListNode[1]; + ListNode[] right = new ListNode[1]; + int[] startIdx = {0}; + + dfs(head, k, startIdx, left, right); + + if (left[0] != null && right[0] != null) { + int temp = left[0].val; + left[0].val = right[0].val; + right[0].val = temp; + } + + return head; + } + + private int dfs(ListNode node, int k, int[] startIdx, ListNode[] left, ListNode[] right) { + if (node == null) { + return 0; + } + + startIdx[0]++; + if (startIdx[0] == k) { + left[0] = node; + } + + int endIdx = dfs(node.next, k, startIdx, left, right) + 1; + if (endIdx == k) { + right[0] = node; + } + + return endIdx; + } +} +``` + +```cpp +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode() : val(0), next(nullptr) {} + * ListNode(int x) : val(x), next(nullptr) {} + * ListNode(int x, ListNode *next) : val(x), next(next) {} + * }; + */ +class Solution { +public: + ListNode* swapNodes(ListNode* head, int k) { + ListNode* left = nullptr; + ListNode* right = nullptr; + int startIdx = 0; + + dfs(head, k, startIdx, left, right); + + if (left && right) { + swap(left->val, right->val); + } + + return head; + } + +private: + int dfs(ListNode* node, int k, int& startIdx, ListNode*& left, ListNode*& right) { + if (!node) { + return 0; + } + + startIdx++; + if (startIdx == k) { + left = node; + } + + int endIdx = dfs(node->next, k, startIdx, left, right) + 1; + if (endIdx == k) { + right = node; + } + + return endIdx; + } +}; +``` + +```javascript +/** + * Definition for singly-linked list. + * class ListNode { + * constructor(val = 0, next = null) { + * this.val = val; + * this.next = next; + * } + * } + */ +class Solution { + /** + * @param {ListNode} head + * @param {number} k + * @return {ListNode} + */ + swapNodes(head, k) { + let left = null, right = null, startIdx = 0; + + const dfs = (node) => { + if (!node) return 0; + + startIdx++; + if (startIdx === k) left = node; + + let endIdx = dfs(node.next) + 1; + if (endIdx === k) right = node; + + return endIdx; + }; + + dfs(head); + if (left && right) { + [left.val, right.val] = [right.val, left.val]; + } + + return head; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ for recursion stack. + +--- + +## 3. Iteration (Two Pass) + +::tabs-start + +```python +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, val=0, next=None): +# self.val = val +# self.next = next +class Solution: + def swapNodes(self, head: Optional[ListNode], k: int) -> Optional[ListNode]: + n = 0 + cur = head + while cur: + n += 1 + cur = cur.next + + left, right = None, None + cur = head + for i in range(1, n + 1): + if i == k: + left = cur + if i == (n - k + 1): + right = cur + cur = cur.next + + left.val, right.val = right.val, left.val + return head +``` + +```java +/** + * Definition for singly-linked list. + * public class ListNode { + * int val; + * ListNode next; + * ListNode() {} + * ListNode(int val) { this.val = val; } + * ListNode(int val, ListNode next) { this.val = val; this.next = next; } + * } + */ +public class Solution { + public ListNode swapNodes(ListNode head, int k) { + int n = 0; + ListNode cur = head; + while (cur != null) { + n++; + cur = cur.next; + } + + ListNode left = null, right = null; + cur = head; + for (int i = 1; i <= n; i++) { + if (i == k) { + left = cur; + } + if (i == (n - k + 1)) { + right = cur; + } + cur = cur.next; + } + + int temp = left.val; + left.val = right.val; + right.val = temp; + + return head; + } +} +``` + +```cpp +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode() : val(0), next(nullptr) {} + * ListNode(int x) : val(x), next(nullptr) {} + * ListNode(int x, ListNode *next) : val(x), next(next) {} + * }; + */ +class Solution { +public: + ListNode* swapNodes(ListNode* head, int k) { + int n = 0; + ListNode* cur = head; + while (cur) { + n++; + cur = cur->next; + } + + ListNode* left = nullptr; + ListNode* right = nullptr; + cur = head; + for (int i = 1; i <= n; i++) { + if (i == k) { + left = cur; + } + if (i == (n - k + 1)) { + right = cur; + } + cur = cur->next; + } + + swap(left->val, right->val); + return head; + } +}; +``` + +```javascript +/** + * Definition for singly-linked list. + * class ListNode { + * constructor(val = 0, next = null) { + * this.val = val; + * this.next = next; + * } + * } + */ +class Solution { + /** + * @param {ListNode} head + * @param {number} k + * @return {ListNode} + */ + swapNodes(head, k) { + let n = 0; + let cur = head; + while (cur) { + n++; + cur = cur.next; + } + + let left = null, right = null; + cur = head; + for (let i = 1; i <= n; i++) { + if (i === k) { + left = cur; + } + if (i === (n - k + 1)) { + right = cur; + } + cur = cur.next; + } + + [left.val, right.val] = [right.val, left.val]; + return head; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(1)$ + +--- + +## 4. Iteration (One Pass) - I + +::tabs-start + +```python +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, val=0, next=None): +# self.val = val +# self.next = next +class Solution: + def swapNodes(self, head: Optional[ListNode], k: int) -> Optional[ListNode]: + cur = head + for _ in range(k - 1): + cur = cur.next + + left = cur + right = head + + while cur.next: + cur = cur.next + right = right.next + + left.val, right.val = right.val, left.val + return head +``` + +```java +/** + * Definition for singly-linked list. + * public class ListNode { + * int val; + * ListNode next; + * ListNode() {} + * ListNode(int val) { this.val = val; } + * ListNode(int val, ListNode next) { this.val = val; this.next = next; } + * } + */ +public class Solution { + public ListNode swapNodes(ListNode head, int k) { + ListNode cur = head; + for (int i = 0; i < k - 1; i++) { + cur = cur.next; + } + + ListNode left = cur; + ListNode right = head; + + while (cur.next != null) { + cur = cur.next; + right = right.next; + } + + int temp = left.val; + left.val = right.val; + right.val = temp; + + return head; + } +} +``` + +```cpp +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode() : val(0), next(nullptr) {} + * ListNode(int x) : val(x), next(nullptr) {} + * ListNode(int x, ListNode *next) : val(x), next(next) {} + * }; + */ +class Solution { +public: + ListNode* swapNodes(ListNode* head, int k) { + ListNode* cur = head; + for (int i = 0; i < k - 1; i++) { + cur = cur->next; + } + + ListNode* left = cur; + ListNode* right = head; + + while (cur->next) { + cur = cur->next; + right = right->next; + } + + swap(left->val, right->val); + return head; + } +}; +``` + +```javascript +/** + * Definition for singly-linked list. + * class ListNode { + * constructor(val = 0, next = null) { + * this.val = val; + * this.next = next; + * } + * } + */ +class Solution { + /** + * @param {ListNode} head + * @param {number} k + * @return {ListNode} + */ + swapNodes(head, k) { + let cur = head; + for (let i = 0; i < k - 1; i++) { + cur = cur.next; + } + + let left = cur; + let right = head; + + while (cur.next) { + cur = cur.next; + right = right.next; + } + + [left.val, right.val] = [right.val, left.val]; + return head; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(1)$ + +--- + +## 5. Iteration (One Pass) - II + +::tabs-start + +```python +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, val=0, next=None): +# self.val = val +# self.next = next +class Solution: + def swapNodes(self, head: Optional[ListNode], k: int) -> Optional[ListNode]: + left, right = None, None + cur = head + + while cur: + if right: + right = right.next + if k == 1: + left = cur + right = head + k -= 1 + cur = cur.next + + left.val, right.val = right.val, left.val + return head +``` + +```java +/** + * Definition for singly-linked list. + * public class ListNode { + * int val; + * ListNode next; + * ListNode() {} + * ListNode(int val) { this.val = val; } + * ListNode(int val, ListNode next) { this.val = val; this.next = next; } + * } + */ +public class Solution { + public ListNode swapNodes(ListNode head, int k) { + ListNode left = null, right = null, cur = head; + + while (cur != null) { + if (right != null) { + right = right.next; + } + if (k == 1) { + left = cur; + right = head; + } + k--; + cur = cur.next; + } + + int temp = left.val; + left.val = right.val; + right.val = temp; + + return head; + } +} +``` + +```cpp +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode() : val(0), next(nullptr) {} + * ListNode(int x) : val(x), next(nullptr) {} + * ListNode(int x, ListNode *next) : val(x), next(next) {} + * }; + */ +class Solution { +public: + ListNode* swapNodes(ListNode* head, int k) { + ListNode* left = nullptr; + ListNode* right = nullptr; + ListNode* cur = head; + + while (cur) { + if (right) { + right = right->next; + } + if (k == 1) { + left = cur; + right = head; + } + k--; + cur = cur->next; + } + + swap(left->val, right->val); + return head; + } +}; +``` + +```javascript +/** + * Definition for singly-linked list. + * class ListNode { + * constructor(val = 0, next = null) { + * this.val = val; + * this.next = next; + * } + * } + */ +class Solution { + /** + * @param {ListNode} head + * @param {number} k + * @return {ListNode} + */ + swapNodes(head, k) { + let left = null, right = null, cur = head; + + while (cur) { + if (right) { + right = right.next; + } + if (k === 1) { + left = cur; + right = head; + } + k--; + cur = cur.next; + } + + [left.val, right.val] = [right.val, left.val]; + return head; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(1)$ \ No newline at end of file From 1654b7ab817c9a9c88294a059ecb16b2c8ea9395 Mon Sep 17 00:00:00 2001 From: Sri Hari Date: Wed, 29 Jan 2025 23:46:13 +0530 Subject: [PATCH 5/7] Batch-5/Neetcode-ALL/Added-articles --- articles/redundant-connection.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/articles/redundant-connection.md b/articles/redundant-connection.md index 4a51a9aa3..0fa8184eb 100644 --- a/articles/redundant-connection.md +++ b/articles/redundant-connection.md @@ -626,7 +626,7 @@ class Solution: def findRedundantConnection(self, edges: List[List[int]]) -> List[int]: n = len(edges) indegree = [0] * (n + 1) - adj = [[] for _ in range(n + 1)] + adj = [[] for _ in range(n + 1)] for u, v in edges: adj[u].append(v) adj[v].append(u) @@ -638,7 +638,7 @@ class Solution: if indegree[i] == 1: q.append(i) - while q: + while q: node = q.popleft() indegree[node] -= 1 for nei in adj[node]: @@ -646,7 +646,7 @@ class Solution: if indegree[nei] == 1: q.append(nei) - for u, v in edges[::-1]: + for u, v in reversed(edges): if indegree[u] == 2 and indegree[v]: return [u, v] return [] From 79724a04c9a3087dd0941bdbee31076dd4913902 Mon Sep 17 00:00:00 2001 From: Sri Hari Date: Wed, 29 Jan 2025 23:47:49 +0530 Subject: [PATCH 6/7] Batch-5/Neetcode-ALL/Added-articles --- articles/redundant-connection.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/articles/redundant-connection.md b/articles/redundant-connection.md index 0fa8184eb..81a67ff84 100644 --- a/articles/redundant-connection.md +++ b/articles/redundant-connection.md @@ -626,7 +626,7 @@ class Solution: def findRedundantConnection(self, edges: List[List[int]]) -> List[int]: n = len(edges) indegree = [0] * (n + 1) - adj = [[] for _ in range(n + 1)] + adj = [[] for _ in range(n + 1)] for u, v in edges: adj[u].append(v) adj[v].append(u) @@ -638,7 +638,7 @@ class Solution: if indegree[i] == 1: q.append(i) - while q: + while q: node = q.popleft() indegree[node] -= 1 for nei in adj[node]: From 5eb6a5b3d88bfd08d4db4d3a3387b9e3b8372fcf Mon Sep 17 00:00:00 2001 From: Sri Hari Date: Thu, 30 Jan 2025 20:28:34 +0530 Subject: [PATCH 7/7] Batch-5/Neetcode-ALL/Added-articles --- articles/check-if-move-is-legal.md | 298 +++++ .../find-closest-node-to-given-two-nodes.md | 669 +++++++++++ articles/shortest-bridge.md | 1068 +++++++++++++++++ articles/shortest-path-in-binary-matrix.md | 475 ++++++++ 4 files changed, 2510 insertions(+) create mode 100644 articles/check-if-move-is-legal.md create mode 100644 articles/find-closest-node-to-given-two-nodes.md create mode 100644 articles/shortest-bridge.md create mode 100644 articles/shortest-path-in-binary-matrix.md diff --git a/articles/check-if-move-is-legal.md b/articles/check-if-move-is-legal.md new file mode 100644 index 000000000..acc1d8b66 --- /dev/null +++ b/articles/check-if-move-is-legal.md @@ -0,0 +1,298 @@ +## 1. Iteration - I + +::tabs-start + +```python +class Solution: + def checkMove(self, board: List[List[str]], rMove: int, cMove: int, color: str) -> bool: + ROWS, COLS = len(board), len(board[0]) + direction = [[1, 0], [-1, 0], [0, 1], [0, -1], + [1, 1], [-1, -1], [1, -1], [-1, 1]] + + board[rMove][cMove] = color + + def legal(row, col, color, direc): + dr, dc = direc + row, col = row + dr, col + dc + length = 1 + + while 0 <= row < ROWS and 0 <= col < COLS: + length += 1 + if board[row][col] == ".": + return False + if board[row][col] == color: + return length >= 3 + row, col = row + dr, col + dc + return False + + for d in direction: + if legal(rMove, cMove, color, d): + return True + return False +``` + +```java +public class Solution { + public boolean checkMove(char[][] board, int rMove, int cMove, char color) { + int ROWS = board.length, COLS = board[0].length; + int[][] direction = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}, + {1, 1}, {-1, -1}, {1, -1}, {-1, 1}}; + + board[rMove][cMove] = color; + + for (int[] d : direction) { + if (legal(board, rMove, cMove, color, d)) { + return true; + } + } + return false; + } + + private boolean legal(char[][] board, int row, int col, char color, int[] direc) { + int ROWS = board.length, COLS = board[0].length; + int dr = direc[0], dc = direc[1]; + row += dr; + col += dc; + int length = 1; + + while (row >= 0 && row < ROWS && col >= 0 && col < COLS) { + length++; + if (board[row][col] == '.') { + return false; + } + if (board[row][col] == color) { + return length >= 3; + } + row += dr; + col += dc; + } + return false; + } +} +``` + +```cpp +class Solution { +public: + bool checkMove(vector>& board, int rMove, int cMove, char color) { + int ROWS = board.size(), COLS = board[0].size(); + vector> direction = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}, + {1, 1}, {-1, -1}, {1, -1}, {-1, 1}}; + + board[rMove][cMove] = color; + + for (auto& d : direction) { + if (legal(board, rMove, cMove, color, d)) { + return true; + } + } + return false; + } + +private: + bool legal(vector>& board, int row, int col, char color, vector& direc) { + int ROWS = board.size(), COLS = board[0].size(); + int dr = direc[0], dc = direc[1]; + row += dr; + col += dc; + int length = 1; + + while (row >= 0 && row < ROWS && col >= 0 && col < COLS) { + length++; + if (board[row][col] == '.') { + return false; + } + if (board[row][col] == color) { + return length >= 3; + } + row += dr; + col += dc; + } + return false; + } +}; +``` + +```javascript +class Solution { + /** + * @param {character[][]} board + * @param {number} rMove + * @param {number} cMove + * @param {character} color + * @return {boolean} + */ + checkMove(board, rMove, cMove, color) { + const ROWS = board.length, COLS = board[0].length; + const direction = [[1, 0], [-1, 0], [0, 1], [0, -1], + [1, 1], [-1, -1], [1, -1], [-1, 1]]; + + board[rMove][cMove] = color; + + const legal = (row, col, color, [dr, dc]) => { + row += dr; + col += dc; + let length = 1; + + while (row >= 0 && row < ROWS && col >= 0 && col < COLS) { + length++; + if (board[row][col] === ".") { + return false; + } + if (board[row][col] === color) { + return length >= 3; + } + row += dr; + col += dc; + } + return false; + }; + + for (let d of direction) { + if (legal(rMove, cMove, color, d)) { + return true; + } + } + return false; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(1)$ +* Space complexity: $O(1)$ + +--- + +## 2. Iteration - II + +::tabs-start + +```python +class Solution: + def checkMove(self, board: List[List[str]], rMove: int, cMove: int, color: str) -> bool: + ROWS, COLS = len(board), len(board[0]) + direction = [0, 1, 0, -1, 0, 1, 1, -1, -1, 1] + + board[rMove][cMove] = color + + for d in range(9): + length = 1 + row, col = rMove, cMove + while True: + row += direction[d] + col += direction[d + 1] + + if row < 0 or col < 0 or row >= ROWS or col >= COLS or board[row][col] == ".": + break + if board[row][col] == color: + if length > 1: + return True + break + length += 1 + + return False +``` + +```java +public class Solution { + public boolean checkMove(char[][] board, int rMove, int cMove, char color) { + int ROWS = board.length, COLS = board[0].length; + int[] direction = {0, 1, 0, -1, 0, 1, 1, -1, -1, 1}; + + board[rMove][cMove] = color; + + for (int d = 0; d < 9; d++) { + int row = rMove, col = cMove; + for (int length = 1; ; ++length) { + row += direction[d]; + col += direction[d + 1]; + + if (row < 0 || col < 0 || row >= ROWS || col >= COLS || board[row][col] == '.') + break; + if (board[row][col] == color) { + if (length > 1) + return true; + break; + } + } + } + return false; + } +} + +``` + +```cpp +class Solution { +public: + bool checkMove(vector>& board, int rMove, int cMove, char color) { + int ROWS = board.size(), COLS = board[0].size(); + int direction[10] = {0, 1, 0, -1, 0, 1, 1, -1, -1, 1}; + + board[rMove][cMove] = color; + + for (int d = 0; d < 9; ++d) { + int row = rMove, col = cMove; + for (int length = 1; ; ++length) { + row += direction[d]; + col += direction[d + 1]; + + if (row < 0 || col < 0 || row >= ROWS || col >= COLS || board[row][col] == '.') + break; + if (board[row][col] == color) { + if (length > 1) + return true; + break; + } + } + } + return false; + } +}; +``` + +```javascript +class Solution { + /** + * @param {character[][]} board + * @param {number} rMove + * @param {number} cMove + * @param {character} color + * @return {boolean} + */ + checkMove(board, rMove, cMove, color) { + const ROWS = board.length, COLS = board[0].length; + const direction = [0, 1, 0, -1, 0, 1, 1, -1, -1, 1]; + + board[rMove][cMove] = color; + + for (let d = 0; d < 9; d++) { + let row = rMove, col = cMove; + for (let length = 1; ; ++length) { + row += direction[d]; + col += direction[d + 1]; + + if (row < 0 || col < 0 || row >= ROWS || col >= COLS || board[row][col] === '.') + break; + if (board[row][col] === color) { + if (length > 1) + return true; + break; + } + } + } + return false; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(1)$ +* Space complexity: $O(1)$ \ No newline at end of file diff --git a/articles/find-closest-node-to-given-two-nodes.md b/articles/find-closest-node-to-given-two-nodes.md new file mode 100644 index 000000000..52cb6d365 --- /dev/null +++ b/articles/find-closest-node-to-given-two-nodes.md @@ -0,0 +1,669 @@ +## 1. Breadth First Search + +::tabs-start + +```python +class Solution: + def closestMeetingNode(self, edges: list[int], node1: int, node2: int) -> int: + adj = defaultdict(list) + for i, nei in enumerate(edges): + adj[i].append(nei) + + def bfs(src, distMap): + q = deque([(src, 0)]) + distMap[src] = 0 + while q: + node, dist = q.popleft() + for nei in adj[node]: + if nei not in distMap: + q.append((nei, dist + 1)) + distMap[nei] = dist + 1 + + node1Dist, node2Dist = {}, {} + bfs(node1, node1Dist) + bfs(node2, node2Dist) + + res, resDist = -1, float("inf") + for i in range(len(edges)): + if i in node1Dist and i in node2Dist: + dist = max(node1Dist[i], node2Dist[i]) + if dist < resDist: + resDist, res = dist, i + + return res +``` + +```java +public class Solution { + public int closestMeetingNode(int[] edges, int node1, int node2) { + int n = edges.length; + List[] adj = new ArrayList[n]; + for (int i = 0; i < n; i++) adj[i] = new ArrayList<>(); + for (int i = 0; i < n; i++) { + if (edges[i] != -1) adj[i].add(edges[i]); + } + + int[] node1Dist = bfs(node1, n, adj); + int[] node2Dist = bfs(node2, n, adj); + + int res = -1, resDist = Integer.MAX_VALUE; + for (int i = 0; i < n; i++) { + if (node1Dist[i] != -1 && node2Dist[i] != -1) { + int dist = Math.max(node1Dist[i], node2Dist[i]); + if (dist < resDist) { + resDist = dist; + res = i; + } + } + } + return res; + } + + private int[] bfs(int src, int n, List[] adj) { + int[] distMap = new int[n]; + Arrays.fill(distMap, -1); + Queue q = new LinkedList<>(); + q.offer(new int[]{src, 0}); + distMap[src] = 0; + + while (!q.isEmpty()) { + int[] cur = q.poll(); + int node = cur[0], dist = cur[1]; + + for (int nei : adj[node]) { + if (distMap[nei] == -1) { + q.offer(new int[]{nei, dist + 1}); + distMap[nei] = dist + 1; + } + } + } + return distMap; + } +} +``` + +```cpp +class Solution { +public: + int closestMeetingNode(vector& edges, int node1, int node2) { + int n = edges.size(); + vector> adj(n); + for (int i = 0; i < n; i++) { + if (edges[i] != -1) adj[i].push_back(edges[i]); + } + + vector node1Dist = bfs(node1, n, adj); + vector node2Dist = bfs(node2, n, adj); + + int res = -1, resDist = INT_MAX; + for (int i = 0; i < n; i++) { + if (node1Dist[i] != -1 && node2Dist[i] != -1) { + int dist = max(node1Dist[i], node2Dist[i]); + if (dist < resDist) { + resDist = dist; + res = i; + } + } + } + return res; + } + +private: + vector bfs(int src, int n, vector>& adj) { + vector distMap(n, -1); + queue> q; + q.push({src, 0}); + distMap[src] = 0; + + while (!q.empty()) { + auto [node, dist] = q.front(); + q.pop(); + + for (int nei : adj[node]) { + if (distMap[nei] == -1) { + q.push({nei, dist + 1}); + distMap[nei] = dist + 1; + } + } + } + return distMap; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} edges + * @param {number} node1 + * @param {number} node2 + * @return {number} + */ + closestMeetingNode(edges, node1, node2) { + const n = edges.length; + const adj = Array.from({ length: n }, () => []); + for (let i = 0; i < n; i++) { + if (edges[i] !== -1) adj[i].push(edges[i]); + } + + const bfs = (src) => { + const distMap = Array(n).fill(-1); + const q = new Queue([[src, 0]]); + distMap[src] = 0; + + while (!q.isEmpty()) { + const [node, dist] = q.pop(); + for (const nei of adj[node]) { + if (distMap[nei] === -1) { + q.push([nei, dist + 1]); + distMap[nei] = dist + 1; + } + } + } + return distMap; + }; + + const node1Dist = bfs(node1); + const node2Dist = bfs(node2); + + let res = -1, resDist = Infinity; + for (let i = 0; i < n; i++) { + if (node1Dist[i] !== -1 && node2Dist[i] !== -1) { + let dist = Math.max(node1Dist[i], node2Dist[i]); + if (dist < resDist) { + resDist = dist; + res = i; + } + } + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ + +--- + +## 2. Breadth First Search (Optimal) + +::tabs-start + +```python +class Solution: + def closestMeetingNode(self, edges: list[int], node1: int, node2: int) -> int: + n = len(edges) + + def bfs(src): + dist = [-1] * n + q = deque([src]) + dist[src] = 0 + + while q: + node = q.popleft() + nei = edges[node] + if nei == -1 or dist[nei] >= 0: + continue + q.append(nei) + dist[nei] = dist[node] + 1 + return dist + + node1Dist, node2Dist = bfs(node1), bfs(node2) + + res, resDist = -1, float("inf") + for i in range(n): + if node1Dist[i] != -1 and node2Dist[i] != -1: + dist = max(node1Dist[i], node2Dist[i]) + if dist < resDist: + resDist, res = dist, i + + return res +``` + +```java +public class Solution { + public int closestMeetingNode(int[] edges, int node1, int node2) { + int n = edges.length; + int[] node1Dist = bfs(node1, edges, n); + int[] node2Dist = bfs(node2, edges, n); + + int res = -1, resDist = Integer.MAX_VALUE; + for (int i = 0; i < n; i++) { + if (node1Dist[i] != -1 && node2Dist[i] != -1) { + int dist = Math.max(node1Dist[i], node2Dist[i]); + if (dist < resDist) { + resDist = dist; + res = i; + } + } + } + + return res; + } + + private int[] bfs(int src, int[] edges, int n) { + int[] dist = new int[n]; + Arrays.fill(dist, -1); + Queue q = new LinkedList<>(); + q.offer(src); + dist[src] = 0; + + while (!q.isEmpty()) { + int node = q.poll(); + int nei = edges[node]; + if (nei == -1 || dist[nei] != -1) { + continue; + } + + q.offer(nei); + dist[nei] = dist[node] + 1; + } + return dist; + } +} +``` + +```cpp +class Solution { +public: + int closestMeetingNode(vector& edges, int node1, int node2) { + int n = edges.size(); + vector node1Dist = bfs(node1, edges, n); + vector node2Dist = bfs(node2, edges, n); + + int res = -1, resDist = INT_MAX; + for (int i = 0; i < n; i++) { + if (node1Dist[i] != -1 && node2Dist[i] != -1) { + int dist = max(node1Dist[i], node2Dist[i]); + if (dist < resDist) { + resDist = dist; + res = i; + } + } + } + return res; + } + +private: + vector bfs(int src, vector& edges, int n) { + vector dist(n, -1); + queue q; + q.push(src); + dist[src] = 0; + + while (!q.empty()) { + int node = q.front(); + q.pop(); + int nei = edges[node]; + if (nei == -1 || dist[nei] != -1) { + continue; + } + + q.push(nei); + dist[nei] = dist[node] + 1; + } + return dist; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} edges + * @param {number} node1 + * @param {number} node2 + * @return {number} + */ + closestMeetingNode(edges, node1, node2) { + const n = edges.length; + + const bfs = (src) => { + const dist = Array(n).fill(-1); + const q = new Queue([src]); + dist[src] = 0; + + while (!q.isEmpty()) { + const node = q.pop(); + const nei = edges[node]; + if (nei === -1 || dist[nei] !== -1) { + continue; + } + + q.push(nei); + dist[nei] = dist[node] + 1; + } + return dist; + }; + + const node1Dist = bfs(node1); + const node2Dist = bfs(node2); + + let res = -1, resDist = Infinity; + for (let i = 0; i < n; i++) { + if (node1Dist[i] !== -1 && node2Dist[i] !== -1) { + let dist = Math.max(node1Dist[i], node2Dist[i]); + if (dist < resDist) { + resDist = dist; + res = i; + } + } + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ + +--- + +## 3. Depth First Search + +::tabs-start + +```python +class Solution: + def closestMeetingNode(self, edges: List[int], node1: int, node2: int) -> int: + n = len(edges) + + def dfs(node, dist): + nei = edges[node] + if nei != -1 and dist[nei] == -1: + dist[nei] = dist[node] + 1 + dfs(nei, dist) + + node1Dist = [-1] * n + node2Dist = [-1] * n + node1Dist[node1] = node2Dist[node2] = 0 + + dfs(node1, node1Dist) + dfs(node2, node2Dist) + + res, resDist = -1, float("inf") + for i in range(n): + if min(node1Dist[i], node2Dist[i]) != -1: + dist = max(node1Dist[i], node2Dist[i]) + if dist < resDist: + resDist, res = dist, i + + return res +``` + +```java +public class Solution { + public int closestMeetingNode(int[] edges, int node1, int node2) { + int n = edges.length; + int[] node1Dist = new int[n]; + int[] node2Dist = new int[n]; + Arrays.fill(node1Dist, -1); + Arrays.fill(node2Dist, -1); + node1Dist[node1] = 0; + node2Dist[node2] = 0; + + dfs(node1, edges, node1Dist); + dfs(node2, edges, node2Dist); + + int res = -1, resDist = Integer.MAX_VALUE; + for (int i = 0; i < n; i++) { + if (Math.min(node1Dist[i], node2Dist[i]) != -1) { + int dist = Math.max(node1Dist[i], node2Dist[i]); + if (dist < resDist) { + resDist = dist; + res = i; + } + } + } + return res; + } + + private void dfs(int node, int[] edges, int[] dist) { + int nei = edges[node]; + if (nei != -1 && dist[nei] == -1) { + dist[nei] = dist[node] + 1; + dfs(nei, edges, dist); + } + } +} +``` + +```cpp +class Solution { +public: + int closestMeetingNode(vector& edges, int node1, int node2) { + int n = edges.size(); + vector node1Dist(n, -1), node2Dist(n, -1); + node1Dist[node1] = node2Dist[node2] = 0; + + dfs(node1, edges, node1Dist); + dfs(node2, edges, node2Dist); + + int res = -1, resDist = INT_MAX; + for (int i = 0; i < n; i++) { + if (min(node1Dist[i], node2Dist[i]) != -1) { + int dist = max(node1Dist[i], node2Dist[i]); + if (dist < resDist) { + resDist = dist; + res = i; + } + } + } + return res; + } + +private: + void dfs(int node, vector& edges, vector& dist) { + int nei = edges[node]; + if (nei != -1 && dist[nei] == -1) { + dist[nei] = dist[node] + 1; + dfs(nei, edges, dist); + } + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} edges + * @param {number} node1 + * @param {number} node2 + * @return {number} + */ + closestMeetingNode(edges, node1, node2) { + const n = edges.length; + + const dfs = (node, dist) => { + const nei = edges[node]; + if (nei !== -1 && dist[nei] === -1) { + dist[nei] = dist[node] + 1; + dfs(nei, dist); + } + }; + + const node1Dist = Array(n).fill(-1); + const node2Dist = Array(n).fill(-1); + node1Dist[node1] = 0; + node2Dist[node2] = 0; + + dfs(node1, node1Dist); + dfs(node2, node2Dist); + + let res = -1, resDist = Infinity; + for (let i = 0; i < n; i++) { + if (Math.min(node1Dist[i], node2Dist[i]) !== -1) { + const dist = Math.max(node1Dist[i], node2Dist[i]); + if (dist < resDist) { + resDist = dist; + res = i; + } + } + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ + +--- + +## 4. Iterative Depth First Search + +::tabs-start + +```python +class Solution: + def closestMeetingNode(self, edges: list[int], node1: int, node2: int) -> int: + n = len(edges) + + def dfs(node): + dist = [-1] * n + dist[node] = 0 + while edges[node] != -1 and dist[edges[node]] == -1: + nei = edges[node] + dist[nei] = dist[node] + 1 + node = nei + return dist + + + node1Dist, node2Dist = dfs(node1), dfs(node2) + res, resDist = -1, float("inf") + for i in range(n): + if min(node1Dist[i], node2Dist[i]) != -1: + dist = max(node1Dist[i], node2Dist[i]) + if dist < resDist: + resDist, res = dist, i + return res +``` + +```java +public class Solution { + public int closestMeetingNode(int[] edges, int node1, int node2) { + int n = edges.length; + int[] node1Dist = dfs(node1, edges, n); + int[] node2Dist = dfs(node2, edges, n); + + int res = -1, resDist = Integer.MAX_VALUE; + for (int i = 0; i < n; i++) { + if (Math.min(node1Dist[i], node2Dist[i]) != -1) { + int dist = Math.max(node1Dist[i], node2Dist[i]); + if (dist < resDist) { + resDist = dist; + res = i; + } + } + } + return res; + } + + private int[] dfs(int node, int[] edges, int n) { + int[] dist = new int[n]; + Arrays.fill(dist, -1); + dist[node] = 0; + while (edges[node] != -1 && dist[edges[node]] == -1) { + int nei = edges[node]; + dist[nei] = dist[node] + 1; + node = nei; + } + return dist; + } +} +``` + +```cpp +class Solution { +public: + int closestMeetingNode(vector& edges, int node1, int node2) { + int n = edges.size(); + vector node1Dist = dfs(node1, edges, n); + vector node2Dist = dfs(node2, edges, n); + + int res = -1, resDist = INT_MAX; + for (int i = 0; i < n; i++) { + if (min(node1Dist[i], node2Dist[i]) != -1) { + int dist = max(node1Dist[i], node2Dist[i]); + if (dist < resDist) { + resDist = dist; + res = i; + } + } + } + return res; + } + +private: + vector dfs(int node, vector& edges, int n) { + vector dist(n, -1); + dist[node] = 0; + while (edges[node] != -1 && dist[edges[node]] == -1) { + int nei = edges[node]; + dist[nei] = dist[node] + 1; + node = nei; + } + return dist; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} edges + * @param {number} node1 + * @param {number} node2 + * @return {number} + */ + closestMeetingNode(edges, node1, node2) { + const n = edges.length; + + const dfs = (node) => { + const dist = Array(n).fill(-1); + dist[node] = 0; + while (edges[node] !== -1 && dist[edges[node]] === -1) { + const nei = edges[node]; + dist[nei] = dist[node] + 1; + node = nei; + } + return dist; + }; + + const node1Dist = dfs(node1); + const node2Dist = dfs(node2); + + let res = -1, resDist = Infinity; + for (let i = 0; i < n; i++) { + if (Math.min(node1Dist[i], node2Dist[i]) !== -1) { + const dist = Math.max(node1Dist[i], node2Dist[i]); + if (dist < resDist) { + resDist = dist; + res = i; + } + } + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ \ No newline at end of file diff --git a/articles/shortest-bridge.md b/articles/shortest-bridge.md new file mode 100644 index 000000000..14f78e190 --- /dev/null +++ b/articles/shortest-bridge.md @@ -0,0 +1,1068 @@ +## 1. Depth First Search + Breadth First Search - I + +::tabs-start + +```python +class Solution: + def shortestBridge(self, grid: List[List[int]]) -> int: + N = len(grid) + direct = [[0, 1], [0, -1], [1, 0], [-1, 0]] + + def invalid(r, c): + return r < 0 or c < 0 or r == N or c == N + + visit = set() + + def dfs(r, c): + if invalid(r, c) or not grid[r][c] or (r, c) in visit: + return + visit.add((r, c)) + for dr, dc in direct: + dfs(r + dr, c + dc) + + def bfs(): + res, q = 0, deque(visit) + while q: + for _ in range(len(q)): + r, c = q.popleft() + for dr, dc in direct: + curR, curC = r + dr, c + dc + if invalid(curR, curC) or (curR, curC) in visit: + continue + if grid[curR][curC]: + return res + q.append((curR, curC)) + visit.add((curR, curC)) + res += 1 + + for r in range(N): + for c in range(N): + if grid[r][c]: + dfs(r, c) + return bfs() +``` + +```java +public class Solution { + private int N; + private boolean[][] visited; + private final int[][] direct = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}}; + + public int shortestBridge(int[][] grid) { + N = grid.length; + visited = new boolean[N][N]; + + boolean found = false; + for (int r = 0; r < N; r++) { + if (found) break; + for (int c = 0; c < N; c++) { + if (grid[r][c] == 1) { + dfs(grid, r, c); + found = true; + break; + } + } + } + + return bfs(grid); + } + + private void dfs(int[][] grid, int r, int c) { + if (r < 0 || c < 0 || r >= N || c >= N || grid[r][c] == 0 || visited[r][c]) + return; + + visited[r][c] = true; + + for (int[] d : direct) { + dfs(grid, r + d[0], c + d[1]); + } + } + + private int bfs(int[][] grid) { + Queue q = new LinkedList<>(); + for (int r = 0; r < N; r++) { + for (int c = 0; c < N; c++) { + if (visited[r][c]) { + q.offer(new int[]{r, c}); + } + } + } + + int res = 0; + while (!q.isEmpty()) { + for (int i = q.size(); i > 0; i--) { + int[] cell = q.poll(); + int r = cell[0], c = cell[1]; + + for (int[] d : direct) { + int curR = r + d[0], curC = c + d[1]; + + if (curR < 0 || curC < 0 || curR >= N || curC >= N || visited[curR][curC]) + continue; + + if (grid[curR][curC] == 1) return res; + + q.offer(new int[]{curR, curC}); + visited[curR][curC] = true; + } + } + res++; + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int N; + vector> visited; + vector> direct = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}}; + + int shortestBridge(vector>& grid) { + N = grid.size(); + visited = vector>(N, vector(N, false)); + + bool found = false; + for (int r = 0; r < N; r++) { + if (found) break; + for (int c = 0; c < N; c++) { + if (grid[r][c] == 1) { + dfs(grid, r, c); + found = true; + break; + } + } + } + + return bfs(grid); + } + +private: + void dfs(vector>& grid, int r, int c) { + if (r < 0 || c < 0 || r >= N || c >= N || grid[r][c] == 0 || visited[r][c]) + return; + + visited[r][c] = true; + for (auto& d : direct) { + dfs(grid, r + d[0], c + d[1]); + } + } + + int bfs(vector>& grid) { + queue> q; + for (int r = 0; r < N; r++) { + for (int c = 0; c < N; c++) { + if (visited[r][c]) { + q.push({r, c}); + } + } + } + + int res = 0; + while (!q.empty()) { + for (int i = q.size(); i > 0; i--) { + auto [r, c] = q.front(); q.pop(); + + for (auto& d : direct) { + int curR = r + d[0], curC = c + d[1]; + + if (curR < 0 || curC < 0 || curR >= N || curC >= N || visited[curR][curC]) + continue; + + if (grid[curR][curC] == 1) return res; + q.push({curR, curC}); + visited[curR][curC] = true; + } + } + res++; + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} grid + * @return {number} + */ + shortestBridge(grid) { + const N = grid.length; + const direct = [[0, 1], [0, -1], [1, 0], [-1, 0]]; + const visited = Array.from({ length: N }, () => Array(N).fill(false)); + const q = new Queue(); + + const dfs = (r, c) => { + if (r < 0 || c < 0 || r >= N || c >= N || grid[r][c] === 0 || visited[r][c]) + return; + visited[r][c] = true; + q.push([r, c]); + + for (const [dr, dc] of direct) { + dfs(r + dr, c + dc); + } + }; + + const bfs = () => { + let res = 0; + while (!q.isEmpty()) { + for (let i = q.size(); i > 0; i--) { + const [r, c] = q.pop(); + for (const [dr, dc] of direct) { + const curR = r + dr, curC = c + dc; + + if (curR < 0 || curC < 0 || curR >= N || curC >= N || visited[curR][curC]) + continue; + if (grid[curR][curC] === 1) return res; + + q.push([curR, curC]); + visited[curR][curC] = true; + } + } + res++; + } + }; + + for (let r = 0; r < N; r++) { + for (let c = 0; c < N; c++) { + if (grid[r][c] === 1) { + dfs(r, c); + return bfs(); + } + } + } + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 2)$ +* Space complexity: $O(n ^ 2)$ + +--- + +## 2. Depth First Search + Breadth First Search - II + +::tabs-start + +```python +class Solution: + def shortestBridge(self, grid: list[list[int]]) -> int: + N, direct = len(grid), [(0, 1), (0, -1), (1, 0), (-1, 0)] + + def dfs(r, c): + if 0 <= r < N and 0 <= c < N and grid[r][c] == 1: + grid[r][c] = 2 + q.append((r, c)) + for dr, dc in direct: + dfs(r + dr, c + dc) + + q = deque() + for r in range(N): + for c in range(N): + if grid[r][c]: + dfs(r, c) + break + if q: break + + res = 0 + while q: + for _ in range(len(q)): + r, c = q.popleft() + for dr, dc in direct: + nr, nc = r + dr, c + dc + if 0 <= nr < N and 0 <= nc < N: + if grid[nr][nc] == 1: + return res + if grid[nr][nc] == 0: + grid[nr][nc] = 2 + q.append((nr, nc)) + res += 1 +``` + +```java +public class Solution { + private int[][] direct = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}}; + + public int shortestBridge(int[][] grid) { + int N = grid.length; + Queue q = new LinkedList<>(); + + boolean found = false; + for (int r = 0; r < N; r++) { + if (found) break; + for (int c = 0; c < N; c++) { + if (grid[r][c] == 1) { + dfs(grid, r, c, q); + found = true; + break; + } + } + } + + int res = 0; + while (!q.isEmpty()) { + for (int i = q.size(); i > 0; i--) { + int[] cell = q.poll(); + int r = cell[0], c = cell[1]; + + for (int[] d : direct) { + int nr = r + d[0], nc = c + d[1]; + + if (nr < 0 || nc < 0 || nr >= N || nc >= N) continue; + if (grid[nr][nc] == 1) return res; + + if (grid[nr][nc] == 0) { + grid[nr][nc] = 2; + q.offer(new int[]{nr, nc}); + } + } + } + res++; + } + return res; + } + + private void dfs(int[][] grid, int r, int c, Queue q) { + if (r < 0 || c < 0 || r >= grid.length || c >= grid.length || grid[r][c] != 1) + return; + + grid[r][c] = 2; + q.offer(new int[]{r, c}); + for (int[] d : direct) { + dfs(grid, r + d[0], c + d[1], q); + } + } +} +``` + +```cpp +class Solution { + vector> direct; + +public: + int shortestBridge(vector>& grid) { + int N = grid.size(); + direct = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}}; + queue> q; + + bool found = false; + for (int r = 0; r < N; r++) { + if (found) break; + for (int c = 0; c < N; c++) { + if (grid[r][c] == 1) { + dfs(grid, r, c, q); + found = true; + break; + } + } + } + + int res = 0; + while (!q.empty()) { + for (int i = q.size(); i > 0; i--) { + auto [r, c] = q.front(); q.pop(); + + for (auto& d : direct) { + int nr = r + d[0], nc = c + d[1]; + + if (nr < 0 || nc < 0 || nr >= N || nc >= N) continue; + if (grid[nr][nc] == 1) return res; + + if (grid[nr][nc] == 0) { + grid[nr][nc] = 2; + q.push({nr, nc}); + } + } + } + res++; + } + return res; + } + +private: + void dfs(vector>& grid, int r, int c, queue>& q) { + if (r < 0 || c < 0 || r >= grid.size() || c >= grid.size() || grid[r][c] != 1) + return; + + grid[r][c] = 2; + q.push({r, c}); + for (auto& d : direct) { + dfs(grid, r + d[0], c + d[1], q); + } + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} grid + * @return {number} + */ + shortestBridge(grid) { + const N = grid.length; + const direct = [[0, 1], [0, -1], [1, 0], [-1, 0]]; + const q = new Queue(); + + const dfs = (r, c) => { + if (r < 0 || c < 0 || r >= N || c >= N || grid[r][c] !== 1) return; + grid[r][c] = 2; + q.push([r, c]); + for (const [dr, dc] of direct) { + dfs(r + dr, c + dc); + } + }; + + let found = false; + for (let r = 0; r < N; r++) { + if (found) break; + for (let c = 0; c < N; c++) { + if (grid[r][c] === 1) { + dfs(r, c); + found = true; + break; + } + } + } + + let res = 0; + while (!q.isEmpty()) { + for (let i = q.size(); i > 0; i--) { + const [r, c] = q.pop(); + for (const [dr, dc] of direct) { + let nr = r + dr, nc = c + dc; + if (nr < 0 || nc < 0 || nr >= N || nc >= N) continue; + if (grid[nr][nc] === 1) return res; + if (grid[nr][nc] === 0) { + grid[nr][nc] = 2; + q.push([nr, nc]); + } + } + } + res++; + } + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 2)$ +* Space complexity: $O(n ^ 2)$ + +--- + +## 3. Breadth First Search + +::tabs-start + +```python +class Solution: + def shortestBridge(self, grid: list[list[int]]) -> int: + N, direct = len(grid), [(0, 1), (0, -1), (1, 0), (-1, 0)] + q2 = deque() + + found = False + for r in range(N): + if found: break + for c in range(N): + if grid[r][c] == 1: + q1 = deque([(r, c)]) + grid[r][c] = 2 + while q1: + x, y = q1.popleft() + q2.append((x, y)) + for dx, dy in direct: + nx, ny = x + dx, y + dy + if 0 <= nx < N and 0 <= ny < N and grid[nx][ny] == 1: + grid[nx][ny] = 2 + q1.append((nx, ny)) + found = True + break + + res = 0 + while q2: + for _ in range(len(q2)): + x, y = q2.popleft() + for dx, dy in direct: + nx, ny = x + dx, y + dy + if 0 <= nx < N and 0 <= ny < N: + if grid[nx][ny] == 1: + return res + if grid[nx][ny] == 0: + grid[nx][ny] = 2 + q2.append((nx, ny)) + res += 1 + + return res +``` + +```java +public class Solution { + public int shortestBridge(int[][] grid) { + int N = grid.length; + int[][] direct = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}}; + Queue q2 = new LinkedList<>(); + + boolean found = false; + for (int r = 0; r < N; r++) { + if (found) break; + for (int c = 0; c < N; c++) { + if (grid[r][c] == 1) { + Queue q1 = new LinkedList<>(); + q1.offer(new int[]{r, c}); + grid[r][c] = 2; + + while (!q1.isEmpty()) { + int[] cell = q1.poll(); + int x = cell[0], y = cell[1]; + q2.offer(new int[]{x, y}); + + for (int[] d : direct) { + int nx = x + d[0], ny = y + d[1]; + if (nx >= 0 && ny >= 0 && nx < N && ny < N && grid[nx][ny] == 1) { + grid[nx][ny] = 2; + q1.offer(new int[]{nx, ny}); + } + } + } + found = true; + break; + } + } + } + + int res = 0; + while (!q2.isEmpty()) { + for (int i = q2.size(); i > 0; i--) { + int[] cell = q2.poll(); + int x = cell[0], y = cell[1]; + + for (int[] d : direct) { + int nx = x + d[0], ny = y + d[1]; + + if (nx >= 0 && ny >= 0 && nx < N && ny < N) { + if (grid[nx][ny] == 1) return res; + if (grid[nx][ny] == 0) { + grid[nx][ny] = 2; + q2.offer(new int[]{nx, ny}); + } + } + } + } + res++; + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int shortestBridge(vector>& grid) { + int N = grid.size(); + vector> direct = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}}; + queue> q2; + + bool found = false; + for (int r = 0; r < N; r++) { + if (found) break; + for (int c = 0; c < N; c++) { + if (grid[r][c] == 1) { + queue> q1; + q1.push({r, c}); + grid[r][c] = 2; + + while (!q1.empty()) { + auto [x, y] = q1.front(); q1.pop(); + q2.push({x, y}); + + for (auto& d : direct) { + int nx = x + d[0], ny = y + d[1]; + if (nx >= 0 && ny >= 0 && nx < N && ny < N && grid[nx][ny] == 1) { + grid[nx][ny] = 2; + q1.push({nx, ny}); + } + } + } + found = true; + break; + } + } + } + + int res = 0; + while (!q2.empty()) { + for (int i = q2.size(); i > 0; i--) { + auto [x, y] = q2.front(); q2.pop(); + + for (auto& d : direct) { + int nx = x + d[0], ny = y + d[1]; + + if (nx >= 0 && ny >= 0 && nx < N && ny < N) { + if (grid[nx][ny] == 1) return res; + if (grid[nx][ny] == 0) { + grid[nx][ny] = 2; + q2.push({nx, ny}); + } + } + } + } + res++; + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} grid + * @return {number} + */ + shortestBridge(grid) { + const N = grid.length; + const direct = [[0, 1], [0, -1], [1, 0], [-1, 0]]; + const q2 = new Queue(); + + let found = false; + for (let r = 0; r < N; r++) { + if (found) break; + for (let c = 0; c < N; c++) { + if (grid[r][c] === 1) { + const q1 = new Queue([[r, c]]); + grid[r][c] = 2; + + while (!q1.isEmpty()) { + let [x, y] = q1.pop(); + q2.push([x, y]); + + for (let [dx, dy] of direct) { + let nx = x + dx, ny = y + dy; + if (nx >= 0 && ny >= 0 && nx < N && ny < N && grid[nx][ny] === 1) { + grid[nx][ny] = 2; + q1.push([nx, ny]); + } + } + } + found = true; + break; + } + } + } + + let res = 0; + while (!q2.isEmpty()) { + for (let i = q2.size(); i > 0; i--) { + const [x, y] = q2.pop(); + + for (let [dx, dy] of direct) { + let nx = x + dx, ny = y + dy; + if (nx >= 0 && ny >= 0 && nx < N && ny < N) { + if (grid[nx][ny] === 1) return res; + if (grid[nx][ny] === 0) { + grid[nx][ny] = 2; + q2.push([nx, ny]); + } + } + } + } + res++; + } + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 2)$ +* Space complexity: $O(n ^ 2)$ + +--- + +## 4. Disjoint Set Union + Breadth First Search + +::tabs-start + +```python +class DSU: + def __init__(self, n): + self.parent = list(range(n)) + self.rank = [1] * n + + def find(self, node): + cur = node + while cur != self.parent[cur]: + self.parent[cur] = self.parent[self.parent[cur]] + cur = self.parent[cur] + return cur + + def union(self, u, v): + pu, pv = self.find(u), self.find(v) + if pu == pv: + return False + if self.rank[pv] > self.rank[pu]: + pu, pv = pv, pu + self.parent[pv] = pu + self.rank[pu] += self.rank[pv] + return True + +class Solution: + def shortestBridge(self, grid: list[list[int]]) -> int: + n, direct = len(grid), [(0, 1), (0, -1), (1, 0), (-1, 0)] + dsu = DSU(n * n + 1) + + def idx(r, c): + return r * n + c + 1 + + for r in range(n): + for c in range(n): + if grid[r][c] == 1: + first_island = dsu.find(idx(r, c)) + if c + 1 < n and grid[r][c + 1] == 1: + dsu.union(idx(r, c), idx(r, c + 1)) + if r + 1 < n and grid[r + 1][c] == 1: + dsu.union(idx(r, c), idx(r + 1, c)) + + q = deque() + for r in range(n): + for c in range(n): + if grid[r][c] == 1: + if dsu.find(idx(r, c)) != first_island: + continue + for dx, dy in direct: + nr, nc = r + dx, c + dy + if 0 <= nr < n and 0 <= nc < n and grid[nr][nc] == 0: + q.append((r,c)) + break + + res = 0 + while q: + for _ in range(len(q)): + r, c = q.popleft() + for dx, dy in direct: + nr, nc = r + dx, c + dy + if 0 <= nr < n and 0 <= nc < n: + if grid[nr][nc] == 1 and dsu.union(idx(r, c), idx(nr, nc)): + return res + if grid[nr][nc] == 0: + grid[nr][nc] = 1 + dsu.union(idx(r, c), idx(nr, nc)) + q.append((nr, nc)) + res += 1 +``` + +```java +class DSU { + private int[] parent, rank; + + public DSU(int n) { + parent = new int[n]; + rank = new int[n]; + for (int i = 0; i < n; i++) parent[i] = i; + Arrays.fill(rank, 1); + } + + public int find(int node) { + if (parent[node] != node) { + parent[node] = find(parent[node]); + } + return parent[node]; + } + + public boolean union(int u, int v) { + int pu = find(u), pv = find(v); + if (pu == pv) return false; + + if (rank[pv] > rank[pu]) { + int temp = pu; + pu = pv; + pv = temp; + } + parent[pv] = pu; + rank[pu] += rank[pv]; + return true; + } +} + +public class Solution { + private int n; + private int idx(int r, int c) { + return r * n + c + 1; + } + + public int shortestBridge(int[][] grid) { + n = grid.length; + int[][] direct = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}}; + DSU dsu = new DSU(n * n + 1); + Queue q = new LinkedList<>(); + + + int firstIsland = -1; + for (int r = 0; r < n; r++) { + for (int c = 0; c < n; c++) { + if (grid[r][c] == 1) { + firstIsland = dsu.find(idx(r, c)); + if (c + 1 < n && grid[r][c + 1] == 1) + dsu.union(idx(r, c), idx(r, c + 1)); + if (r + 1 < n && grid[r + 1][c] == 1) + dsu.union(idx(r, c), idx(r + 1, c)); + } + } + } + + for (int r = 0; r < n; r++) { + for (int c = 0; c < n; c++) { + if (grid[r][c] == 1 && dsu.find(idx(r, c)) == firstIsland) { + for (int[] d : direct) { + int nr = r + d[0], nc = c + d[1]; + if (nr >= 0 && nc >= 0 && nr < n && nc < n && grid[nr][nc] == 0) { + q.offer(new int[]{r, c}); + break; + } + } + } + } + } + + int res = 0; + while (!q.isEmpty()) { + for (int i = q.size(); i > 0; i--) { + int[] cell = q.poll(); + int r = cell[0], c = cell[1]; + + for (int[] d : direct) { + int nr = r + d[0], nc = c + d[1]; + if (nr >= 0 && nc >= 0 && nr < n && nc < n) { + if (grid[nr][nc] == 1 && dsu.union(idx(r, c), idx(nr, nc))) { + return res; + } + if (grid[nr][nc] == 0) { + grid[nr][nc] = 1; + dsu.union(idx(r, c), idx(nr, nc)); + q.offer(new int[]{nr, nc}); + } + } + } + } + res++; + } + return res; + } +} +``` + +```cpp +class DSU { +public: + vector parent, rank; + + DSU(int n) : parent(n), rank(n, 1) { + for (int i = 0; i < n; i++) parent[i] = i; + } + + int find(int node) { + if (parent[node] != node) + parent[node] = find(parent[node]); + return parent[node]; + } + + bool unionSet(int u, int v) { + int pu = find(u), pv = find(v); + if (pu == pv) return false; + if (rank[pv] > rank[pu]) swap(pu, pv); + parent[pv] = pu; + rank[pu] += rank[pv]; + return true; + } +}; + +class Solution { +public: + int shortestBridge(vector>& grid) { + int N = grid.size(); + vector> direct = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}}; + DSU dsu(N * N + 1); + queue> q; + + auto idx = [&](int r, int c) { + return r * N + c + 1; + }; + + int firstIsland = -1; + for (int r = 0; r < N; r++) { + for (int c = 0; c < N; c++) { + if (grid[r][c] == 1) { + firstIsland = dsu.find(idx(r, c)); + if (c + 1 < N && grid[r][c + 1] == 1) + dsu.unionSet(idx(r, c), idx(r, c + 1)); + if (r + 1 < N && grid[r + 1][c] == 1) + dsu.unionSet(idx(r, c), idx(r + 1, c)); + } + } + } + + for (int r = 0; r < N; r++) { + for (int c = 0; c < N; c++) { + if (grid[r][c] == 1 && dsu.find(idx(r, c)) == firstIsland) { + for (auto& d : direct) { + int nr = r + d[0], nc = c + d[1]; + if (nr >= 0 && nc >= 0 && nr < N && nc < N && grid[nr][nc] == 0) { + q.push({r, c}); + break; + } + } + } + } + } + + int res = 0; + while (!q.empty()) { + for (int i = q.size(); i > 0; i--) { + auto [r, c] = q.front();q.pop(); + for (auto& d : direct) { + int nr = r + d[0], nc = c + d[1]; + if (nr >= 0 && nc >= 0 && nr < N && nc < N) { + if (grid[nr][nc] == 1 && dsu.unionSet(idx(r, c), idx(nr, nc))) + return res; + if (grid[nr][nc] == 0) { + grid[nr][nc] = 1; + dsu.unionSet(idx(r, c), idx(nr, nc)); + q.push({nr, nc}); + } + } + } + } + res++; + } + return res; + } +}; +``` + +```javascript +class DSU { + /** + * @constructor + * @param {number} n + */ + constructor(n) { + this.parent = Array.from({ length: n }, (_, i) => i); + this.rank = Array(n).fill(1); + } + + /** + * @param {number} node + * @return {number} + */ + find(node) { + if (this.parent[node] !== node) { + this.parent[node] = this.find(this.parent[node]); + } + return this.parent[node]; + } + + /** + * @param {number} u + * @param {number} v + * @return {boolean} + */ + union(u, v) { + let pu = this.find(u), + pv = this.find(v); + if (pu === pv) return false; + + if (this.rank[pv] > this.rank[pu]) [pu, pv] = [pv, pu]; + this.parent[pv] = pu; + this.rank[pu] += this.rank[pv]; + return true; + } +} + +class Solution { + /** + * @param {number[][]} grid + * @return {number} + */ + shortestBridge(grid) { + const N = grid.length; + const direct = [[0, 1], [0, -1], [1, 0], [-1, 0]]; + const dsu = new DSU(N * N + 1); + const q = new Queue(); + + const idx = (r, c) => r * N + c + 1; + + let firstIsland = -1; + for (let r = 0; r < N; r++) { + for (let c = 0; c < N; c++) { + if (grid[r][c] === 1) { + firstIsland = dsu.find(idx(r, c)); + if (c + 1 < N && grid[r][c + 1] === 1) + dsu.union(idx(r, c), idx(r, c + 1)); + if (r + 1 < N && grid[r + 1][c] === 1) + dsu.union(idx(r, c), idx(r + 1, c)); + } + } + } + + + for (let r = 0; r < N; r++) { + for (let c = 0; c < N; c++) { + if (grid[r][c] === 1 && dsu.find(idx(r, c)) === firstIsland) { + for (const [dx, dy] of direct) { + let nr = r + dx, + nc = c + dy; + if (nr >= 0 && nc >= 0 && nr < N && nc < N && grid[nr][nc] === 0) { + q.push([r, c]); + break; + } + } + } + } + } + + let res = 0; + while (!q.isEmpty()) { + for (let i = q.size(); i > 0; i--) { + const [r, c] = q.pop(); + for (let [dx, dy] of direct) { + let nr = r + dx, + nc = c + dy; + if (nr >= 0 && nc >= 0 && nr < N && nc < N) { + if (grid[nr][nc] === 1 && dsu.union(idx(r, c), idx(nr, nc))) { + return res; + } + if (grid[nr][nc] === 0) { + grid[nr][nc] = 1; + dsu.union(idx(r, c), idx(nr, nc)); + q.push([nr, nc]); + } + } + } + } + res++; + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 2)$ +* Space complexity: $O(n ^ 2)$ \ No newline at end of file diff --git a/articles/shortest-path-in-binary-matrix.md b/articles/shortest-path-in-binary-matrix.md new file mode 100644 index 000000000..c0a87d383 --- /dev/null +++ b/articles/shortest-path-in-binary-matrix.md @@ -0,0 +1,475 @@ +## 1. Breadth First Search + +::tabs-start + +```python +class Solution: + def shortestPathBinaryMatrix(self, grid: list[list[int]]) -> int: + N = len(grid) + if grid[0][0] or grid[N - 1][N - 1]: + return -1 + + q = deque([(0, 0, 1)]) + visit = set((0, 0)) + direct = [(0, 1), (1, 0), (0, -1), (-1, 0), + (1, 1), (-1, -1), (1, -1), (-1, 1)] + + while q: + r, c, length = q.popleft() + if r == N - 1 and c == N - 1: + return length + + for dr, dc in direct: + nr, nc = r + dr, c + dc + if (0 <= nr < N and 0 <= nc < N and grid[nr][nc] == 0 and + (nr, nc) not in visit): + q.append((nr, nc, length + 1)) + visit.add((nr, nc)) + + return -1 +``` + +```java +public class Solution { + public int shortestPathBinaryMatrix(int[][] grid) { + int N = grid.length; + if (grid[0][0] == 1 || grid[N - 1][N - 1] == 1) return -1; + + int[][] directions = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}, + {1, 1}, {-1, -1}, {1, -1}, {-1, 1}}; + boolean[][] visit = new boolean[N][N]; + + Queue q = new LinkedList<>(); + q.offer(new int[]{0, 0, 1}); + visit[0][0] = true; + + while (!q.isEmpty()) { + int[] cell = q.poll(); + int r = cell[0], c = cell[1], length = cell[2]; + + if (r == N - 1 && c == N - 1) return length; + + for (int[] d : directions) { + int nr = r + d[0], nc = c + d[1]; + if (nr >= 0 && nc >= 0 && nr < N && nc < N && + grid[nr][nc] == 0 && !visit[nr][nc]) { + q.offer(new int[]{nr, nc, length + 1}); + visit[nr][nc] = true; + } + } + } + return -1; + } +} +``` + +```cpp +class Solution { +public: + int shortestPathBinaryMatrix(vector>& grid) { + int N = grid.size(); + if (grid[0][0] == 1 || grid[N - 1][N - 1] == 1) return -1; + + vector> directions = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}, + {1, 1}, {-1, -1}, {1, -1}, {-1, 1}}; + vector> visit(N, vector(N, false)); + + queue> q; + q.push({0, 0, 1}); + visit[0][0] = true; + + while (!q.empty()) { + auto [r, c, length] = q.front(); + q.pop(); + + if (r == N - 1 && c == N - 1) return length; + + for (auto [dr, dc] : directions) { + int nr = r + dr, nc = c + dc; + if (nr >= 0 && nc >= 0 && nr < N && nc < N && + grid[nr][nc] == 0 && !visit[nr][nc]) { + q.push({nr, nc, length + 1}); + visit[nr][nc] = true; + } + } + } + return -1; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} grid + * @return {number} + */ + shortestPathBinaryMatrix(grid) { + const N = grid.length; + if (grid[0][0] === 1 || grid[N - 1][N - 1] === 1) return -1; + + const directions = [ + [0, 1], [1, 0], [0, -1], [-1, 0], + [1, 1], [-1, -1], [1, -1], [-1, 1] + ]; + const visit = Array.from({ length: N }, () => + Array(N).fill(false) + ); + + const q = new Queue([[0, 0, 1]]); + visit[0][0] = true; + + while (!q.isEmpty()) { + const [r, c, length] = q.pop(); + if (r === N - 1 && c === N - 1) return length; + + for (const [dr, dc] of directions) { + const nr = r + dr, nc = c + dc; + if (nr >= 0 && nc >= 0 && nr < N && nc < N && + grid[nr][nc] === 0 && !visit[nr][nc]) { + q.push([nr, nc, length + 1]); + visit[nr][nc] = true; + } + } + } + return -1; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 2)$ +* Space complexity: $O(n ^ 2)$ + +--- + +## 2. Breadth First Search (Overwriting the Input) + +::tabs-start + +```python +class Solution: + def shortestPathBinaryMatrix(self, grid: list[list[int]]) -> int: + N = len(grid) + direct = [0, 1, 0, -1, 0, 1, 1, -1, -1, 1] + + if grid[0][0] or grid[N - 1][N - 1]: + return -1 + + q = deque([(0, 0)]) + grid[0][0] = 1 + + while q: + r, c = q.popleft() + dist = grid[r][c] + + if r == N - 1 and c == N - 1: + return dist + + for d in range(9): + nr, nc = r + direct[d], c + direct[d + 1] + if 0 <= nr < N and 0 <= nc < N and grid[nr][nc] == 0: + grid[nr][nc] = dist + 1 + q.append((nr, nc)) + + return -1 +``` + +```java +public class Solution { + public int shortestPathBinaryMatrix(int[][] grid) { + int N = grid.length; + int[] direct = {0, 1, 0, -1, 0, 1, 1, -1, -1, 1}; + + if (grid[0][0] == 1 || grid[N - 1][N - 1] == 1) + return -1; + + Queue q = new LinkedList<>(); + q.offer(new int[]{0, 0}); + grid[0][0] = 1; + + while (!q.isEmpty()) { + int[] cell = q.poll(); + int r = cell[0], c = cell[1]; + int dist = grid[r][c]; + + if (r == N - 1 && c == N - 1) + return dist; + + for (int d = 0; d < 9; d++) { + int nr = r + direct[d], nc = c + direct[d + 1]; + + if (nr >= 0 && nc >= 0 && nr < N && nc < N && grid[nr][nc] == 0) { + grid[nr][nc] = dist + 1; + q.offer(new int[]{nr, nc}); + } + } + } + + return -1; + } +} +``` + +```cpp +class Solution { +public: + int shortestPathBinaryMatrix(vector>& grid) { + int N = grid.size(); + int direct[10] = {0, 1, 0, -1, 0, 1, 1, -1, -1, 1}; + + if (grid[0][0] || grid[N - 1][N - 1]) + return -1; + + queue> q; + q.push({0, 0}); + grid[0][0] = 1; + + while (!q.empty()) { + auto [r, c] = q.front(); + q.pop(); + int dist = grid[r][c]; + + if (r == N - 1 && c == N - 1) + return dist; + + for (int d = 0; d < 9; d++) { + int nr = r + direct[d], nc = c + direct[d + 1]; + + if (nr >= 0 && nc >= 0 && nr < N && nc < N && grid[nr][nc] == 0) { + grid[nr][nc] = dist + 1; + q.push({nr, nc}); + } + } + } + + return -1; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} grid + * @return {number} + */ + shortestPathBinaryMatrix(grid) { + const N = grid.length; + const direct = [0, 1, 0, -1, 0, 1, 1, -1, -1, 1]; + + if (grid[0][0] || grid[N - 1][N - 1]) + return -1; + + let q = [[0, 0]]; + grid[0][0] = 1; + + while (q.length) { + let [r, c] = q.shift(); + let dist = grid[r][c]; + + if (r === N - 1 && c === N - 1) + return dist; + + for (let d = 0; d < 9; d++) { + let nr = r + direct[d], nc = c + direct[d + 1]; + + if (nr >= 0 && nc >= 0 && nr < N && nc < N && grid[nr][nc] === 0) { + grid[nr][nc] = dist + 1; + q.push([nr, nc]); + } + } + } + + return -1; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 2)$ +* Space complexity: $O(n ^ 2)$ + +--- + +## 3. Bidirectional Breadth First Search + +::tabs-start + +```python +class Solution: + def shortestPathBinaryMatrix(self, grid: list[list[int]]) -> int: + N = len(grid) + if grid[0][0] or grid[N - 1][N - 1]: + return -1 + if N == 1: + return 1 + + direct = [0, 1, 0, -1, 0, 1, 1, -1, -1, 1] + q1 = deque([(0, 0)]) + q2 = deque([(N - 1, N - 1)]) + grid[0][0] = -1 + grid[N - 1][N - 1] = -2 + + res = 2 + start, end = -1, -2 + while q1 and q2: + for _ in range(len(q1)): + r, c = q1.popleft() + for d in range(9): + nr, nc = r + direct[d], c + direct[d + 1] + if 0 <= nr < N and 0 <= nc < N: + if grid[nr][nc] == end: + return res + if grid[nr][nc] == 0: + grid[nr][nc] = start + q1.append((nr, nc)) + + q1, q2 = q2, q1 + start, end = end, start + res += 1 + + return -1 +``` + +```java +public class Solution { + public int shortestPathBinaryMatrix(int[][] grid) { + int N = grid.length; + if (grid[0][0] == 1 || grid[N - 1][N - 1] == 1) return -1; + if (N == 1) return 1; + + int[] direct = {0, 1, 0, -1, 0, 1, 1, -1, -1, 1}; + Queue q1 = new LinkedList<>(), q2 = new LinkedList<>(); + q1.offer(new int[]{0, 0}); + q2.offer(new int[]{N - 1, N - 1}); + grid[0][0] = -1; + grid[N - 1][N - 1] = -2; + + int res = 2, start = -1, end = -2; + while (!q1.isEmpty() && !q2.isEmpty()) { + for (int i = q1.size(); i > 0; i--) { + int[] cell = q1.poll(); + int r = cell[0], c = cell[1]; + + for (int d = 0; d < 9; d++) { + int nr = r + direct[d], nc = c + direct[d + 1]; + if (nr >= 0 && nc >= 0 && nr < N && nc < N) { + if (grid[nr][nc] == end) return res; + if (grid[nr][nc] == 0) { + grid[nr][nc] = start; + q1.offer(new int[]{nr, nc}); + } + } + } + } + Queue temp = q1; + q1 = q2; + q2 = temp; + int tempVal = start; + start = end; + end = tempVal; + res++; + } + + return -1; + } +} +``` + +```cpp +class Solution { +public: + int shortestPathBinaryMatrix(vector>& grid) { + int N = grid.size(); + if (grid[0][0] || grid[N - 1][N - 1]) return -1; + if (N == 1) return 1; + + int direct[10] = {0, 1, 0, -1, 0, 1, 1, -1, -1, 1}; + queue> q1, q2; + q1.push({0, 0}); + q2.push({N - 1, N - 1}); + grid[0][0] = -1; + grid[N - 1][N - 1] = -2; + + int res = 2, start = -1, end = -2; + while (!q1.empty() && !q2.empty()) { + for (int i = q1.size(); i > 0; i--) { + auto [r, c] = q1.front(); + q1.pop(); + + for (int d = 0; d < 9; d++) { + int nr = r + direct[d], nc = c + direct[d + 1]; + if (nr >= 0 && nc >= 0 && nr < N && nc < N) { + if (grid[nr][nc] == end) return res; + if (grid[nr][nc] == 0) { + grid[nr][nc] = start; + q1.push({nr, nc}); + } + } + } + } + swap(q1, q2); + swap(start, end); + res++; + } + + return -1; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} grid + * @return {number} + */ + shortestPathBinaryMatrix(grid) { + const N = grid.length; + if (grid[0][0] || grid[N - 1][N - 1]) return -1; + if (N === 1) return 1; + + const direct = [0, 1, 0, -1, 0, 1, 1, -1, -1, 1]; + let q1 = new Queue([[0, 0]]); + let q2 = new Queue([[N - 1, N - 1]]); + grid[0][0] = -1; + grid[N - 1][N - 1] = -2; + + let res = 2, start = -1, end = -2; + while (!q1.isEmpty() && !q2.isEmpty()) { + for (let i = q1.size(); i > 0; i--) { + const [r, c] = q1.pop(); + for (let d = 0; d < 9; d++) { + let nr = r + direct[d], nc = c + direct[d + 1]; + if (nr >= 0 && nc >= 0 && nr < N && nc < N) { + if (grid[nr][nc] === end) return res; + if (grid[nr][nc] === 0) { + grid[nr][nc] = start; + q1.push([nr, nc]); + } + } + } + } + [q1, q2] = [q2, q1]; + [start, end] = [end, start]; + res++; + } + + return -1; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 2)$ +* Space complexity: $O(n ^ 2)$ \ No newline at end of file