diff --git a/articles/convert-bst-to-greater-tree.md b/articles/convert-bst-to-greater-tree.md index 9e01d51be..e7e645ac2 100644 --- a/articles/convert-bst-to-greater-tree.md +++ b/articles/convert-bst-to-greater-tree.md @@ -155,6 +155,45 @@ class Solution { } ``` +```csharp +/** + * Definition for a binary tree node. + * public class TreeNode { + * public int val; + * public TreeNode left; + * public TreeNode right; + * public TreeNode(int val=0, TreeNode left=null, TreeNode right=null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public TreeNode ConvertBST(TreeNode root) { + int GetSum(TreeNode node) { + if (node == null) return 0; + return node.val + GetSum(node.left) + GetSum(node.right); + } + + int totalSum = GetSum(root); + + void Dfs(TreeNode node) { + if (node == null) return; + + Dfs(node.left); + int tmp = node.val; + node.val = totalSum; + totalSum -= tmp; + Dfs(node.right); + } + + Dfs(root); + return root; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -299,6 +338,40 @@ class Solution { } ``` +```csharp +/** + * Definition for a binary tree node. + * public class TreeNode { + * public int val; + * public TreeNode left; + * public TreeNode right; + * public TreeNode(int val=0, TreeNode left=null, TreeNode right=null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public TreeNode ConvertBST(TreeNode root) { + int curSum = 0; + + void Dfs(TreeNode node) { + if (node == null) return; + + Dfs(node.right); + int tmp = node.val; + node.val += curSum; + curSum += tmp; + Dfs(node.left); + } + + Dfs(root); + return root; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -448,6 +521,43 @@ class Solution { } ``` +```csharp +/** + * Definition for a binary tree node. + * public class TreeNode { + * public int val; + * public TreeNode left; + * public TreeNode right; + * public TreeNode(int val=0, TreeNode left=null, TreeNode right=null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public TreeNode ConvertBST(TreeNode root) { + int curSum = 0; + Stack stack = new Stack(); + TreeNode node = root; + + while (stack.Count > 0 || node != null) { + while (node != null) { + stack.Push(node); + node = node.right; + } + + node = stack.Pop(); + curSum += node.val; + node.val = curSum; + node = node.left; + } + + return root; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -635,6 +745,53 @@ class Solution { } ``` +```csharp +/** + * Definition for a binary tree node. + * public class TreeNode { + * public int val; + * public TreeNode left; + * public TreeNode right; + * public TreeNode(int val=0, TreeNode left=null, TreeNode right=null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public TreeNode ConvertBST(TreeNode root) { + int curSum = 0; + TreeNode cur = root; + + while (cur != null) { + if (cur.right != null) { + TreeNode prev = cur.right; + while (prev.left != null && prev.left != cur) { + prev = prev.left; + } + + if (prev.left == null) { + prev.left = cur; + cur = cur.right; + } else { + prev.left = null; + curSum += cur.val; + cur.val = curSum; + cur = cur.left; + } + } else { + curSum += cur.val; + cur.val = curSum; + cur = cur.left; + } + } + + return root; + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/find-the-index-of-the-first-occurrence-in-a-string.md b/articles/find-the-index-of-the-first-occurrence-in-a-string.md index beb5b5893..69ca21249 100644 --- a/articles/find-the-index-of-the-first-occurrence-in-a-string.md +++ b/articles/find-the-index-of-the-first-occurrence-in-a-string.md @@ -80,6 +80,27 @@ class Solution { } ``` +```csharp +public class Solution { + public int StrStr(string haystack, string needle) { + int n = haystack.Length, m = needle.Length; + for (int i = 0; i <= n - m; i++) { + int j = 0; + while (j < m) { + if (haystack[i + j] != needle[j]) { + break; + } + j++; + } + if (j == m) { + return i; + } + } + return -1; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -274,6 +295,52 @@ class Solution { } ``` +```csharp +public class Solution { + public int StrStr(string haystack, string needle) { + if (needle == "") return 0; + + int[] lps = new int[needle.Length]; + int prevLPS = 0, i = 1; + + while (i < needle.Length) { + if (needle[i] == needle[prevLPS]) { + lps[i] = prevLPS + 1; + prevLPS++; + i++; + } else if (prevLPS == 0) { + lps[i] = 0; + i++; + } else { + prevLPS = lps[prevLPS - 1]; + } + } + + i = 0; + int j = 0; + + while (i < haystack.Length) { + if (haystack[i] == needle[j]) { + i++; + j++; + } else { + if (j == 0) { + i++; + } else { + j = lps[j - 1]; + } + } + + if (j == needle.Length) { + return i - needle.Length; + } + } + + return -1; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -423,6 +490,41 @@ class Solution { } ``` +```csharp +public class Solution { + public int StrStr(string haystack, string needle) { + if (string.IsNullOrEmpty(needle)) return 0; + + string s = needle + "$" + haystack; + int n = s.Length; + int[] z = new int[n]; + int l = 0, r = 0; + + for (int i = 1; i < n; i++) { + if (i <= r) { + z[i] = Math.Min(r - i + 1, z[i - l]); + } + while (i + z[i] < n && s[z[i]] == s[i + z[i]]) { + z[i]++; + } + if (i + z[i] - 1 > r) { + l = i; + r = i + z[i] - 1; + } + } + + int m = needle.Length; + for (int i = m + 1; i < n; i++) { + if (z[i] == m) { + return i - m - 1; + } + } + + return -1; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -623,6 +725,52 @@ class Solution { } ``` +```csharp +public class Solution { + public int StrStr(string haystack, string needle) { + if (string.IsNullOrEmpty(needle)) return 0; + + int base1 = 31, mod1 = 768258391; + int base2 = 37, mod2 = 685683731; + + int n = haystack.Length, m = needle.Length; + if (m > n) return -1; + + long power1 = 1, power2 = 1; + for (int i = 0; i < m; i++) { + power1 = (power1 * base1) % mod1; + power2 = (power2 * base2) % mod2; + } + + long needleHash1 = 0, needleHash2 = 0; + long haystackHash1 = 0, haystackHash2 = 0; + + for (int i = 0; i < m; i++) { + needleHash1 = (needleHash1 * base1 + needle[i]) % mod1; + needleHash2 = (needleHash2 * base2 + needle[i]) % mod2; + haystackHash1 = (haystackHash1 * base1 + haystack[i]) % mod1; + haystackHash2 = (haystackHash2 * base2 + haystack[i]) % mod2; + } + + for (int i = 0; i <= n - m; i++) { + if (haystackHash1 == needleHash1 && haystackHash2 == needleHash2) { + return i; + } + + if (i + m < n) { + haystackHash1 = (haystackHash1 * base1 - haystack[i] * power1 + haystack[i + m]) % mod1; + haystackHash2 = (haystackHash2 * base2 - haystack[i] * power2 + haystack[i + m]) % mod2; + + if (haystackHash1 < 0) haystackHash1 += mod1; + if (haystackHash2 < 0) haystackHash2 += mod2; + } + } + + return -1; + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/flood-fill.md b/articles/flood-fill.md new file mode 100644 index 000000000..825e87525 --- /dev/null +++ b/articles/flood-fill.md @@ -0,0 +1,276 @@ +## 1. Depth First Search + +::tabs-start + +```python +class Solution: + def floodFill(self, image: List[List[int]], sr: int, sc: int, color: int) -> List[List[int]]: + if image[sr][sc] == color: + return image + + m, n = len(image), len(image[0]) + dirs = [1,0,-1,0,1] + + def dfs(r, c, org): + if not (0 <= r < m) or not (0 <= c < n) or image[r][c] != org: + return + + image[r][c] = color + for d in range(4): + dfs(r + dirs[d], c + dirs[d + 1], org) + + dfs(sr, sc, image[sr][sc]) + return image +``` + +```java +public class Solution { + public int[][] floodFill(int[][] image, int sr, int sc, int color) { + int orig = image[sr][sc]; + if (orig == color) return image; + int m = image.length, n = image[0].length; + dfs(image, sr, sc, orig, color, m, n); + return image; + } + + private void dfs(int[][] image, int r, int c, int orig, int color, int m, int n) { + if (r < 0 || r >= m || c < 0 || c >= n || image[r][c] != orig) return; + image[r][c] = color; + dfs(image, r + 1, c, orig, color, m, n); + dfs(image, r - 1, c, orig, color, m, n); + dfs(image, r, c + 1, orig, color, m, n); + dfs(image, r, c - 1, orig, color, m, n); + } +} +``` + +```cpp +class Solution { +public: + vector> floodFill(vector>& image, int sr, int sc, int color) { + int orig = image[sr][sc]; + if (orig == color) return image; + m = image.size(); + n = image[0].size(); + dfs(image, sr, sc, orig, color); + return image; + } +private: + int m, n; + void dfs(vector>& image, int r, int c, int orig, int color) { + if (r < 0 || r >= m || c < 0 || c >= n || image[r][c] != orig) return; + image[r][c] = color; + dfs(image, r + 1, c, orig, color); + dfs(image, r - 1, c, orig, color); + dfs(image, r, c + 1, orig, color); + dfs(image, r, c - 1, orig, color); + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} image + * @param {number} sr + * @param {number} sc + * @param {number} color + * @return {number[][]} + */ + floodFill(image, sr, sc, color) { + const orig = image[sr][sc]; + if (orig === color) return image; + const m = image.length, n = image[0].length; + const dfs = (r, c) => { + if (r < 0 || r >= m || c < 0 || c >= n || image[r][c] !== orig) return; + image[r][c] = color; + dfs(r + 1, c); + dfs(r - 1, c); + dfs(r, c + 1); + dfs(r, c - 1); + }; + dfs(sr, sc); + return image; + } +} +``` + +```csharp +public class Solution { + public int[][] FloodFill(int[][] image, int sr, int sc, int color) { + int orig = image[sr][sc]; + if (orig == color) return image; + int m = image.Length, n = image[0].Length; + DFS(image, sr, sc, orig, color, m, n); + return image; + } + + private void DFS(int[][] image, int r, int c, int orig, int color, int m, int n) { + if (r < 0 || r >= m || c < 0 || c >= n || image[r][c] != orig) return; + image[r][c] = color; + DFS(image, r + 1, c, orig, color, m, n); + DFS(image, r - 1, c, orig, color, m, n); + DFS(image, r, c + 1, orig, color, m, n); + DFS(image, r, c - 1, orig, color, m, n); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(m * n)$ +* Space complexity: $O(m * n)$ + +> Where $m$ is the number of rows and $n$ is the number of columns in the image. + +--- + +## 2. Breadth First Search + +::tabs-start + +```python +class Solution: + def floodFill(self, image: List[List[int]], sr: int, sc: int, color: int) -> List[List[int]]: + orig = image[sr][sc] + if orig == color: + return image + + m, n = len(image), len(image[0]) + q = deque([(sr, sc)]) + image[sr][sc] = color + dirs = [(1,0), (-1,0), (0,1), (0,-1)] + + while q: + r, c = q.popleft() + for dr, dc in dirs: + nr, nc = r + dr, c + dc + if 0 <= nr < m and 0 <= nc < n and image[nr][nc] == orig: + image[nr][nc] = color + q.append((nr, nc)) + + return image +``` + +```java +public class Solution { + public int[][] floodFill(int[][] image, int sr, int sc, int color) { + int orig = image[sr][sc]; + if (orig == color) return image; + int m = image.length, n = image[0].length; + Deque q = new ArrayDeque<>(); + q.add(new int[]{sr, sc}); + image[sr][sc] = color; + int[][] dirs = {{1,0},{-1,0},{0,1},{0,-1}}; + + while (!q.isEmpty()) { + int[] cell = q.remove(); + int r = cell[0], c = cell[1]; + for (int[] d : dirs) { + int nr = r + d[0], nc = c + d[1]; + if (nr >= 0 && nr < m && nc >= 0 && nc < n && image[nr][nc] == orig) { + image[nr][nc] = color; + q.add(new int[]{nr, nc}); + } + } + } + return image; + } +} +``` + +```cpp +class Solution { +public: + vector> floodFill(vector>& image, int sr, int sc, int color) { + int orig = image[sr][sc]; + if (orig == color) return image; + int m = image.size(), n = image[0].size(); + queue> q; + q.emplace(sr, sc); + image[sr][sc] = color; + int dirs[4][2] = {{1,0},{-1,0},{0,1},{0,-1}}; + + while (!q.empty()) { + auto [r, c] = q.front(); q.pop(); + for (auto &d : dirs) { + int nr = r + d[0], nc = c + d[1]; + if (nr >= 0 && nr < m && nc >= 0 && nc < n && image[nr][nc] == orig) { + image[nr][nc] = color; + q.emplace(nr, nc); + } + } + } + return image; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} image + * @param {number} sr + * @param {number} sc + * @param {number} color + * @return {number[][]} + */ + floodFill(image, sr, sc, color) { + const orig = image[sr][sc]; + if (orig === color) return image; + const m = image.length, n = image[0].length; + const q = new Queue([[sr, sc]]); + image[sr][sc] = color; + const dirs = [[1,0],[-1,0],[0,1],[0,-1]]; + + while (!q.isEmpty()) { + const [r, c] = q.pop(); + for (const [dr, dc] of dirs) { + const nr = r + dr, nc = c + dc; + if (nr >= 0 && nr < m && nc >= 0 && nc < n && image[nr][nc] === orig) { + image[nr][nc] = color; + q.push([nr, nc]); + } + } + } + return image; + } +} +``` + +```csharp +public class Solution { + public int[][] FloodFill(int[][] image, int sr, int sc, int color) { + int orig = image[sr][sc]; + if (orig == color) return image; + int m = image.Length, n = image[0].Length; + var q = new Queue<(int r, int c)>(); + q.Enqueue((sr, sc)); + image[sr][sc] = color; + var dirs = new (int dr, int dc)[] { (1,0), (-1,0), (0,1), (0,-1) }; + + while (q.Count > 0) { + var (r, c) = q.Dequeue(); + foreach (var (dr, dc) in dirs) { + int nr = r + dr, nc = c + dc; + if (nr >= 0 && nr < m && nc >= 0 && nc < n && image[nr][nc] == orig) { + image[nr][nc] = color; + q.Enqueue((nr, nc)); + } + } + } + return image; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(m * n)$ +* Space complexity: $O(m * n)$ + +> Where $m$ is the number of rows and $n$ is the number of columns in the image. \ No newline at end of file diff --git a/articles/frequency-of-the-most-frequent-element.md b/articles/frequency-of-the-most-frequent-element.md index 51c727d97..513f40b38 100644 --- a/articles/frequency-of-the-most-frequent-element.md +++ b/articles/frequency-of-the-most-frequent-element.md @@ -86,6 +86,27 @@ class Solution { } ``` +```csharp +public class Solution { + public int MaxFrequency(int[] nums, int k) { + Array.Sort(nums); + int res = 1; + + for (int i = 0; i < nums.Length; i++) { + int j = i - 1; + long tmpK = k; + + while (j >= 0 && tmpK - (nums[i] - nums[j]) >= 0) { + tmpK -= (nums[i] - nums[j]); + j--; + } + res = Math.Max(res, i - j); + } + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -218,6 +239,36 @@ class Solution { } ``` +```csharp +public class Solution { + public int MaxFrequency(int[] nums, int k) { + Array.Sort(nums); + int n = nums.Length; + long[] prefixSum = new long[n + 1]; + for (int i = 0; i < n; i++) { + prefixSum[i + 1] = prefixSum[i] + nums[i]; + } + + int res = 1; + for (int i = 0; i < n; i++) { + int left = 0, right = i; + while (left <= right) { + int mid = (left + right) / 2; + long curSum = prefixSum[i + 1] - prefixSum[mid]; + long need = (long)(i - mid + 1) * nums[i] - curSum; + if (need <= k) { + res = Math.Max(res, i - mid + 1); + right = mid - 1; + } else { + left = mid + 1; + } + } + } + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -317,6 +368,27 @@ class Solution { } ``` +```csharp +public class Solution { + public int MaxFrequency(int[] nums, int k) { + Array.Sort(nums); + long total = 0; + int res = 0, l = 0; + + for (int r = 0; r < nums.Length; r++) { + total += nums[r]; + while ((long)nums[r] * (r - l + 1) > total + k) { + total -= nums[l]; + l++; + } + res = Math.Max(res, r - l + 1); + } + + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -412,6 +484,26 @@ class Solution { } ``` +```csharp +public class Solution { + public int MaxFrequency(int[] nums, int k) { + Array.Sort(nums); + long total = 0; + int l = 0; + + for (int r = 0; r < nums.Length; r++) { + total += nums[r]; + if ((long)(r - l + 1) * nums[r] > total + k) { + total -= nums[l]; + l++; + } + } + + return nums.Length - l; + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/guess-number-higher-or-lower.md b/articles/guess-number-higher-or-lower.md index 4946e4968..d0ddea8ad 100644 --- a/articles/guess-number-higher-or-lower.md +++ b/articles/guess-number-higher-or-lower.md @@ -238,10 +238,20 @@ class Solution { public class Solution : GuessGame { public int GuessNumber(int n) { - for (int num = 1; num <= n; num++) { - if (guess(num) == 0) return num; + int l = 1, r = n; + while (true) { + int m = l + (r - l) / 2; + int res = guess(m); + if (res > 0) { + l = m + 1; + } + else if (res < 0) { + r = m - 1; + } + else { + return m; + } } - return n; } } ``` diff --git a/articles/intersection-of-two-linked-lists.md b/articles/intersection-of-two-linked-lists.md index 855f2a43f..0d712a869 100644 --- a/articles/intersection-of-two-linked-lists.md +++ b/articles/intersection-of-two-linked-lists.md @@ -108,6 +108,32 @@ class Solution { } ``` +```csharp +/** + * Definition for singly-linked list. + * public class ListNode { + * public int val; + * public ListNode next; + * public ListNode(int x) { val = x; } + * } + */ +public class Solution { + public ListNode GetIntersectionNode(ListNode headA, ListNode headB) { + while (headA != null) { + ListNode cur = headB; + while (cur != null) { + if (headA == cur) { + return headA; + } + cur = cur.next; + } + headA = headA.next; + } + return null; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -252,6 +278,37 @@ class Solution { } ``` +```csharp +/** + * Definition for singly-linked list. + * public class ListNode { + * public int val; + * public ListNode next; + * public ListNode(int x) { val = x; } + * } + */ +public class Solution { + public ListNode GetIntersectionNode(ListNode headA, ListNode headB) { + var nodeSet = new HashSet(); + var cur = headA; + while (cur != null) { + nodeSet.Add(cur); + cur = cur.next; + } + + cur = headB; + while (cur != null) { + if (nodeSet.Contains(cur)) { + return cur; + } + cur = cur.next; + } + + return null; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -440,6 +497,50 @@ class Solution { } ``` +```csharp +/** + * Definition for singly-linked list. + * public class ListNode { + * public int val; + * public ListNode next; + * public ListNode(int x) { val = x; } + * } + */ +public class Solution { + public ListNode GetIntersectionNode(ListNode headA, ListNode headB) { + int GetLength(ListNode head) { + int length = 0; + while (head != null) { + length++; + head = head.next; + } + return length; + } + + int m = GetLength(headA); + int n = GetLength(headB); + ListNode l1 = headA, l2 = headB; + + if (m < n) { + int temp = m; m = n; n = temp; + l1 = headB; + l2 = headA; + } + + for (int i = 0; i < m - n; i++) { + l1 = l1.next; + } + + while (l1 != l2) { + l1 = l1.next; + l2 = l2.next; + } + + return l1; + } +} +``` + ::tabs-end ### Time & Space Complexity @@ -544,6 +645,29 @@ class Solution { } ``` +```csharp +/** + * Definition for singly-linked list. + * public class ListNode { + * public int val; + * public ListNode next; + * public ListNode(int x) { val = x; } + * } + */ +public class Solution { + public ListNode GetIntersectionNode(ListNode headA, ListNode headB) { + ListNode l1 = headA, l2 = headB; + + while (l1 != l2) { + l1 = (l1 != null) ? l1.next : headB; + l2 = (l2 != null) ? l2.next : headA; + } + + return l1; + } +} +``` + ::tabs-end ### Time & Space Complexity diff --git a/articles/kth-smallest-product-of-two-sorted-arrays.md b/articles/kth-smallest-product-of-two-sorted-arrays.md new file mode 100644 index 000000000..7fb3d255b --- /dev/null +++ b/articles/kth-smallest-product-of-two-sorted-arrays.md @@ -0,0 +1,738 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def kthSmallestProduct(self, nums1: List[int], nums2: List[int], k: int) -> int: + prod = [] + + for i in range(len(nums1)): + for j in range(len(nums2)): + prod.append(nums1[i] * nums2[j]) + + prod.sort() + return prod[k - 1] +``` + +```java +public class Solution { + public long kthSmallestProduct(int[] nums1, int[] nums2, long k) { + int n = nums1.length, m = nums2.length; + long[] prod = new long[n * m]; + int idx = 0; + for (int i = 0; i < n; i++) { + for (int j = 0; j < m; j++) { + prod[idx++] = 1L * nums1[i] * nums2[j]; + } + } + Arrays.sort(prod); + return prod[(int)k - 1]; + } +} +``` + +```cpp +class Solution { +public: + long long kthSmallestProduct(vector& nums1, vector& nums2, long long k) { + int n = nums1.size(), m = nums2.size(); + vector prod; + prod.reserve((size_t)n * m); + for (int x : nums1) { + for (int y : nums2) { + prod.push_back(1LL * x * y); + } + } + sort(prod.begin(), prod.end()); + return prod[k - 1]; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums1 + * @param {number[]} nums2 + * @param {number} k + * @return {number} + */ + kthSmallestProduct(nums1, nums2, k) { + const prod = []; + for (let x of nums1) { + for (let y of nums2) { + prod.push(x * y); + } + } + prod.sort((a, b) => a - b); + return prod[k - 1]; + } +} +``` + +```csharp +public class Solution { + public long KthSmallestProduct(int[] nums1, int[] nums2, long k) { + int n = nums1.Length, m = nums2.Length; + long[] prod = new long[n * m]; + int idx = 0; + for (int i = 0; i < n; i++) { + for (int j = 0; j < m; j++) { + prod[idx++] = (long)nums1[i] * nums2[j]; + } + } + Array.Sort(prod); + return prod[k - 1]; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(m * n)$ +* Space complexity: $O(m * n)$ + +> Where $m$ and $n$ are the lengths of the arrays $nums1$ and $nums2$, respectively. + +--- + +## 2. Binary Search + +::tabs-start + +```python +class Solution: + def kthSmallestProduct(self, nums1: List[int], nums2: List[int], k: int) -> int: + def count(prod): + cnt = 0 + n2 = len(nums2) + for a in nums1: + if a > 0: + cnt += bisect.bisect_right(nums2, prod // a) + elif a < 0: + threshold = math.ceil(prod / a) + idx = bisect.bisect_left(nums2, threshold) + cnt += n2 - idx + else: + if prod >= 0: + cnt += n2 + return cnt + + + l, r = -(10**10), 10**10 + while l <= r: + m = l + (r - l) // 2 + if count(m) < k: + l = m + 1 + else: + r = m - 1 + return l +``` + +```java +public class Solution { + public long kthSmallestProduct(int[] nums1, int[] nums2, long k) { + long left = -10_000_000_000L, right = 10_000_000_000L; + while (left <= right) { + long mid = left + (right - left) / 2; + if (count(nums1, nums2, mid) < k) { + left = mid + 1; + } else { + right = mid - 1; + } + } + return left; + } + + private long count(int[] nums1, int[] nums2, long prod) { + long cnt = 0; + int n2 = nums2.length; + for (int a : nums1) { + if (a > 0) { + long bound = Math.floorDiv(prod, a); + cnt += upperBound(nums2, bound); + } else if (a < 0) { + double div = (double) prod / a; + long threshold = (long) Math.ceil(div); + cnt += n2 - lowerBound(nums2, threshold); + } else { + if (prod >= 0) { + cnt += n2; + } + } + } + return cnt; + } + + private int lowerBound(int[] arr, long target) { + int l = 0, r = arr.length; + while (l < r) { + int m = (l + r) / 2; + if (arr[m] < target) l = m + 1; + else r = m; + } + return l; + } + + private int upperBound(int[] arr, long target) { + int l = 0, r = arr.length; + while (l < r) { + int m = (l + r) / 2; + if (arr[m] <= target) l = m + 1; + else r = m; + } + return l; + } +} +``` + +```cpp +class Solution { +public: + long long kthSmallestProduct(vector& nums1, vector& nums2, long long k) { + long long left = -10000000000LL, right = 10000000000LL; + while (left <= right) { + long long mid = left + (right - left) / 2; + if (count(nums1, nums2, mid) < k) left = mid + 1; + else right = mid - 1; + } + return left; + } + +private: + long long count(vector& nums1, vector& nums2, long long prod) { + long long cnt = 0; + int n2 = nums2.size(); + for (int a : nums1) { + if (a > 0) { + long long bound = prod >= 0 + ? prod / a + : -(( -prod + a - 1) / a); + cnt += upper_bound(nums2.begin(), nums2.end(), bound) - nums2.begin(); + } else if (a < 0) { + long long threshold = (long long)ceil((long double)prod / a); + cnt += n2 - (lower_bound(nums2.begin(), nums2.end(), threshold) - nums2.begin()); + } else { + if (prod >= 0) cnt += n2; + } + } + return cnt; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums1 + * @param {number[]} nums2 + * @param {number} k + * @return {number} + */ + kthSmallestProduct(nums1, nums2, k) { + const lowerBound = (arr, target) => { + let l = 0, r = arr.length; + while (l < r) { + const m = (l + r) >>> 1; + if (arr[m] < target) l = m + 1; + else r = m; + } + return l; + }; + + const upperBound = (arr, target) => { + let l = 0, r = arr.length; + while (l < r) { + const m = (l + r) >>> 1; + if (arr[m] <= target) l = m + 1; + else r = m; + } + return l; + }; + + let left = -1e10, right = 1e10; + const n2 = nums2.length; + while (left < right) { + const mid = Math.floor((left + right) / 2); + let cnt = 0; + for (const a of nums1) { + if (a > 0) { + cnt += upperBound(nums2, Math.floor(mid / a)); + } else if (a < 0) { + cnt += n2 - lowerBound(nums2, Math.ceil(mid / a)); + } else if (mid >= 0) { + cnt += n2; + } + if (cnt >= k) break; + } + if (cnt < k) left = mid + 1; + else right = mid; + } + return left; + } +} +``` + +```csharp +public class Solution { + public long KthSmallestProduct(int[] nums1, int[] nums2, long k) { + long left = -10000000000L, right = 10000000000L; + while (left <= right) { + long mid = left + (right - left) / 2; + if (Count(nums1, nums2, mid) < k) left = mid + 1; + else right = mid - 1; + } + return left; + } + + private long Count(int[] nums1, int[] nums2, long prod) { + long cnt = 0; + int n2 = nums2.Length; + foreach (int a in nums1) { + if (a > 0) { + long bound = prod >= 0 + ? prod / a + : -(( -prod + a - 1) / a); + cnt += UpperBound(nums2, bound); + } else if (a < 0) { + long threshold = (long)Math.Ceiling((double)prod / a); + cnt += n2 - LowerBound(nums2, threshold); + } else { + if (prod >= 0) cnt += n2; + } + } + return cnt; + } + + private int LowerBound(int[] arr, long target) { + int l = 0, r = arr.Length; + while (l < r) { + int m = (l + r) >> 1; + if (arr[m] < target) l = m + 1; + else r = m; + } + return l; + } + + private int UpperBound(int[] arr, long target) { + int l = 0, r = arr.Length; + while (l < r) { + int m = (l + r) >> 1; + if (arr[m] <= target) l = m + 1; + else r = m; + } + return l; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(m \log (\log N))$ +* Space complexity: $O(1)$ + +> Where $m$ and $n$ are the lengths of the arrays $nums1$ and $nums2$, respectively. $N$ is the size of the range of the product. + +--- + +## 3. Binary Search + Two Pointers + +::tabs-start + +```python +class Solution: + def kthSmallestProduct(self, nums1: List[int], nums2: List[int], k: int) -> int: + n1, n2 = len(nums1), len(nums2) + pos1 = 0 # first non-negative in nums1 + while pos1 < n1 and nums1[pos1] < 0: + pos1 += 1 + + pos2 = 0 # first non-negative in nums2 + while pos2 < n2 and nums2[pos2] < 0: + pos2 += 1 + + def count(prod): + cnt = 0 + + # negative * negative -> positive + i, j = 0, pos2 - 1 + while i < pos1 and j >= 0: + if nums1[i] * nums2[j] > prod: + i += 1 + else: + cnt += (pos1 - i) + j -= 1 + + # positive * positive -> positive + i, j = pos1, n2 - 1 + while i < n1 and j >= pos2: + if nums1[i] * nums2[j] > prod: + j -= 1 + else: + cnt += (j - pos2 + 1) + i += 1 + + # negative * positive -> negative + i, j = 0, pos2 + while i < pos1 and j < n2: + if nums1[i] * nums2[j] > prod: + j += 1 + else: + cnt += (n2 - j) + i += 1 + + # positive * negative → negative + i, j = pos1, 0 + while i < n1 and j < pos2: + if nums1[i] * nums2[j] > prod: + i += 1 + else: + cnt += (n1 - i) + j += 1 + + return cnt + + left, right = -10**10, 10**10 + while left <= right: + mid = (left + right) // 2 + if count(mid) < k: + left = mid + 1 + else: + right = mid - 1 + + return left +``` + +```java +public class Solution { + public long kthSmallestProduct(int[] nums1, int[] nums2, long k) { + int n1 = nums1.length, n2 = nums2.length; + int pos1 = 0; // first non-negative in nums1 + while (pos1 < n1 && nums1[pos1] < 0) { + pos1++; + } + int pos2 = 0; // first non-negative in nums2 + while (pos2 < n2 && nums2[pos2] < 0) { + pos2++; + } + + long left = -10_000_000_000L, right = 10_000_000_000L; + while (left <= right) { + long mid = left + (right - left) / 2; + if (count(nums1, nums2, pos1, pos2, n1, n2, mid) < k) { + left = mid + 1; + } else { + right = mid - 1; + } + } + return left; + } + + private long count(int[] nums1, int[] nums2, + int pos1, int pos2, int n1, int n2, + long prod) { + long cnt = 0; + + // negative * negative -> positive + int i = 0, j = pos2 - 1; + while (i < pos1 && j >= 0) { + if ((long)nums1[i] * nums2[j] > prod) { + i++; + } else { + cnt += (pos1 - i); + j--; + } + } + + // positive * positive -> positive + i = pos1; j = n2 - 1; + while (i < n1 && j >= pos2) { + if ((long)nums1[i] * nums2[j] > prod) { + j--; + } else { + cnt += (j - pos2 + 1); + i++; + } + } + + // negative * positive -> negative + i = 0; j = pos2; + while (i < pos1 && j < n2) { + if ((long)nums1[i] * nums2[j] > prod) { + j++; + } else { + cnt += (n2 - j); + i++; + } + } + + // positive * negative -> negative + i = pos1; j = 0; + while (i < n1 && j < pos2) { + if ((long)nums1[i] * nums2[j] > prod) { + i++; + } else { + cnt += (n1 - i); + j++; + } + } + + return cnt; + } +} +``` + +```cpp +class Solution { +public: + long long kthSmallestProduct(vector& nums1, vector& nums2, long long k) { + int n1 = nums1.size(), n2 = nums2.size(); + int pos1 = 0; // first non-negative in nums1 + while (pos1 < n1 && nums1[pos1] < 0) { + pos1++; + } + int pos2 = 0; // first non-negative in nums2 + while (pos2 < n2 && nums2[pos2] < 0) { + pos2++; + } + + long long left = -10000000000LL, right = 10000000000LL; + while (left <= right) { + long long mid = left + (right - left) / 2; + if (count(nums1, nums2, pos1, pos2, n1, n2, mid) < k) { + left = mid + 1; + } else { + right = mid - 1; + } + } + return left; + } + +private: + long long count(const vector& nums1, const vector& nums2, + int pos1, int pos2, int n1, int n2, + long long prod) { + long long cnt = 0; + + // negative * negative -> positive + int i = 0, j = pos2 - 1; + while (i < pos1 && j >= 0) { + if ((long long)nums1[i] * nums2[j] > prod) { + i++; + } else { + cnt += (pos1 - i); + j--; + } + } + + // positive * positive -> positive + i = pos1; j = n2 - 1; + while (i < n1 && j >= pos2) { + if ((long long)nums1[i] * nums2[j] > prod) { + j--; + } else { + cnt += (j - pos2 + 1); + i++; + } + } + + // negative * positive -> negative + i = 0; j = pos2; + while (i < pos1 && j < n2) { + if ((long long)nums1[i] * nums2[j] > prod) { + j++; + } else { + cnt += (n2 - j); + i++; + } + } + + // positive * negative -> negative + i = pos1; j = 0; + while (i < n1 && j < pos2) { + if ((long long)nums1[i] * nums2[j] > prod) { + i++; + } else { + cnt += (n1 - i); + j++; + } + } + + return cnt; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums1 + * @param {number[]} nums2 + * @param {number} k + * @return {number} + */ + kthSmallestProduct(nums1, nums2, k) { + const n1 = nums1.length, n2 = nums2.length; + + let pos1 = 0; // first non-negative in nums1 + while (pos1 < n1 && nums1[pos1] < 0) { + pos1++; + } + let pos2 = 0; // first non-negative in nums2 + while (pos2 < n2 && nums2[pos2] < 0) { + pos2++; + } + + let left = -1e10, right = 1e10; + while (left <= right) { + const mid = left + Math.floor((right - left) / 2); + let cnt = 0; + + // negative * negative -> positive + let i = 0, j = pos2 - 1; + while (i < pos1 && j >= 0) { + if (nums1[i] * nums2[j] > mid) { + i++; + } else { + cnt += (pos1 - i); + j--; + } + } + + // positive * positive -> positive + i = pos1; j = n2 - 1; + while (i < n1 && j >= pos2) { + if (nums1[i] * nums2[j] > mid) { + j--; + } else { + cnt += (j - pos2 + 1); + i++; + } + } + + // negative * positive -> negative + i = 0; j = pos2; + while (i < pos1 && j < n2) { + if (nums1[i] * nums2[j] > mid) { + j++; + } else { + cnt += (n2 - j); + i++; + } + } + + // positive * negative -> negative + i = pos1; j = 0; + while (i < n1 && j < pos2) { + if (nums1[i] * nums2[j] > mid) { + i++; + } else { + cnt += (n1 - i); + j++; + } + } + + if (cnt < k) { + left = mid + 1; + } else { + right = mid - 1; + } + } + + return left; + } +} +``` + +```csharp +public class Solution { + public long KthSmallestProduct(int[] nums1, int[] nums2, long k) { + int n1 = nums1.Length, n2 = nums2.Length; + int pos1 = 0; // first non-negative in nums1 + while (pos1 < n1 && nums1[pos1] < 0) { + pos1++; + } + int pos2 = 0; // first non-negative in nums2 + while (pos2 < n2 && nums2[pos2] < 0) { + pos2++; + } + + long left = -10000000000L, right = 10000000000L; + while (left <= right) { + long mid = left + (right - left) / 2; + if (count(nums1, nums2, pos1, pos2, n1, n2, mid) < k) { + left = mid + 1; + } else { + right = mid - 1; + } + } + return left; + } + + private long count(int[] nums1, int[] nums2, + int pos1, int pos2, int n1, int n2, + long prod) { + long cnt = 0; + + // negative * negative -> positive + int i = 0, j = pos2 - 1; + while (i < pos1 && j >= 0) { + if ((long)nums1[i] * nums2[j] > prod) { + i++; + } else { + cnt += (pos1 - i); + j--; + } + } + + // positive * positive -> positive + i = pos1; j = n2 - 1; + while (i < n1 && j >= pos2) { + if ((long)nums1[i] * nums2[j] > prod) { + j--; + } else { + cnt += (j - pos2 + 1); + i++; + } + } + + // negative * positive -> negative + i = 0; j = pos2; + while (i < pos1 && j < n2) { + if ((long)nums1[i] * nums2[j] > prod) { + j++; + } else { + cnt += (n2 - j); + i++; + } + } + + // positive * negative -> negative + i = pos1; j = 0; + while (i < n1 && j < pos2) { + if ((long)nums1[i] * nums2[j] > prod) { + i++; + } else { + cnt += (n1 - i); + j++; + } + } + + return cnt; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O((m + n) \log N)$ +* Space complexity: $O(1)$ + +> Where $m$ and $n$ are the lengths of the arrays $nums1$ and $nums2$, respectively. $N$ is the size of the range of the product. \ No newline at end of file diff --git a/articles/lowest-common-ancestor-of-a-binary-tree.md b/articles/lowest-common-ancestor-of-a-binary-tree.md new file mode 100644 index 000000000..d6fdbe8e4 --- /dev/null +++ b/articles/lowest-common-ancestor-of-a-binary-tree.md @@ -0,0 +1,546 @@ +## 1. Depth First Search + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +class Solution: + def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode': + lca = None + + def dfs(node): + nonlocal lca + if not node: + return [False, False] + if lca: + return [False, False] + + left = dfs(node.left) + right = dfs(node.right) + res = [left[0] or right[0] or (node == p), left[1] or right[1] or (node == q)] + if res[0] and res[1] and not lca: + lca = node + + return res + + dfs(root) + return lca +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode(int x) { val = x; } + * } + */ +public class Solution { + private TreeNode lca = null; + + public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { + lca = null; + dfs(root, p, q); + return lca; + } + + private boolean[] dfs(TreeNode node, TreeNode p, TreeNode q) { + if (node == null || lca != null) { + return new boolean[]{false, false}; + } + boolean[] left = dfs(node.left, p, q); + boolean[] right = dfs(node.right, p, q); + boolean foundP = left[0] || right[0] || node == p; + boolean foundQ = left[1] || right[1] || node == q; + if (foundP && foundQ && lca == null) { + lca = node; + } + return new boolean[]{foundP, foundQ}; + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode(int x) : val(x), left(NULL), right(NULL) {} + * }; + */ +class Solution { +public: + TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) { + lca = nullptr; + dfs(root, p, q); + return lca; + } + +private: + TreeNode* lca; + + pair dfs(TreeNode* node, TreeNode* p, TreeNode* q) { + if (!node || lca) { + return {false, false}; + } + auto left = dfs(node->left, p, q); + auto right = dfs(node->right, p, q); + bool foundP = left.first || right.first || node == p; + bool foundQ = left.second || right.second || node == q; + if (foundP && foundQ && !lca) { + lca = node; + } + return {foundP, foundQ}; + } +}; +``` + +```javascript +/** + * // Definition for a Node. + * function Node(val) { + * this.val = val; + * this.left = null; + * this.right = null; + * this.parent = null; + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @param {TreeNode} p + * @param {TreeNode} q + * @return {TreeNode} + */ + lowestCommonAncestor(root, p, q) { + let lca = null; + const dfs = node => { + if (!node || lca) return [false, false]; + const left = dfs(node.left); + const right = dfs(node.right); + const foundP = left[0] || right[0] || node === p; + const foundQ = left[1] || right[1] || node === q; + if (foundP && foundQ && !lca) { + lca = node; + } + return [foundP, foundQ]; + }; + dfs(root); + return lca; + } +} +``` + +```csharp +/** + * Definition for a binary tree node. + * public class TreeNode { + * public int val; + * public TreeNode left; + * public TreeNode right; + * public TreeNode(int x) { val = x; } + * } + */ +public class Solution { + private TreeNode lca = null; + + public TreeNode LowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { + lca = null; + Dfs(root, p, q); + return lca; + } + + private (bool, bool) Dfs(TreeNode node, TreeNode p, TreeNode q) { + if (node == null || lca != null) { + return (false, false); + } + var left = Dfs(node.left, p, q); + var right = Dfs(node.right, p, q); + bool foundP = left.Item1 || right.Item1 || node == p; + bool foundQ = left.Item2 || right.Item2 || node == q; + if (foundP && foundQ && lca == null) { + lca = node; + } + return (foundP, foundQ); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ + +--- + +## 2. Depth First Search (Optimal) + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +class Solution: + def lowestCommonAncestor( + self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode' + ) -> 'TreeNode': + if root is None or root is p or root is q: + return root + + left = self.lowestCommonAncestor(root.left, p, q) + right = self.lowestCommonAncestor(root.right, p, q) + + if left and right: + return root + + return left if left else right +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode(int x) { val = x; } + * } + */ +public class Solution { + public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { + if (root == null || root == p || root == q) { + return root; + } + TreeNode left = lowestCommonAncestor(root.left, p, q); + TreeNode right = lowestCommonAncestor(root.right, p, q); + if (left != null && right != null) { + return root; + } + return left != null ? left : right; + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode(int x) : val(x), left(NULL), right(NULL) {} + * }; + */ +class Solution { +public: + TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) { + if (!root || root == p || root == q) { + return root; + } + TreeNode* left = lowestCommonAncestor(root->left, p, q); + TreeNode* right = lowestCommonAncestor(root->right, p, q); + if (left && right) { + return root; + } + return left ? left : right; + } +}; +``` + +```javascript +/** + * // Definition for a Node. + * function Node(val) { + * this.val = val; + * this.left = null; + * this.right = null; + * this.parent = null; + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @param {TreeNode} p + * @param {TreeNode} q + * @return {TreeNode} + */ + lowestCommonAncestor(root, p, q) { + if (!root || root === p || root === q) { + return root; + } + const left = this.lowestCommonAncestor(root.left, p, q); + const right = this.lowestCommonAncestor(root.right, p, q); + return left && right ? root : (left || right); + } +} +``` + +```csharp +/** + * Definition for a binary tree node. + * public class TreeNode { + * public int val; + * public TreeNode left; + * public TreeNode right; + * public TreeNode(int x) { val = x; } + * } + */ +public class Solution { + public TreeNode LowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { + if (root == null || root == p || root == q) { + return root; + } + TreeNode left = LowestCommonAncestor(root.left, p, q); + TreeNode right = LowestCommonAncestor(root.right, p, q); + if (left != null && right != null) { + return root; + } + return left ?? right; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ + +--- + +## 3. Breadth First Search + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +class Solution: + def lowestCommonAncestor( + self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode' + ) -> 'TreeNode': + parent = {root: None} + queue = deque([root]) + while p not in parent or q not in parent: + node = queue.popleft() + if node.left: + parent[node.left] = node + queue.append(node.left) + if node.right: + parent[node.right] = node + queue.append(node.right) + + ancestors = set() + while p: + ancestors.add(p) + p = parent[p] + + while q not in ancestors: + q = parent[q] + + return q +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode(int x) { val = x; } + * } + */ +public class Solution { + public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { + if (root == null) return null; + Map parent = new HashMap<>(); + Queue queue = new LinkedList<>(); + parent.put(root, null); + queue.add(root); + while (!parent.containsKey(p) || !parent.containsKey(q)) { + TreeNode node = queue.poll(); + if (node.left != null) { + parent.put(node.left, node); + queue.add(node.left); + } + if (node.right != null) { + parent.put(node.right, node); + queue.add(node.right); + } + } + + Set ancestors = new HashSet<>(); + while (p != null) { + ancestors.add(p); + p = parent.get(p); + } + while (!ancestors.contains(q)) { + q = parent.get(q); + } + return q; + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode(int x) : val(x), left(NULL), right(NULL) {} + * }; + */ +class Solution { +public: + TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) { + if (!root) return nullptr; + unordered_map parent; + queue queue; + parent[root] = nullptr; + queue.push(root); + while (!parent.count(p) || !parent.count(q)) { + TreeNode* node = queue.front(); queue.pop(); + if (node->left) { + parent[node->left] = node; + queue.push(node->left); + } + if (node->right) { + parent[node->right] = node; + queue.push(node->right); + } + } + + unordered_set ancestors; + while (p) { + ancestors.insert(p); + p = parent[p]; + } + while (!ancestors.count(q)) { + q = parent[q]; + } + return q; + } +}; +``` + +```javascript +/** + * // Definition for a Node. + * function Node(val) { + * this.val = val; + * this.left = null; + * this.right = null; + * this.parent = null; + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @param {TreeNode} p + * @param {TreeNode} q + * @return {TreeNode} + */ + lowestCommonAncestor(root, p, q) { + if (!root) return null; + const parent = new Map(); + const queue = new Queue([root]); + parent.set(root, null); + while (!parent.has(p) || !parent.has(q)) { + const node = queue.pop(); + if (node.left) { + parent.set(node.left, node); + queue.push(node.left); + } + if (node.right) { + parent.set(node.right, node); + queue.push(node.right); + } + } + + const ancestors = new Set(); + while (p) { + ancestors.add(p); + p = parent.get(p); + } + while (!ancestors.has(q)) { + q = parent.get(q); + } + return q; + } +} +``` + +```csharp +/** + * Definition for a binary tree node. + * public class TreeNode { + * public int val; + * public TreeNode left; + * public TreeNode right; + * public TreeNode(int x) { val = x; } + * } + */ +public class Solution { + public TreeNode LowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { + if (root == null) return null; + var parent = new Dictionary(); + var queue = new Queue(); + parent[root] = null; + queue.Enqueue(root); + while (!parent.ContainsKey(p) || !parent.ContainsKey(q)) { + var node = queue.Dequeue(); + if (node.left != null) { + parent[node.left] = node; + queue.Enqueue(node.left); + } + if (node.right != null) { + parent[node.right] = node; + queue.Enqueue(node.right); + } + } + + var ancestors = new HashSet(); + while (p != null) { + ancestors.Add(p); + p = parent[p]; + } + while (!ancestors.Contains(q)) { + q = parent[q]; + } + return q; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ \ No newline at end of file diff --git a/articles/max-consecutive-ones.md b/articles/max-consecutive-ones.md new file mode 100644 index 000000000..2b067be81 --- /dev/null +++ b/articles/max-consecutive-ones.md @@ -0,0 +1,279 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def findMaxConsecutiveOnes(self, nums: List[int]) -> int: + n, res = len(nums), 0 + + for i in range(n): + cnt = 0 + for j in range(i, n): + if nums[j] == 0: break + cnt += 1 + res = max(res, cnt) + + return res +``` + +```java +public class Solution { + public int findMaxConsecutiveOnes(int[] nums) { + int n = nums.length, res = 0; + for (int i = 0; i < n; i++) { + int cnt = 0; + for (int j = i; j < n; j++) { + if (nums[j] == 0) break; + cnt++; + } + res = Math.max(res, cnt); + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int findMaxConsecutiveOnes(vector& nums) { + int n = nums.size(), res = 0; + for (int i = 0; i < n; i++) { + int cnt = 0; + for (int j = i; j < n; j++) { + if (nums[j] == 0) break; + cnt++; + } + res = max(res, cnt); + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number} + */ + findMaxConsecutiveOnes(nums) { + const n = nums.length; + let res = 0; + for (let i = 0; i < n; i++) { + let cnt = 0; + for (let j = i; j < n; j++) { + if (nums[j] === 0) break; + cnt++; + } + res = Math.max(res, cnt); + } + return res; + } +} +``` + +```csharp +public class Solution { + public int FindMaxConsecutiveOnes(int[] nums) { + int n = nums.Length, res = 0; + for (int i = 0; i < n; i++) { + int cnt = 0; + for (int j = i; j < n; j++) { + if (nums[j] == 0) break; + cnt++; + } + res = Math.Max(res, cnt); + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 2)$ +* Space complexity: $O(1)$ + +--- + +## 2. Iteration - I + +::tabs-start + +```python +class Solution: + def findMaxConsecutiveOnes(self, nums: List[int]) -> int: + res = cnt = 0 + for num in nums: + if num == 0: + res = max(res, cnt) + cnt = 0 + else: + cnt += 1 + + return max(cnt, res) +``` + +```java +public class Solution { + public int findMaxConsecutiveOnes(int[] nums) { + int res = 0, cnt = 0; + for (int num : nums) { + if (num == 0) { + res = Math.max(res, cnt); + cnt = 0; + } else { + cnt++; + } + } + return Math.max(res, cnt); + } +} +``` + +```cpp +class Solution { +public: + int findMaxConsecutiveOnes(vector& nums) { + int res = 0, cnt = 0; + for (int num : nums) { + if (num == 0) { + res = max(res, cnt); + cnt = 0; + } else { + cnt++; + } + } + return max(res, cnt); + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number} + */ + findMaxConsecutiveOnes(nums) { + let res = 0, cnt = 0; + for (const num of nums) { + if (num === 0) { + res = Math.max(res, cnt); + cnt = 0; + } else { + cnt++; + } + } + return Math.max(res, cnt); + } +} +``` + +```csharp +public class Solution { + public int FindMaxConsecutiveOnes(int[] nums) { + int res = 0, cnt = 0; + foreach (int num in nums) { + if (num == 0) { + res = Math.Max(res, cnt); + cnt = 0; + } else { + cnt++; + } + } + return Math.Max(res, cnt); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(1)$ + +--- + +## 3. Iteration - II + +::tabs-start + +```python +class Solution: + def findMaxConsecutiveOnes(self, nums: List[int]) -> int: + res = cnt = 0 + for num in nums: + cnt += 1 if num else -cnt + res = max(res, cnt) + return res +``` + +```java +public class Solution { + public int findMaxConsecutiveOnes(int[] nums) { + int res = 0, cnt = 0; + for (int num : nums) { + cnt = (num == 1) ? cnt + 1 : 0; + res = Math.max(res, cnt); + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int findMaxConsecutiveOnes(vector& nums) { + int res = 0, cnt = 0; + for (int num : nums) { + cnt = num ? cnt + 1 : 0; + res = max(res, cnt); + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number} + */ + findMaxConsecutiveOnes(nums) { + let res = 0, cnt = 0; + for (const num of nums) { + cnt = num === 1 ? cnt + 1 : 0; + res = Math.max(res, cnt); + } + return res; + } +} +``` + +```csharp +public class Solution { + public int FindMaxConsecutiveOnes(int[] nums) { + int res = 0, cnt = 0; + foreach (int num in nums) { + cnt = (num == 1) ? cnt + 1 : 0; + res = Math.Max(res, cnt); + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(1)$ \ No newline at end of file diff --git a/articles/maximize-ysum-by-picking-a-triplet-of-distinct-xvalues.md b/articles/maximize-ysum-by-picking-a-triplet-of-distinct-xvalues.md new file mode 100644 index 000000000..6edca0eb9 --- /dev/null +++ b/articles/maximize-ysum-by-picking-a-triplet-of-distinct-xvalues.md @@ -0,0 +1,435 @@ +## 1. Hash Map + +::tabs-start + +```python +class Solution: + def maxSumDistinctTriplet(self, x: List[int], y: List[int]) -> int: + mp = {} + + for i in range(len(x)): + if x[i] not in mp: + mp[x[i]] = y[i] + + mp[x[i]] = max(mp[x[i]], y[i]) + + return -1 if len(mp) < 3 else sum(sorted(list(mp.values()))[-3:]) +``` + +```java +public class Solution { + public int maxSumDistinctTriplet(int[] x, int[] y) { + Map mp = new HashMap<>(); + for (int i = 0; i < x.length; i++) { + int key = x[i], val = y[i]; + mp.put(key, Math.max(mp.getOrDefault(key, 0), val)); + } + if (mp.size() < 3) return -1; + List vals = new ArrayList<>(mp.values()); + Collections.sort(vals); + int n = vals.size(); + return vals.get(n-1) + vals.get(n-2) + vals.get(n-3); + } +} +``` + +```cpp +class Solution { +public: + int maxSumDistinctTriplet(vector& x, vector& y) { + unordered_map mp; + for (int i = 0; i < x.size(); i++) { + int key = x[i], val = y[i]; + mp[key] = max(mp[key], val); + } + if (mp.size() < 3) return -1; + vector vals; + vals.reserve(mp.size()); + for (auto &p : mp) vals.push_back(p.second); + sort(vals.begin(), vals.end()); + int n = vals.size(); + return vals[n-1] + vals[n-2] + vals[n-3]; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} x + * @param {number[]} y + * @return {number} + */ + maxSumDistinctTriplet(x, y) { + const mp = new Map(); + for (let i = 0; i < x.length; i++) { + const key = x[i], val = y[i]; + mp.set(key, Math.max(mp.get(key) || 0, val)); + } + if (mp.size < 3) return -1; + const vals = Array.from(mp.values()).sort((a, b) => a - b); + const n = vals.length; + return vals[n-1] + vals[n-2] + vals[n-3]; + } +} +``` + +```csharp +public class Solution { + public int MaxSumDistinctTriplet(int[] x, int[] y) { + var mp = new Dictionary(); + for (int i = 0; i < x.Length; i++) { + int key = x[i], val = y[i]; + if (mp.TryGetValue(key, out var existing)) { + mp[key] = Math.Max(existing, val); + } else { + mp[key] = val; + } + } + if (mp.Count < 3) return -1; + var vals = mp.Values.ToList(); + vals.Sort(); + int n = vals.Count; + return vals[n-1] + vals[n-2] + vals[n-3]; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n \log n)$ +* Space complexity: $O(n)$ + +--- + +## 2. Hash Map + Min-Heap + +::tabs-start + +```python +class Solution: + def maxSumDistinctTriplet(self, x: List[int], y: List[int]) -> int: + mp = {} + for xi, yi in zip(x, y): + mp[xi] = max(mp.get(xi, 0), yi) + + minHeap = [] + for val in mp.values(): + heapq.heappush(minHeap, val) + if len(minHeap) > 3: + heapq.heappop(minHeap) + + return -1 if len(minHeap) < 3 else sum(minHeap) +``` + +```java +public class Solution { + public int maxSumDistinctTriplet(int[] x, int[] y) { + Map mp = new HashMap<>(); + for (int i = 0; i < x.length; i++) { + mp.put(x[i], Math.max(mp.getOrDefault(x[i], 0), y[i])); + } + PriorityQueue pq = new PriorityQueue<>(); + for (int val : mp.values()) { + pq.offer(val); + if (pq.size() > 3) { + pq.poll(); + } + } + + if (pq.size() < 3) { + return -1; + } + int sum = 0; + while (!pq.isEmpty()) { + sum += pq.poll(); + } + return sum; + } +} +``` + +```cpp +class Solution { +public: + int maxSumDistinctTriplet(vector& x, vector& y) { + unordered_map mp; + for (int i = 0; i < x.size(); i++) { + mp[x[i]] = max(mp[x[i]], y[i]); + } + priority_queue, greater> pq; + for (auto &p : mp) { + pq.push(p.second); + if (pq.size() > 3) { + pq.pop(); + } + } + + if (pq.size() < 3) return -1; + int sum = 0; + while (!pq.empty()) { + sum += pq.top(); + pq.pop(); + } + return sum; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} x + * @param {number[]} y + * @return {number} + */ + maxSumDistinctTriplet(x, y) { + const mp = new Map(); + for (let i = 0; i < x.length; i++) { + mp.set(x[i], Math.max(mp.get(x[i])||0, y[i])); + } + const heap = new MinPriorityQueue(); + for (const val of mp.values()) { + heap.enqueue(val); + if (heap.size() > 3) { + heap.dequeue(); + } + } + if (heap.size() < 3) { + return -1; + } + return heap.dequeue() + heap.dequeue() + heap.dequeue(); + } +} +``` + +```csharp +public class Solution { + public int MaxSumDistinctTriplet(int[] x, int[] y) { + var mp = new Dictionary(); + for (int i = 0; i < x.Length; i++) { + int key = x[i], val = y[i]; + if (mp.TryGetValue(key, out var prev)) { + mp[key] = Math.Max(prev, val); + } else { + mp[key] = val; + } + } + var pq = new PriorityQueue(); + foreach (var val in mp.Values) { + pq.Enqueue(val, val); + if (pq.Count > 3) { + pq.Dequeue(); + } + } + + if (pq.Count < 3) { + return -1; + } + int sum = 0; + while (pq.Count > 0) { + sum += pq.Dequeue(); + } + return sum; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ + +--- + +## 3. Greedy + +::tabs-start + +```python +class Solution: + def maxSumDistinctTriplet(self, x: List[int], y: List[int]) -> int: + best = [(None, float("-inf"))] * 3 + for xi, yi in zip(x, y): + for i, (xj, yj) in enumerate(best): + if xi == xj: + if yi > yj: + best[i] = (xi, yi) + best.sort(key=lambda t: t[1], reverse=True) + break + else: + if yi > best[0][1]: + best = [(xi, yi), best[0], best[1]] + elif yi > best[1][1]: + best = [best[0], (xi, yi), best[1]] + elif yi > best[2][1]: + best[2] = (xi, yi) + + return sum(v for _, v in best) if best[2][1] > float("-inf") else -1 +``` + +```java +public class Solution { + public int maxSumDistinctTriplet(int[] x, int[] y) { + List best = new ArrayList<>(); + for (int i = 0; i < 3; i++) { + best.add(new int[]{Integer.MIN_VALUE, Integer.MIN_VALUE}); + } + for (int idx = 0; idx < x.length; idx++) { + int xi = x[idx], yi = y[idx]; + boolean updated = false; + for (int i = 0; i < 3; i++) { + if (best.get(i)[0] == xi) { + if (yi > best.get(i)[1]) { + best.get(i)[1] = yi; + best.sort((a, b) -> Integer.compare(b[1], a[1])); + } + updated = true; + break; + } + } + if (updated) continue; + if (yi > best.get(0)[1]) { + best.add(0, new int[]{xi, yi}); + best.remove(3); + } else if (yi > best.get(1)[1]) { + best.add(1, new int[]{xi, yi}); + best.remove(3); + } else if (yi > best.get(2)[1]) { + best.get(2)[1] = yi; + best.get(2)[0] = xi; + } + } + if (best.get(2)[1] == Integer.MIN_VALUE) { + return -1; + } + return best.get(0)[1] + best.get(1)[1] + best.get(2)[1]; + } +} +``` + +```cpp +class Solution { +public: + int maxSumDistinctTriplet(vector& x, vector& y) { + vector> best(3, {INT_MIN, INT_MIN}); + for (int i = 0; i < x.size(); i++) { + int xi = x[i], yi = y[i]; + bool updated = false; + for (int j = 0; j < 3; j++) { + if (best[j].first == xi) { + if (yi > best[j].second) { + best[j].second = yi; + sort(best.begin(), best.end(), + [](auto &a, auto &b){ return a.second > b.second; }); + } + updated = true; + break; + } + } + if (updated) continue; + if (yi > best[0].second) { + best.insert(best.begin(), {xi, yi}); + best.pop_back(); + } else if (yi > best[1].second) { + best.insert(best.begin()+1, {xi, yi}); + best.pop_back(); + } else if (yi > best[2].second) { + best[2] = {xi, yi}; + } + } + if (best[2].second == INT_MIN) return -1; + return best[0].second + best[1].second + best[2].second; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} x + * @param {number[]} y + * @return {number} + */ + maxSumDistinctTriplet(x, y) { + let best = [ + [null, -Infinity], + [null, -Infinity], + [null, -Infinity] + ]; + for (let i = 0; i < x.length; i++) { + const xi = x[i], yi = y[i]; + let updated = false; + for (let j = 0; j < 3; j++) { + if (best[j][0] === xi) { + if (yi > best[j][1]) { + best[j][1] = yi; + best.sort((a, b) => b[1] - a[1]); + } + updated = true; + break; + } + } + if (updated) continue; + if (yi > best[0][1]) { + best = [[xi, yi], best[0], best[1]]; + } else if (yi > best[1][1]) { + best = [best[0], [xi, yi], best[1]]; + } else if (yi > best[2][1]) { + best[2] = [xi, yi]; + } + } + return best[2][1] === -Infinity + ? -1 + : best[0][1] + best[1][1] + best[2][1]; + } +} +``` + +```csharp +public class Solution { + public int MaxSumDistinctTriplet(int[] x, int[] y) { + var best = new List<(int xi, int yi)> { + (int.MinValue, int.MinValue), + (int.MinValue, int.MinValue), + (int.MinValue, int.MinValue) + }; + for (int i = 0; i < x.Length; i++) { + int xi = x[i], yi = y[i]; + bool updated = false; + for (int j = 0; j < 3; j++) { + if (best[j].xi == xi) { + if (yi > best[j].yi) { + best[j] = (xi, yi); + best = best.OrderByDescending(t => t.yi).ToList(); + } + updated = true; + break; + } + } + if (updated) continue; + if (yi > best[0].yi) { + best = new List<(int,int)> { (xi, yi), best[0], best[1] }; + } else if (yi > best[1].yi) { + best = new List<(int,int)> { best[0], (xi, yi), best[1] }; + } else if (yi > best[2].yi) { + best[2] = (xi, yi); + } + } + return best[2].yi == int.MinValue + ? -1 + : best[0].yi + best[1].yi + best[2].yi; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(1)$ \ No newline at end of file diff --git a/articles/maximum-difference-between-even-and-odd-frequency-i.md b/articles/maximum-difference-between-even-and-odd-frequency-i.md new file mode 100644 index 000000000..f151f4fb9 --- /dev/null +++ b/articles/maximum-difference-between-even-and-odd-frequency-i.md @@ -0,0 +1,235 @@ +## 1. Counting + +::tabs-start + +```python +class Solution: + def maxDifference(self, s: str) -> int: + count = Counter(s) + res = float("-inf") + + for odd in count.values(): + if odd % 2 == 0: continue + for even in count.values(): + if even % 2 == 1: continue + res = max(res, odd - even) + + return res +``` + +```java +public class Solution { + public int maxDifference(String s) { + int[] count = new int[26]; + for (char c : s.toCharArray()) { + count[c - 'a']++; + } + + int res = Integer.MIN_VALUE; + for (int odd : count) { + if (odd == 0 || odd % 2 == 0) continue; + for (int even : count) { + if (even == 0 || even % 2 == 1) continue; + res = Math.max(res, odd - even); + } + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int maxDifference(string s) { + vector count(26, 0); + for (char c : s) { + count[c - 'a']++; + } + + int res = INT_MIN; + for (int odd : count) { + if (odd == 0 || odd % 2 == 0) continue; + for (int even : count) { + if (even == 0 || even % 2 == 1) continue; + res = max(res, odd - even); + } + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s + * @return {number} + */ + maxDifference(s) { + const count = new Array(26).fill(0); + for (const c of s) { + count[c.charCodeAt(0) - 'a'.charCodeAt(0)]++; + } + + let res = -Infinity; + for (const odd of count) { + if (odd === 0 || odd % 2 === 0) continue; + for (const even of count) { + if (even === 0 || even % 2 === 1) continue; + res = Math.max(res, odd - even); + } + } + return res; + } +} +``` + +```csharp +public class Solution { + public int MaxDifference(string s) { + int[] count = new int[26]; + foreach (char c in s) { + count[c - 'a']++; + } + + int res = int.MinValue; + foreach (int odd in count) { + if (odd == 0 || odd % 2 == 0) continue; + foreach (int even in count) { + if (even == 0 || even % 2 == 1) continue; + res = Math.Max(res, odd - even); + } + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(1)$ since we have at most $26$ different characters. + +--- + +## 2. Counting (Optimal) + +::tabs-start + +```python +class Solution: + def maxDifference(self, s: str) -> int: + count = Counter(s) + oddMax, evenMin = 0, len(s) + + for cnt in count.values(): + if cnt & 1: + oddMax = max(oddMax, cnt) + else: + evenMin = min(evenMin, cnt) + + return oddMax - evenMin +``` + +```java +public class Solution { + public int maxDifference(String s) { + int[] count = new int[26]; + for (char c : s.toCharArray()) { + count[c - 'a']++; + } + + int oddMax = 0, evenMin = s.length(); + for (int c : count) { + if ((c & 1) == 1) { + oddMax = Math.max(oddMax, c); + } else if (c > 0) { + evenMin = Math.min(evenMin, c); + } + } + + return oddMax - evenMin; + } +} +``` + +```cpp +class Solution { +public: + int maxDifference(string s) { + vector count(26, 0); + for (char c : s) { + count[c - 'a']++; + } + + int oddMax = 0, evenMin = s.length(); + for (int c : count) { + if (c & 1) { + oddMax = max(oddMax, c); + } else if (c > 0) { + evenMin = min(evenMin, c); + } + } + + return oddMax - evenMin; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s + * @return {number} + */ + maxDifference(s) { + const count = new Array(26).fill(0); + for (const c of s) { + count[c.charCodeAt(0) - 'a'.charCodeAt(0)]++; + } + + let oddMax = 0, evenMin = s.length; + for (const c of count) { + if (c & 1) { + oddMax = Math.max(oddMax, c); + } else if (c > 0) { + evenMin = Math.min(evenMin, c); + } + } + + return oddMax - evenMin; + } +} +``` + +```csharp +public class Solution { + public int MaxDifference(string s) { + int[] count = new int[26]; + foreach (char c in s) { + count[c - 'a']++; + } + + int oddMax = 0, evenMin = s.Length; + foreach (int c in count) { + if ((c & 1) == 1) { + oddMax = Math.Max(oddMax, c); + } else if (c > 0) { + evenMin = Math.Min(evenMin, c); + } + } + + return oddMax - evenMin; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(1)$ since we have at most $26$ different characters. \ No newline at end of file diff --git a/articles/maximum-frequency-after-subarray-operation.md b/articles/maximum-frequency-after-subarray-operation.md new file mode 100644 index 000000000..79c12ee17 --- /dev/null +++ b/articles/maximum-frequency-after-subarray-operation.md @@ -0,0 +1,381 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def maxFrequency(self, nums: List[int], k: int) -> int: + n = len(nums) + cntK = nums.count(k) + res = cntK + + for num in range(1, 51): + if num == k: continue + for i in range(n): + tmp, cnt = cntK, 0 + for j in range(i, n): + if nums[j] == num: + cnt += 1 + elif nums[j] == k: + cntK -= 1 + res = max(res, cnt + cntK) + + cntK = tmp + + return res +``` + +```java +public class Solution { + public int maxFrequency(int[] nums, int k) { + int n = nums.length; + int cntK = 0; + for (int x : nums) if (x == k) cntK++; + int res = cntK; + + for (int num = 1; num <= 50; num++) { + if (num == k) continue; + for (int i = 0; i < n; i++) { + int tmp = cntK; + int cnt = 0; + for (int j = i; j < n; j++) { + if (nums[j] == num) { + cnt++; + } else if (nums[j] == k) { + cntK--; + } + res = Math.max(res, cnt + cntK); + } + cntK = tmp; + } + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int maxFrequency(vector& nums, int k) { + int n = nums.size(); + int cntK = 0; + for (int x : nums) if (x == k) cntK++; + int res = cntK; + + for (int num = 1; num <= 50; num++) { + if (num == k) continue; + for (int i = 0; i < n; i++) { + int tmp = cntK, cnt = 0; + for (int j = i; j < n; j++) { + if (nums[j] == num) { + cnt++; + } else if (nums[j] == k) { + cntK--; + } + res = max(res, cnt + cntK); + } + cntK = tmp; + } + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ + maxFrequency(nums, k) { + const n = nums.length; + let cntK = nums.filter(x => x === k).length; + let res = cntK; + + for (let num = 1; num <= 50; num++) { + if (num === k) continue; + for (let i = 0; i < n; i++) { + const tmp = cntK; + let cnt = 0; + for (let j = i; j < n; j++) { + if (nums[j] === num) { + cnt++; + } else if (nums[j] === k) { + cntK--; + } + res = Math.max(res, cnt + cntK); + } + cntK = tmp; + } + } + return res; + } +} +``` + +```csharp +public class Solution { + public int MaxFrequency(int[] nums, int k) { + int n = nums.Length; + int cntK = 0; + foreach (var x in nums) if (x == k) cntK++; + int res = cntK; + + for (int num = 1; num <= 50; num++) { + if (num == k) continue; + for (int i = 0; i < n; i++) { + int tmp = cntK; + int cnt = 0; + for (int j = i; j < n; j++) { + if (nums[j] == num) { + cnt++; + } else if (nums[j] == k) { + cntK--; + } + res = Math.Max(res, cnt + cntK); + } + cntK = tmp; + } + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(50 * n ^ 2)$ +* Space complexity: $O(1)$ + +--- + +## 2. Kadane's Algorithm - I + +::tabs-start + +```python +class Solution: + def maxFrequency(self, nums: List[int], k: int) -> int: + cntK = nums.count(k) + res = 0 + + for i in range(1, 51): + if i == k: + continue + cnt = 0 + for num in nums: + if num == i: + cnt += 1 + if num == k: + cnt -= 1 + cnt = max(cnt, 0) + res = max(res, cntK + cnt) + return res +``` + +```java +public class Solution { + public int maxFrequency(int[] nums, int k) { + int cntK = 0; + for (int num : nums) { + if (num == k) cntK++; + } + int res = 0; + + for (int i = 1; i <= 50; i++) { + if (i == k) continue; + int cnt = 0; + for (int num : nums) { + if (num == i) cnt++; + if (num == k) cnt--; + cnt = Math.max(cnt, 0); + res = Math.max(res, cntK + cnt); + } + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int maxFrequency(vector& nums, int k) { + int cntK = 0; + for (int num : nums) { + if (num == k) cntK++; + } + int res = 0; + + for (int i = 1; i <= 50; i++) { + if (i == k) continue; + int cnt = 0; + for (int num : nums) { + if (num == i) cnt++; + if (num == k) cnt--; + cnt = max(cnt, 0); + res = max(res, cntK + cnt); + } + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ + maxFrequency(nums, k) { + let cntK = 0; + for (const num of nums) { + if (num === k) cntK++; + } + let res = 0; + + for (let i = 1; i <= 50; i++) { + if (i === k) continue; + let cnt = 0; + for (const num of nums) { + if (num === i) cnt++; + if (num === k) cnt--; + cnt = Math.max(cnt, 0); + res = Math.max(res, cntK + cnt); + } + } + return res; + } +} +``` + +```csharp +public class Solution { + public int MaxFrequency(int[] nums, int k) { + int cntK = 0; + foreach (var num in nums) { + if (num == k) cntK++; + } + int res = 0; + + for (int i = 1; i <= 50; i++) { + if (i == k) continue; + int cnt = 0; + foreach (var num in nums) { + if (num == i) cnt++; + if (num == k) cnt--; + cnt = Math.Max(cnt, 0); + res = Math.Max(res, cntK + cnt); + } + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(50 * n)$ +* Space complexity: $O(1)$ + +--- + +## 3. Kadane's Algorithm - II + +::tabs-start + +```python +class Solution: + def maxFrequency(self, nums: List[int], k: int) -> int: + cnt = defaultdict(int) + res = 0 + for num in nums: + cnt[num] = max(cnt[num], cnt[k]) + 1 + res = max(res, cnt[num] - cnt[k]) + return cnt[k] + res +``` + +```java +public class Solution { + public int maxFrequency(int[] nums, int k) { + Map cnt = new HashMap<>(); + int res = 0; + for (int num : nums) { + int prev = Math.max(cnt.getOrDefault(num, 0), cnt.getOrDefault(k, 0)); + cnt.put(num, prev + 1); + res = Math.max(res, cnt.get(num) - cnt.getOrDefault(k, 0)); + } + return cnt.getOrDefault(k, 0) + res; + } +} +``` + +```cpp +class Solution { +public: + int maxFrequency(vector& nums, int k) { + unordered_map cnt; + int res = 0; + for (int num : nums) { + int prev = max(cnt[num], cnt[k]); + cnt[num] = prev + 1; + res = max(res, cnt[num] - cnt[k]); + } + return cnt[k] + res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ + maxFrequency(nums, k) { + const cnt = new Map(); + let res = 0; + for (const num of nums) { + const prev = Math.max(cnt.get(num) || 0, cnt.get(k) || 0); + cnt.set(num, prev + 1); + res = Math.max(res, cnt.get(num) - (cnt.get(k) || 0)); + } + return (cnt.get(k) || 0) + res; + } +} +``` + +```csharp +public class Solution { + public int MaxFrequency(int[] nums, int k) { + var cnt = new Dictionary(); + int res = 0; + foreach (var num in nums) { + int prev = Math.Max( + cnt.TryGetValue(num, out var cn) ? cn : 0, + cnt.TryGetValue(k, out var ck) ? ck : 0 + ); + cnt[num] = prev + 1; + res = Math.Max(res, cnt[num] - (cnt.TryGetValue(k, out ck) ? ck : 0)); + } + return (cnt.TryGetValue(k, out var ckk) ? ckk : 0) + res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(50)$ \ No newline at end of file diff --git a/articles/recover-binary-search-tree.md b/articles/recover-binary-search-tree.md new file mode 100644 index 000000000..8ead7cb15 --- /dev/null +++ b/articles/recover-binary-search-tree.md @@ -0,0 +1,982 @@ +## 1. Brute Force + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def recoverTree(self, root: Optional[TreeNode]) -> None: + """ + Do not return anything, modify root in-place instead. + """ + def isBST(node): + if not node: + return True + + q = deque([(node, float("-inf"), float("inf"))]) + while q: + cur, left, right = q.popleft() + if not (left < cur.val < right): + return False + if cur.left: + q.append((cur.left, left, cur.val)) + if cur.right: + q.append((cur.right, cur.val, right)) + + return True + + def dfs1(node1, node2): + if not node2 or node1 == node2: + return False + + node1.val, node2.val = node2.val, node1.val + if isBST(root): + return True + + node1.val, node2.val = node2.val, node1.val + return dfs1(node1, node2.left) or dfs1(node1, node2.right) + + + def dfs(node): + if not node: + return False + + if dfs1(node, root): + return True + + return dfs(node.left) or dfs(node.right) + + dfs(root) + return root +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public void recoverTree(TreeNode root) { + dfs(root, root); + } + + private boolean dfs(TreeNode node1, TreeNode root) { + if (node1 == null) return false; + if (dfs1(node1, root, root)) return true; + return dfs(node1.left, root) || dfs(node1.right, root); + } + + private boolean dfs1(TreeNode node1, TreeNode node2, TreeNode root) { + if (node2 == null || node1 == node2) return false; + + swap(node1, node2); + if (isBST(root)) return true; + swap(node1, node2); + + return dfs1(node1, node2.left, root) || dfs1(node1, node2.right, root); + } + + private boolean isBST(TreeNode node) { + Queue q = new LinkedList<>(); + q.offer(new Object[]{node, Long.MIN_VALUE, Long.MAX_VALUE}); + + while (!q.isEmpty()) { + Object[] curr = q.poll(); + TreeNode n = (TreeNode) curr[0]; + long left = (long) curr[1]; + long right = (long) curr[2]; + + if (n == null) continue; + if (n.val <= left || n.val >= right) return false; + + q.offer(new Object[]{n.left, left, (long) n.val}); + q.offer(new Object[]{n.right, (long) n.val, right}); + } + + return true; + } + + private void swap(TreeNode a, TreeNode b) { + int tmp = a.val; + a.val = b.val; + b.val = tmp; + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + void recoverTree(TreeNode* root) { + dfs(root, root, root); + } + + bool dfs(TreeNode* node1, TreeNode* node2, TreeNode* root) { + if (!node1) return false; + if (dfs1(node1, node2, root)) return true; + return dfs(node1->left, node2, root) || dfs(node1->right, node2, root); + } + + bool dfs1(TreeNode* node1, TreeNode* node2, TreeNode* root) { + if (!node2 || node1 == node2) return false; + + swap(node1->val, node2->val); + if (isBST(root)) return true; + swap(node1->val, node2->val); + + return dfs1(node1, node2->left, root) || dfs1(node1, node2->right, root); + } + + bool isBST(TreeNode* node) { + TreeNode* prev = nullptr; + return inorder(node, prev); + } + + bool inorder(TreeNode* node, TreeNode*& prev) { + if (!node) return true; + if (!inorder(node->left, prev)) return false; + if (prev && prev->val >= node->val) return false; + prev = node; + return inorder(node->right, prev); + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ + class Solution { + /** + * @param {TreeNode} root + * @return {void} Do not return anything, modify root in-place instead. + */ + recoverTree(root) { + const isBST = (node) => { + const q = [[node, -Infinity, Infinity]]; + while (q.length) { + const [cur, left, right] = q.shift(); + if (!cur) continue; + if (!(left < cur.val && cur.val < right)) return false; + q.push([cur.left, left, cur.val]); + q.push([cur.right, cur.val, right]); + } + return true; + }; + + const dfs1 = (node1, node2) => { + if (!node2 || node1 === node2) return false; + [node1.val, node2.val] = [node2.val, node1.val]; + if (isBST(root)) return true; + [node1.val, node2.val] = [node2.val, node1.val]; + return dfs1(node1, node2.left) || dfs1(node1, node2.right); + }; + + const dfs = (node) => { + if (!node) return false; + if (dfs1(node, root)) return true; + return dfs(node.left) || dfs(node.right); + }; + + dfs(root); + } + } +``` + +```csharp +/** + * Definition for a binary tree node. + * public class TreeNode { + * public int val; + * public TreeNode left; + * public TreeNode right; + * public TreeNode(int val=0, TreeNode left=null, TreeNode right=null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public void RecoverTree(TreeNode root) { + Dfs(root, root); + } + + private bool Dfs(TreeNode node1, TreeNode root) { + if (node1 == null) return false; + if (Dfs1(node1, root, root)) return true; + return Dfs(node1.left, root) || Dfs(node1.right, root); + } + + private bool Dfs1(TreeNode node1, TreeNode node2, TreeNode root) { + if (node2 == null || node1 == node2) return false; + + Swap(node1, node2); + if (IsBST(root)) return true; + Swap(node1, node2); + + return Dfs1(node1, node2.left, root) || Dfs1(node1, node2.right, root); + } + + private bool IsBST(TreeNode node) { + var q = new Queue<(TreeNode node, long min, long max)>(); + q.Enqueue((node, long.MinValue, long.MaxValue)); + + while (q.Count > 0) { + var (cur, min, max) = q.Dequeue(); + if (cur == null) continue; + long val = cur.val; + if (val <= min || val >= max) return false; + + q.Enqueue((cur.left, min, val)); + q.Enqueue((cur.right, val, max)); + } + return true; + } + + private void Swap(TreeNode a, TreeNode b) { + int temp = a.val; + a.val = b.val; + b.val = temp; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 2)$ +* Space complexity: $O(n)$ + +--- + +## 2. Inorder Traversal + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def recoverTree(self, root: Optional[TreeNode]) -> None: + """ + Do not return anything, modify root in-place instead. + """ + arr = [] + def inorder(node): + if not node: + return + + inorder(node.left) + arr.append(node) + inorder(node.right) + + inorder(root) + node1, node2 = None, None + + for i in range(len(arr) - 1): + if arr[i].val > arr[i + 1].val: + node2 = arr[i + 1] + if node1 is None: + node1 = arr[i] + else: + break + node1.val, node2.val = node2.val, node1.val +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public void recoverTree(TreeNode root) { + List arr = new ArrayList<>(); + inorder(root, arr); + + TreeNode node1 = null, node2 = null; + for (int i = 0; i < arr.size() - 1; i++) { + if (arr.get(i).val > arr.get(i + 1).val) { + node2 = arr.get(i + 1); + if (node1 == null) node1 = arr.get(i); + else break; + } + } + + int temp = node1.val; + node1.val = node2.val; + node2.val = temp; + } + + private void inorder(TreeNode node, List arr) { + if (node == null) return; + inorder(node.left, arr); + arr.add(node); + inorder(node.right, arr); + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + void recoverTree(TreeNode* root) { + vector arr; + inorder(root, arr); + + TreeNode* node1 = nullptr; + TreeNode* node2 = nullptr; + + for (int i = 0; i < arr.size() - 1; i++) { + if (arr[i]->val > arr[i + 1]->val) { + node2 = arr[i + 1]; + if (!node1) node1 = arr[i]; + else break; + } + } + + swap(node1->val, node2->val); + } + + void inorder(TreeNode* node, vector& arr) { + if (!node) return; + inorder(node->left, arr); + arr.push_back(node); + inorder(node->right, arr); + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ + class Solution { + /** + * @param {TreeNode} root + * @return {void} Do not return anything, modify root in-place instead. + */ + recoverTree(root) { + const arr = []; + + const inorder = node => { + if (!node) return; + inorder(node.left); + arr.push(node); + inorder(node.right); + }; + + inorder(root); + + let node1 = null, node2 = null; + for (let i = 0; i < arr.length - 1; i++) { + if (arr[i].val > arr[i + 1].val) { + node2 = arr[i + 1]; + if (node1 === null) node1 = arr[i]; + else break; + } + } + + [node1.val, node2.val] = [node2.val, node1.val]; + } + } +``` + +```csharp +/** + * Definition for a binary tree node. + * public class TreeNode { + * public int val; + * public TreeNode left; + * public TreeNode right; + * public TreeNode(int val=0, TreeNode left=null, TreeNode right=null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public void RecoverTree(TreeNode root) { + var arr = new List(); + Inorder(root, arr); + + TreeNode node1 = null, node2 = null; + for (int i = 0; i < arr.Count - 1; i++) { + if (arr[i].val > arr[i + 1].val) { + node2 = arr[i + 1]; + if (node1 == null) node1 = arr[i]; + else break; + } + } + + int temp = node1.val; + node1.val = node2.val; + node2.val = temp; + } + + private void Inorder(TreeNode node, List arr) { + if (node == null) return; + Inorder(node.left, arr); + arr.Add(node); + Inorder(node.right, arr); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ + +--- + +## 3. Iterative Inorder Traversal + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def recoverTree(self, root: Optional[TreeNode]) -> None: + stack = [] + node1 = node2 = prev = None + curr = root + + while stack or curr: + while curr: + stack.append(curr) + curr = curr.left + + curr = stack.pop() + if prev and prev.val > curr.val: + node2 = curr + if not node1: + node1 = prev + else: + break + prev = curr + curr = curr.right + + node1.val, node2.val = node2.val, node1.val +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public void recoverTree(TreeNode root) { + Stack stack = new Stack<>(); + TreeNode node1 = null, node2 = null, prev = null, curr = root; + + while (!stack.isEmpty() || curr != null) { + while (curr != null) { + stack.push(curr); + curr = curr.left; + } + + curr = stack.pop(); + if (prev != null && prev.val > curr.val) { + node2 = curr; + if (node1 == null) node1 = prev; + else break; + } + prev = curr; + curr = curr.right; + } + + int temp = node1.val; + node1.val = node2.val; + node2.val = temp; + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + void recoverTree(TreeNode* root) { + stack stack; + TreeNode *node1 = nullptr, *node2 = nullptr, *prev = nullptr, *curr = root; + + while (!stack.empty() || curr) { + while (curr) { + stack.push(curr); + curr = curr->left; + } + + curr = stack.top(); stack.pop(); + if (prev && prev->val > curr->val) { + node2 = curr; + if (!node1) node1 = prev; + else break; + } + prev = curr; + curr = curr->right; + } + + swap(node1->val, node2->val); + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ + class Solution { + /** + * @param {TreeNode} root + * @return {void} Do not return anything, modify root in-place instead. + */ + recoverTree(root) { + let stack = []; + let node1 = null, node2 = null, prev = null, curr = root; + + while (stack.length > 0 || curr) { + while (curr) { + stack.push(curr); + curr = curr.left; + } + + curr = stack.pop(); + if (prev && prev.val > curr.val) { + node2 = curr; + if (!node1) node1 = prev; + else break; + } + prev = curr; + curr = curr.right; + } + + [node1.val, node2.val] = [node2.val, node1.val]; + } + } +``` + +```csharp +/** + * Definition for a binary tree node. + * public class TreeNode { + * public int val; + * public TreeNode left; + * public TreeNode right; + * public TreeNode(int val=0, TreeNode left=null, TreeNode right=null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public void RecoverTree(TreeNode root) { + var stack = new Stack(); + TreeNode node1 = null, node2 = null, prev = null, curr = root; + + while (stack.Count > 0 || curr != null) { + while (curr != null) { + stack.Push(curr); + curr = curr.left; + } + + curr = stack.Pop(); + if (prev != null && prev.val > curr.val) { + node2 = curr; + if (node1 == null) node1 = prev; + else break; + } + prev = curr; + curr = curr.right; + } + + int temp = node1.val; + node1.val = node2.val; + node2.val = temp; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ + +--- + +## 4. Morris Traversal + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def recoverTree(self, root: Optional[TreeNode]) -> None: + node1 = node2 = prev = None + curr = root + + while curr: + if not curr.left: + if prev and prev.val > curr.val: + node2 = curr + if not node1: + node1 = prev + prev = curr + curr = curr.right + else: + pred = curr.left + while pred.right and pred.right != curr: + pred = pred.right + + if not pred.right: + pred.right = curr + curr = curr.left + else: + pred.right = None + if prev and prev.val > curr.val: + node2 = curr + if not node1: + node1 = prev + prev = curr + curr = curr.right + + node1.val, node2.val = node2.val, node1.val +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public void recoverTree(TreeNode root) { + TreeNode node1 = null, node2 = null, prev = null, curr = root; + + while (curr != null) { + if (curr.left == null) { + if (prev != null && prev.val > curr.val) { + node2 = curr; + if (node1 == null) node1 = prev; + } + prev = curr; + curr = curr.right; + } else { + TreeNode pred = curr.left; + while (pred.right != null && pred.right != curr) { + pred = pred.right; + } + + if (pred.right == null) { + pred.right = curr; + curr = curr.left; + } else { + pred.right = null; + if (prev != null && prev.val > curr.val) { + node2 = curr; + if (node1 == null) node1 = prev; + } + prev = curr; + curr = curr.right; + } + } + } + + int temp = node1.val; + node1.val = node2.val; + node2.val = temp; + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + void recoverTree(TreeNode* root) { + TreeNode* node1 = nullptr; + TreeNode* node2 = nullptr; + TreeNode* prev = nullptr; + TreeNode* curr = root; + + while (curr) { + if (!curr->left) { + if (prev && prev->val > curr->val) { + node2 = curr; + if (!node1) node1 = prev; + } + prev = curr; + curr = curr->right; + } else { + TreeNode* pred = curr->left; + while (pred->right && pred->right != curr) { + pred = pred->right; + } + + if (!pred->right) { + pred->right = curr; + curr = curr->left; + } else { + pred->right = nullptr; + if (prev && prev->val > curr->val) { + node2 = curr; + if (!node1) node1 = prev; + } + prev = curr; + curr = curr->right; + } + } + } + + swap(node1->val, node2->val); + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ + class Solution { + /** + * @param {TreeNode} root + * @return {void} Do not return anything, modify root in-place instead. + */ + recoverTree(root) { + let node1 = null, node2 = null, prev = null, curr = root; + + while (curr !== null) { + if (curr.left === null) { + if (prev !== null && prev.val > curr.val) { + node2 = curr; + if (node1 === null) node1 = prev; + } + prev = curr; + curr = curr.right; + } else { + let pred = curr.left; + while (pred.right !== null && pred.right !== curr) { + pred = pred.right; + } + + if (pred.right === null) { + pred.right = curr; + curr = curr.left; + } else { + pred.right = null; + if (prev !== null && prev.val > curr.val) { + node2 = curr; + if (node1 === null) node1 = prev; + } + prev = curr; + curr = curr.right; + } + } + } + + let temp = node1.val; + node1.val = node2.val; + node2.val = temp; + } + } +``` + +```csharp +/** + * Definition for a binary tree node. + * public class TreeNode { + * public int val; + * public TreeNode left; + * public TreeNode right; + * public TreeNode(int val=0, TreeNode left=null, TreeNode right=null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public void RecoverTree(TreeNode root) { + TreeNode node1 = null, node2 = null, prev = null, curr = root; + + while (curr != null) { + if (curr.left == null) { + if (prev != null && prev.val > curr.val) { + node2 = curr; + if (node1 == null) node1 = prev; + } + prev = curr; + curr = curr.right; + } else { + TreeNode pred = curr.left; + while (pred.right != null && pred.right != curr) { + pred = pred.right; + } + + if (pred.right == null) { + pred.right = curr; + curr = curr.left; + } else { + pred.right = null; + if (prev != null && prev.val > curr.val) { + node2 = curr; + if (node1 == null) node1 = prev; + } + prev = curr; + curr = curr.right; + } + } + } + + int temp = node1.val; + node1.val = node2.val; + node2.val = temp; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(1)$ \ No newline at end of file