diff --git a/problems/0015.三数之和.md b/problems/0015.三数之和.md index adb9a113..6b5311ae 100644 --- a/problems/0015.三数之和.md +++ b/problems/0015.三数之和.md @@ -434,6 +434,46 @@ class Solution { } ``` +Swift: +```swift +// 双指针法 +func threeSum(_ nums: [Int]) -> [[Int]] { + var res = [[Int]]() + var sorted = nums + sorted.sort() + for i in 0 ..< sorted.count { + if sorted[i] > 0 { + return res + } + if i > 0 && sorted[i] == sorted[i - 1] { + continue + } + var left = i + 1 + var right = sorted.count - 1 + while left < right { + let sum = sorted[i] + sorted[left] + sorted[right] + if sum < 0 { + left += 1 + } else if sum > 0 { + right -= 1 + } else { + res.append([sorted[i], sorted[left], sorted[right]]) + + while left < right && sorted[left] == sorted[left + 1] { + left += 1 + } + while left < right && sorted[right] == sorted[right - 1] { + right -= 1 + } + + left += 1 + right -= 1 + } + } + } + return res +} +``` ----------------------- * 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) diff --git a/problems/0018.四数之和.md b/problems/0018.四数之和.md index c81c5df7..9891f0fe 100644 --- a/problems/0018.四数之和.md +++ b/problems/0018.四数之和.md @@ -354,6 +354,54 @@ class Solution { } ``` +Swift: +```swift +func fourSum(_ nums: [Int], _ target: Int) -> [[Int]] { + var res = [[Int]]() + var sorted = nums + sorted.sort() + for k in 0 ..< sorted.count { + // 这种剪枝不行,target可能是负数 +// if sorted[k] > target { +// return res +// } + // 去重 + if k > 0 && sorted[k] == sorted[k - 1] { + continue + } + + let target2 = target - sorted[k] + for i in (k + 1) ..< sorted.count { + if i > (k + 1) && sorted[i] == sorted[i - 1] { + continue + } + var left = i + 1 + var right = sorted.count - 1 + while left < right { + let sum = sorted[i] + sorted[left] + sorted[right] + if sum < target2 { + left += 1 + } else if sum > target2 { + right -= 1 + } else { + res.append([sorted[k], sorted[i], sorted[left], sorted[right]]) + while left < right && sorted[left] == sorted[left + 1] { + left += 1 + } + while left < right && sorted[right] == sorted[right - 1] { + right -= 1 + } + // 找到答案 双指针同时收缩 + left += 1 + right -= 1 + } + } + } + } + return res +} +``` + ----------------------- * 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) * B站视频:[代码随想录](https://space.bilibili.com/525438321) diff --git a/problems/0042.接雨水.md b/problems/0042.接雨水.md index 522b10f9..4383a0b8 100644 --- a/problems/0042.接雨水.md +++ b/problems/0042.接雨水.md @@ -391,6 +391,7 @@ class Solution { } } ``` + 动态规划法 ```java class Solution { @@ -418,6 +419,54 @@ class Solution { } } ``` + +单调栈法 +```java +class Solution { + public int trap(int[] height){ + int size = height.length; + + if (size <= 2) return 0; + + // in the stack, we push the index of array + // using height[] to access the real height + Stack stack = new Stack(); + stack.push(0); + + int sum = 0; + for (int index = 1; index < size; index++){ + int stackTop = stack.peek(); + if (height[index] < height[stackTop]){ + stack.push(index); + }else if (height[index] == height[stackTop]){ + // 因为相等的相邻墙,左边一个是不可能存放雨水的,所以pop左边的index, push当前的index + stack.pop(); + stack.push(index); + }else{ + //pop up all lower value + int heightAtIdx = height[index]; + while (!stack.isEmpty() && (heightAtIdx > height[stackTop])){ + int mid = stack.pop(); + + if (!stack.isEmpty()){ + int left = stack.peek(); + + int h = Math.min(height[left], height[index]) - height[mid]; + int w = index - left - 1; + int hold = h * w; + if (hold > 0) sum += hold; + stackTop = stack.peek(); + } + } + stack.push(index); + } + } + + return sum; + } +} +``` + Python: 双指针法 diff --git a/problems/0084.柱状图中最大的矩形.md b/problems/0084.柱状图中最大的矩形.md index a0f06e8f..57df4161 100644 --- a/problems/0084.柱状图中最大的矩形.md +++ b/problems/0084.柱状图中最大的矩形.md @@ -228,6 +228,50 @@ class Solution { } ``` +单调栈 +```java +class Solution { + int largestRectangleArea(int[] heights) { + Stack st = new Stack(); + + // 数组扩容,在头和尾各加入一个元素 + int [] newHeights = new int[heights.length + 2]; + newHeights[0] = 0; + newHeights[newHeights.length - 1] = 0; + for (int index = 0; index < heights.length; index++){ + newHeights[index + 1] = heights[index]; + } + + heights = newHeights; + + st.push(0); + int result = 0; + // 第一个元素已经入栈,从下表1开始 + for (int i = 1; i < heights.length; i++) { + // 注意heights[i] 是和heights[st.top()] 比较 ,st.top()是下表 + if (heights[i] > heights[st.peek()]) { + st.push(i); + } else if (heights[i] == heights[st.peek()]) { + st.pop(); // 这个可以加,可以不加,效果一样,思路不同 + st.push(i); + } else { + while (heights[i] < heights[st.peek()]) { // 注意是while + int mid = st.peek(); + st.pop(); + int left = st.peek(); + int right = i; + int w = right - left - 1; + int h = heights[mid]; + result = Math.max(result, w * h); + } + st.push(i); + } + } + return result; + } +} +``` + Python: 动态规划 diff --git a/problems/0106.从中序与后序遍历序列构造二叉树.md b/problems/0106.从中序与后序遍历序列构造二叉树.md index 39b55d8c..a9639d8f 100644 --- a/problems/0106.从中序与后序遍历序列构造二叉树.md +++ b/problems/0106.从中序与后序遍历序列构造二叉树.md @@ -607,6 +607,7 @@ class Solution { for (int i = inLeft; i < inRight; i++) { if (inorder[i] == rootVal) { rootIndex = i; + break; } } // 根据rootIndex划分左右子树 diff --git a/problems/0112.路径总和.md b/problems/0112.路径总和.md index 283a9913..da62452c 100644 --- a/problems/0112.路径总和.md +++ b/problems/0112.路径总和.md @@ -411,6 +411,31 @@ class solution { } ``` +```java +// 解法2 +class Solution { + List> result; + LinkedList path; + public List> pathSum (TreeNode root,int targetSum) { + result = new LinkedList<>(); + path = new LinkedList<>(); + travesal(root, targetSum); + return result; + } + private void travesal(TreeNode root, int count) { + if (root == null) return; + path.offer(root.val); + count -= root.val; + if (root.left == null && root.right == null && count == 0) { + result.add(new LinkedList<>(path)); + } + travesal(root.left, count); + travesal(root.right, count); + path.removeLast(); // 回溯 + } +} +``` + ## python 0112.路径总和 diff --git a/problems/0129.求根到叶子节点数字之和.md b/problems/0129.求根到叶子节点数字之和.md index 3439cd25..7f50c885 100644 --- a/problems/0129.求根到叶子节点数字之和.md +++ b/problems/0129.求根到叶子节点数字之和.md @@ -164,6 +164,52 @@ public: Java: +```java +class Solution { + List path = new ArrayList<>(); + int res = 0; + public int sumNumbers(TreeNode root) { + // 如果节点为0,那么就返回0 + if (root == null) return 0; + // 首先将根节点放到集合中 + path.add(root.val); + // 开始递归 + recur(root); + return res; + } + + public void recur(TreeNode root){ + if (root.left == null && root.right == null) { + // 当是叶子节点的时候,开始处理 + res += listToInt(path); + return; + } + + if (root.left != null){ + // 注意有回溯 + path.add(root.left.val); + recur(root.left); + path.remove(path.size() - 1); + } + if (root.right != null){ + // 注意有回溯 + path.add(root.right.val); + recur(root.right); + path.remove(path.size() - 1); + } + return; + } + public int listToInt(List path){ + int sum = 0; + for (Integer num:path){ + // sum * 10 表示进位 + sum = sum * 10 + num; + } + return sum; + } +} +``` + Python: ```python3 class Solution: diff --git a/problems/0143.重排链表.md b/problems/0143.重排链表.md index 76df63b7..2b4e68b7 100644 --- a/problems/0143.重排链表.md +++ b/problems/0143.重排链表.md @@ -177,6 +177,7 @@ public: Java: ```java +// 方法三 public class ReorderList { public void reorderList(ListNode head) { ListNode fast = head, slow = head; @@ -219,6 +220,76 @@ public class ReorderList { return headNode.next; } } + +------------------------------------------------------------------------- +// 方法一 Java实现,使用数组存储节点 + class Solution { + public void reorderList(ListNode head) { + // 双指针的做法 + ListNode cur = head; + // ArrayList底层是数组,可以使用下标随机访问 + List list = new ArrayList<>(); + while (cur != null){ + list.add(cur); + cur = cur.next; + } + cur = head; // 重新回到头部 + int l = 1, r = list.size() - 1; // 注意左边是从1开始 + int count = 0; + while (l <= r){ + if (count % 2 == 0){ + // 偶数 + cur.next = list.get(r); + r--; + }else { + // 奇数 + cur.next = list.get(l); + l++; + } + // 每一次指针都需要移动 + cur = cur.next; + count++; + } + // 当是偶数的话,需要做额外处理 + if (list.size() % 2== 0){ + cur.next = list.get(l); + cur = cur.next; + } + + // 注意结尾要结束一波 + cur.next = null; + } +} +------------------------------------------------------------------------- +// 方法二:使用双端队列,简化了数组的操作,代码相对于前者更简洁(避免一些边界条件) +class Solution { + public void reorderList(ListNode head) { + // 使用双端队列的方法来解决 + Deque de = new LinkedList<>(); + // 这里是取head的下一个节点,head不需要再入队了,避免造成重复 + ListNode cur = head.next; + while (cur != null){ + de.offer(cur); + cur = cur.next; + } + cur = head; // 回到头部 + + int count = 0; + while (!de.isEmpty()){ + if (count % 2 == 0){ + // 偶数,取出队列右边尾部的值 + cur.next = de.pollLast(); + }else { + // 奇数,取出队列左边头部的值 + cur.next = de.poll(); + } + cur = cur.next; + count++; + } + cur.next = null; + } +} + ``` Python: diff --git a/problems/0235.二叉搜索树的最近公共祖先.md b/problems/0235.二叉搜索树的最近公共祖先.md index 929e6eb2..25bbf7e4 100644 --- a/problems/0235.二叉搜索树的最近公共祖先.md +++ b/problems/0235.二叉搜索树的最近公共祖先.md @@ -234,7 +234,15 @@ public: ## Java 递归法: - +```java +class Solution { + public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { + if (root.val > p.val && root.val > q.val) return lowestCommonAncestor(root.left, p, q); + if (root.val < p.val && root.val < q.val) return lowestCommonAncestor(root.right, p, q); + return root; + } +} +``` 迭代法: ```java diff --git a/problems/0257.二叉树的所有路径.md b/problems/0257.二叉树的所有路径.md index 2984427f..6386c48d 100644 --- a/problems/0257.二叉树的所有路径.md +++ b/problems/0257.二叉树的所有路径.md @@ -367,6 +367,43 @@ class Solution { } } ``` +```java +// 解法2 +class Solution { + /** + * 迭代法 + */ + public List binaryTreePaths(TreeNode root) { + List result = new ArrayList<>(); + if (root == null) + return result; + Stack stack = new Stack<>(); + // 节点和路径同时入栈 + stack.push(root); + stack.push(root.val + ""); + while (!stack.isEmpty()) { + // 节点和路径同时出栈 + String path = (String) stack.pop(); + TreeNode node = (TreeNode) stack.pop(); + // 若找到叶子节点 + if (node.left == null && node.right == null) { + result.add(path); + } + //右子节点不为空 + if (node.right != null) { + stack.push(node.right); + stack.push(path + "->" + node.right.val); + } + //左子节点不为空 + if (node.left != null) { + stack.push(node.left); + stack.push(path + "->" + node.left.val); + } + } + return result; + } +} +``` Python: ```Python diff --git a/problems/0300.最长上升子序列.md b/problems/0300.最长上升子序列.md index f9145f4c..fdd5fda8 100644 --- a/problems/0300.最长上升子序列.md +++ b/problems/0300.最长上升子序列.md @@ -39,7 +39,7 @@ 1. dp[i]的定义 -**dp[i]表示i之前包括i的最长上升子序列**。 +**dp[i]表示i之前包括i的最长上升子序列的长度**。 2. 状态转移方程 diff --git a/problems/0406.根据身高重建队列.md b/problems/0406.根据身高重建队列.md index 6d8f703b..bd27b1b2 100644 --- a/problems/0406.根据身高重建队列.md +++ b/problems/0406.根据身高重建队列.md @@ -209,8 +209,13 @@ Python: ```python class Solution: def reconstructQueue(self, people: List[List[int]]) -> List[List[int]]: + # 先按照h维度的身高顺序从高到低排序。确定第一个维度 + # lambda返回的是一个元组:当-x[0](维度h)相同时,再根据x[1](维度k)从小到大排序 people.sort(key=lambda x: (-x[0], x[1])) que = [] + + # 根据每个元素的第二个维度k,贪心算法,进行插入 + # people已经排序过了:同一高度时k值小的排前面。 for p in people: que.insert(p[1], p) return que diff --git a/problems/0450.删除二叉搜索树中的节点.md b/problems/0450.删除二叉搜索树中的节点.md index 35c8e24d..b12d40aa 100644 --- a/problems/0450.删除二叉搜索树中的节点.md +++ b/problems/0450.删除二叉搜索树中的节点.md @@ -118,10 +118,25 @@ public: if (root == nullptr) return root; // 第一种情况:没找到删除的节点,遍历到空节点直接返回了 if (root->val == key) { // 第二种情况:左右孩子都为空(叶子节点),直接删除节点, 返回NULL为根节点 + if (root->left == nullptr && root->right == nullptr) { + ///! 内存释放 + delete root; + return nullptr; + } // 第三种情况:其左孩子为空,右孩子不为空,删除节点,右孩子补位 ,返回右孩子为根节点 - if (root->left == nullptr) return root->right; + else if (root->left == nullptr) { + auto retNode = root->right; + ///! 内存释放 + delete root; + return retNode; + } // 第四种情况:其右孩子为空,左孩子不为空,删除节点,左孩子补位,返回左孩子为根节点 - else if (root->right == nullptr) return root->left; + else if (root->right == nullptr) { + auto retNode = root->left; + ///! 内存释放 + delete root; + return retNode; + } // 第五种情况:左右孩子节点都不为空,则将删除节点的左子树放到删除节点的右子树的最左面节点的左孩子的位置 // 并返回删除节点右孩子为新的根节点。 else { @@ -278,6 +293,32 @@ class Solution { } } ``` +```java +// 解法2 +class Solution { + public TreeNode deleteNode(TreeNode root, int key) { + if (root == null) return root; + if (root.val == key) { + if (root.left == null) { + return root.right; + } else if (root.right == null) { + return root.left; + } else { + TreeNode cur = root.right; + while (cur.left != null) { + cur = cur.left; + } + cur.left = root.left; + root = root.right; + return root; + } + } + if (root.val > key) root.left = deleteNode(root.left, key); + if (root.val < key) root.right = deleteNode(root.right, key); + return root; + } +} +``` ## Python diff --git a/problems/0501.二叉搜索树中的众数.md b/problems/0501.二叉搜索树中的众数.md index aeddc600..22d4f4ac 100644 --- a/problems/0501.二叉搜索树中的众数.md +++ b/problems/0501.二叉搜索树中的众数.md @@ -429,6 +429,44 @@ class Solution { } } ``` +迭代法 +```java +class Solution { + public int[] findMode(TreeNode root) { + TreeNode pre = null; + Stack stack = new Stack<>(); + List result = new ArrayList<>(); + int maxCount = 0; + int count = 0; + TreeNode cur = root; + while (cur != null || !stack.isEmpty()) { + if (cur != null) { + stack.push(cur); + cur =cur.left; + }else { + cur = stack.pop(); + // 计数 + if (pre == null || cur.val != pre.val) { + count = 1; + }else { + count++; + } + // 更新结果 + if (count > maxCount) { + maxCount = count; + result.clear(); + result.add(cur.val); + }else if (count == maxCount) { + result.add(cur.val); + } + pre = cur; + cur = cur.right; + } + } + return result.stream().mapToInt(Integer::intValue).toArray(); + } +} +``` ## Python diff --git a/problems/0503.下一个更大元素II.md b/problems/0503.下一个更大元素II.md index 4e088ed4..624c6c7c 100644 --- a/problems/0503.下一个更大元素II.md +++ b/problems/0503.下一个更大元素II.md @@ -132,6 +132,26 @@ class Solution: return dp ``` Go: +```go +func nextGreaterElements(nums []int) []int { + length := len(nums) + result := make([]int,length,length) + for i:=0;i0&&nums[i%length]>nums[stack[len(stack)-1]]{ + index := stack[len(stack)-1] + stack = stack[:len(stack)-1] // pop + result[index] = nums[i%length] + } + stack = append(stack,i%length) + } + return result +} +``` JavaScript: diff --git a/problems/0530.二叉搜索树的最小绝对差.md b/problems/0530.二叉搜索树的最小绝对差.md index ae6719ec..b19a0dd2 100644 --- a/problems/0530.二叉搜索树的最小绝对差.md +++ b/problems/0530.二叉搜索树的最小绝对差.md @@ -171,7 +171,34 @@ class Solution { } } ``` +迭代法-中序遍历 +```java +class Solution { + TreeNode pre; + Stack stack; + public int getMinimumDifference(TreeNode root) { + if (root == null) return 0; + stack = new Stack<>(); + TreeNode cur = root; + int result = Integer.MAX_VALUE; + while (cur != null || !stack.isEmpty()) { + if (cur != null) { + stack.push(cur); // 将访问的节点放进栈 + cur = cur.left; // 左 + }else { + cur = stack.pop(); + if (pre != null) { // 中 + result = Math.min(result, cur.val - pre.val); + } + pre = cur; + cur = cur.right; // 右 + } + } + return result; + } +} +``` ## Python 递归 diff --git a/problems/0617.合并二叉树.md b/problems/0617.合并二叉树.md index 22a527f9..e21efcb3 100644 --- a/problems/0617.合并二叉树.md +++ b/problems/0617.合并二叉树.md @@ -274,7 +274,7 @@ class Solution { ```Java class Solution { - // 迭代 + // 使用栈迭代 public TreeNode mergeTrees(TreeNode root1, TreeNode root2) { if (root1 == null) { return root2; @@ -310,6 +310,43 @@ class Solution { } } ``` +```java +class Solution { + // 使用队列迭代 + public TreeNode mergeTrees(TreeNode root1, TreeNode root2) { + if (root1 == null) return root2; + if (root2 ==null) return root1; + Queue queue = new LinkedList<>(); + queue.offer(root1); + queue.offer(root2); + while (!queue.isEmpty()) { + TreeNode node1 = queue.poll(); + TreeNode node2 = queue.poll(); + // 此时两个节点一定不为空,val相加 + node1.val = node1.val + node2.val; + // 如果两棵树左节点都不为空,加入队列 + if (node1.left != null && node2.left != null) { + queue.offer(node1.left); + queue.offer(node2.left); + } + // 如果两棵树右节点都不为空,加入队列 + if (node1.right != null && node2.right != null) { + queue.offer(node1.right); + queue.offer(node2.right); + } + // 若node1的左节点为空,直接赋值 + if (node1.left == null && node2.left != null) { + node1.left = node2.left; + } + // 若node2的左节点为空,直接赋值 + if (node1.right == null && node2.right != null) { + node1.right = node2.right; + } + } + return root1; + } +} +``` ## Python diff --git a/problems/1002.查找常用字符.md b/problems/1002.查找常用字符.md index c0ca578e..e02780da 100644 --- a/problems/1002.查找常用字符.md +++ b/problems/1002.查找常用字符.md @@ -193,6 +193,26 @@ class Solution: hash[i] -= 1 return result ``` + +Python 3 使用collections.Counter +```python +class Solution: + def commonChars(self, words: List[str]) -> List[str]: + tmp = collections.Counter(words[0]) + l = [] + for i in range(1,len(words)): + # 使用 & 取交集 + tmp = tmp & collections.Counter(words[i]) + + # 剩下的就是每个单词都出现的字符(键),个数(值) + for j in tmp: + v = tmp[j] + while(v): + l.append(j) + v -= 1 + return l +``` + javaScript ```js var commonChars = function (words) { diff --git a/problems/1356.根据数字二进制下1的数目排序.md b/problems/1356.根据数字二进制下1的数目排序.md index 660434a2..06c29500 100644 --- a/problems/1356.根据数字二进制下1的数目排序.md +++ b/problems/1356.根据数字二进制下1的数目排序.md @@ -123,6 +123,31 @@ public: ## Java ```java +class Solution { + private int cntInt(int val){ + int count = 0; + while(val > 0) { + val = val & (val - 1); + count ++; + } + + return count; + } + + public int[] sortByBits(int[] arr) { + return Arrays.stream(arr).boxed() + .sorted(new Comparator(){ + @Override + public int compare(Integer o1, Integer o2) { + int cnt1 = cntInt(o1); + int cnt2 = cntInt(o2); + return (cnt1 == cnt2) ? Integer.compare(o1, o2) : Integer.compare(cnt1, cnt2); + } + }) + .mapToInt(Integer::intValue) + .toArray(); + } +} ``` diff --git a/problems/二叉树的递归遍历.md b/problems/二叉树的递归遍历.md index 223cf722..93f4000e 100644 --- a/problems/二叉树的递归遍历.md +++ b/problems/二叉树的递归遍历.md @@ -360,8 +360,56 @@ var postorderTraversal = function(root) { }; ``` +C: +```c +//前序遍历: +void preOrderTraversal(struct TreeNode* root, int* ret, int* returnSize) { + if(root == NULL) + return; + ret[(*returnSize)++] = root->val; + preOrderTraverse(root->left, ret, returnSize); + preOrderTraverse(root->right, ret, returnSize); +} +int* preorderTraversal(struct TreeNode* root, int* returnSize){ + int* ret = (int*)malloc(sizeof(int) * 100); + *returnSize = 0; + preOrderTraversal(root, ret, returnSize); + return ret; +} +//中序遍历: +void inOrder(struct TreeNode* node, int* ret, int* returnSize) { + if(!node) + return; + inOrder(node->left, ret, returnSize); + ret[(*returnSize)++] = node->val; + inOrder(node->right, ret, returnSize); +} + +int* inorderTraversal(struct TreeNode* root, int* returnSize){ + int* ret = (int*)malloc(sizeof(int) * 100); + *returnSize = 0; + inOrder(root, ret, returnSize); + return ret; +} + +//后序遍历: +void postOrder(struct TreeNode* node, int* ret, int* returnSize) { + if(node == NULL) + return; + postOrder(node->left, ret, returnSize); + postOrder(node->right, ret, returnSize); + ret[(*returnSize)++] = node->val; +} + +int* postorderTraversal(struct TreeNode* root, int* returnSize){ + int* ret= (int*)malloc(sizeof(int) * 100); + *returnSize = 0; + postOrder(root, ret, returnSize); + return ret; +} +``` ----------------------- * 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) diff --git a/problems/前序/递归算法的时间与空间复杂度分析.md b/problems/前序/递归算法的时间与空间复杂度分析.md index 27b9d7cc..7a690781 100644 --- a/problems/前序/递归算法的时间与空间复杂度分析.md +++ b/problems/前序/递归算法的时间与空间复杂度分析.md @@ -166,7 +166,7 @@ void time_consumption() { system_clock::now().time_since_epoch() ); - fibonacci_3(0, 1, n); + fibonacci_3(1, 1, n); milliseconds end_time = duration_cast( system_clock::now().time_since_epoch()