diff --git a/problems/0062.不同路径.md b/problems/0062.不同路径.md index af3a8f40..31896fd1 100644 --- a/problems/0062.不同路径.md +++ b/problems/0062.不同路径.md @@ -327,6 +327,25 @@ var uniquePaths = function(m, n) { return dp[m - 1][n - 1] }; ``` +>版本二:直接将dp数值值初始化为1 +```javascript +/** + * @param {number} m + * @param {number} n + * @return {number} + */ +var uniquePaths = function(m, n) { + let dp = new Array(m).fill(1).map(() => new Array(n).fill(1)); + // dp[i][j] 表示到达(i,j) 点的路径数 + for (let i=1; ileft); // 左 -if (leftDepth == -1) return -1; -int rightDepth = depth(node->right); // 右 -if (rightDepth == -1) return -1; +int leftHeight = getHeight(node->left); // 左 +if (leftHeight == -1) return -1; +int rightHeight = getHeight(node->right); // 右 +if (rightHeight == -1) return -1; int result; -if (abs(leftDepth - rightDepth) > 1) { // 中 +if (abs(leftHeight - rightHeight) > 1) { // 中 result = -1; } else { - result = 1 + max(leftDepth, rightDepth); // 以当前节点为根节点的最大高度 + result = 1 + max(leftHeight, rightHeight); // 以当前节点为根节点的树的最大高度 } return result; @@ -180,27 +181,27 @@ return result; 代码精简之后如下: ```CPP -int leftDepth = getDepth(node->left); -if (leftDepth == -1) return -1; -int rightDepth = getDepth(node->right); -if (rightDepth == -1) return -1; -return abs(leftDepth - rightDepth) > 1 ? -1 : 1 + max(leftDepth, rightDepth); +int leftHeight = getHeight(node->left); +if (leftHeight == -1) return -1; +int rightHeight = getHeight(node->right); +if (rightHeight == -1) return -1; +return abs(leftHeight - rightHeight) > 1 ? -1 : 1 + max(leftHeight, rightHeight); ``` 此时递归的函数就已经写出来了,这个递归的函数传入节点指针,返回以该节点为根节点的二叉树的高度,如果不是二叉平衡树,则返回-1。 -getDepth整体代码如下: +getHeight整体代码如下: ```CPP -int getDepth(TreeNode* node) { +int getHeight(TreeNode* node) { if (node == NULL) { return 0; } - int leftDepth = getDepth(node->left); - if (leftDepth == -1) return -1; - int rightDepth = getDepth(node->right); - if (rightDepth == -1) return -1; - return abs(leftDepth - rightDepth) > 1 ? -1 : 1 + max(leftDepth, rightDepth); + int leftHeight = getHeight(node->left); + if (leftHeight == -1) return -1; + int rightHeight = getHeight(node->right); + if (rightHeight == -1) return -1; + return abs(leftHeight - rightHeight) > 1 ? -1 : 1 + max(leftHeight, rightHeight); } ``` @@ -210,18 +211,18 @@ int getDepth(TreeNode* node) { class Solution { public: // 返回以该节点为根节点的二叉树的高度,如果不是二叉搜索树了则返回-1 - int getDepth(TreeNode* node) { + int getHeight(TreeNode* node) { if (node == NULL) { return 0; } - int leftDepth = getDepth(node->left); - if (leftDepth == -1) return -1; // 说明左子树已经不是二叉平衡树 - int rightDepth = getDepth(node->right); - if (rightDepth == -1) return -1; // 说明右子树已经不是二叉平衡树 - return abs(leftDepth - rightDepth) > 1 ? -1 : 1 + max(leftDepth, rightDepth); + int leftHeight = getHeight(node->left); + if (leftHeight == -1) return -1; + int rightHeight = getHeight(node->right); + if (rightHeight == -1) return -1; + return abs(leftHeight - rightHeight) > 1 ? -1 : 1 + max(leftHeight, rightHeight); } bool isBalanced(TreeNode* root) { - return getDepth(root) == -1 ? false : true; + return getHeight(root) == -1 ? false : true; } }; ``` @@ -498,20 +499,35 @@ class Solution { ## Python 递归法: -```python +```python3 +# 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 isBalanced(self, root: TreeNode) -> bool: - return True if self.getDepth(root) != -1 else False + if self.get_height(root) != -1: + return True + else: + return False - #返回以该节点为根节点的二叉树的高度,如果不是二叉搜索树了则返回-1 - def getDepth(self, node): - if not node: + def get_height(self, root: TreeNode) -> int: + # Base Case + if not root: return 0 - leftDepth = self.getDepth(node.left) - if leftDepth == -1: return -1 #说明左子树已经不是二叉平衡树 - rightDepth = self.getDepth(node.right) - if rightDepth == -1: return -1 #说明右子树已经不是二叉平衡树 - return -1 if abs(leftDepth - rightDepth)>1 else 1 + max(leftDepth, rightDepth) + # 左 + if (left_height := self.get_height(root.left)) == -1: + return -1 + # 右 + if (right_height := self.get_height(root.right)) == -1: + return -1 + # 中 + if abs(left_height - right_height) > 1: + return -1 + else: + return 1 + max(left_height, right_height) ``` 迭代法: diff --git a/problems/0206.翻转链表.md b/problems/0206.翻转链表.md index ef2664eb..ec6f3dca 100644 --- a/problems/0206.翻转链表.md +++ b/problems/0206.翻转链表.md @@ -96,6 +96,28 @@ public: }; ``` +我们可以发现,上面的递归写法和双指针法实质上都是从前往后翻转指针指向,其实还有另外一种与双指针法不同思路的递归写法:从后往前翻转指针指向。 + +具体代码如下(带详细注释): + +```CPP +class Solution { +public: + ListNode* reverseList(ListNode* head) { + // 边缘条件判断 + if(head == NULL) return NULL; + if (head->next == NULL) return head; + + // 递归调用,翻转第二个节点开始往后的链表 + ListNode *last = reverseList(head->next); + // 翻转头节点与第二个节点的指向 + head->next->next = head; + // 此时的 head 节点为尾节点,next 需要指向 NULL + head->next = NULL; + return last; + } +}; +``` ## 其他语言版本 @@ -135,9 +157,9 @@ class Solution { temp = cur.next;// 先保存下一个节点 cur.next = prev;// 反转 // 更新prev、cur位置 - prev = cur; - cur = temp; - return reverse(prev, cur); + // prev = cur; + // cur = temp; + return reverse(cur, temp); } } ``` diff --git a/problems/0257.二叉树的所有路径.md b/problems/0257.二叉树的所有路径.md index c85186d5..f902aab2 100644 --- a/problems/0257.二叉树的所有路径.md +++ b/problems/0257.二叉树的所有路径.md @@ -404,33 +404,41 @@ class Solution { } } ``` - -Python: -```Python +--- +Python: +递归法+隐形回溯 +```Python3 +# 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 binaryTreePaths(self, root: TreeNode) -> List[str]: - path, result = '', [] + path = '' + result = [] + if not root: return result self.traversal(root, path, result) return result - def traversal(self, cur: TreeNode, path: List, result: List): + def traversal(self, cur: TreeNode, path: str, result: List[str]) -> None: path += str(cur.val) - # 如果当前节点为叶子节点,添加路径到结果中 - if not (cur.left or cur.right): + # 若当前节点为leave,直接输出 + if not cur.left and not cur.right: result.append(path) - return - + if cur.left: + # + '->' 是隐藏回溯 self.traversal(cur.left, path + '->', result) - + if cur.right: self.traversal(cur.right, path + '->', result) - ``` - -```python + +迭代法: + +```python3 from collections import deque @@ -457,7 +465,8 @@ class Solution: return result ``` - + +--- Go: ```go @@ -482,7 +491,7 @@ func binaryTreePaths(root *TreeNode) []string { return res } ``` - +--- JavaScript: 1.递归版本 diff --git a/problems/0279.完全平方数.md b/problems/0279.完全平方数.md index a00ed47e..b1af7e95 100644 --- a/problems/0279.完全平方数.md +++ b/problems/0279.完全平方数.md @@ -334,8 +334,8 @@ var numSquares1 = function(n) { let dp = new Array(n + 1).fill(Infinity) dp[0] = 0 - for(let i = 0; i <= n; i++) { - let val = i * i + for(let i = 1; i**2 <= n; i++) { + let val = i**2 for(let j = val; j <= n; j++) { dp[j] = Math.min(dp[j], dp[j - val] + 1) } diff --git a/problems/0392.判断子序列.md b/problems/0392.判断子序列.md index cda0c82d..1a8e55fa 100644 --- a/problems/0392.判断子序列.md +++ b/problems/0392.判断子序列.md @@ -141,7 +141,7 @@ public: Java: -``` +```java class Solution { public boolean isSubsequence(String s, String t) { int length1 = s.length(); int length2 = t.length(); diff --git a/problems/0416.分割等和子集.md b/problems/0416.分割等和子集.md index fd20f68a..05c272c6 100644 --- a/problems/0416.分割等和子集.md +++ b/problems/0416.分割等和子集.md @@ -227,7 +227,7 @@ class Solution: ``` Go: -``` +```go func canPartition(nums []int) bool { /** 动态五部曲: diff --git a/problems/0494.目标和.md b/problems/0494.目标和.md index 210ac749..00771c22 100644 --- a/problems/0494.目标和.md +++ b/problems/0494.目标和.md @@ -371,7 +371,6 @@ const findTargetSumWays = (nums, target) => { } const halfSum = (target + sum) / 2; - nums.sort((a, b) => a - b); let dp = new Array(halfSum+1).fill(0); dp[0] = 1; diff --git a/problems/0714.买卖股票的最佳时机含手续费.md b/problems/0714.买卖股票的最佳时机含手续费.md index c6a147b4..576f5f85 100644 --- a/problems/0714.买卖股票的最佳时机含手续费.md +++ b/problems/0714.买卖股票的最佳时机含手续费.md @@ -262,6 +262,34 @@ var maxProfit = function(prices, fee) { } return result }; + +// 动态规划 +/** + * @param {number[]} prices + * @param {number} fee + * @return {number} + */ +var maxProfit = function(prices, fee) { + // 滚动数组 + // have表示当天持有股票的最大收益 + // notHave表示当天不持有股票的最大收益 + // 把手续费算在买入价格中 + let n = prices.length, + have = -prices[0]-fee, // 第0天持有股票的最大收益 + notHave = 0; // 第0天不持有股票的最大收益 + for (let i = 1; i < n; i++) { + // 第i天持有股票的最大收益由两种情况组成 + // 1、第i-1天就已经持有股票,第i天什么也没做 + // 2、第i-1天不持有股票,第i天刚买入 + have = Math.max(have, notHave - prices[i] - fee); + // 第i天不持有股票的最大收益由两种情况组成 + // 1、第i-1天就已经不持有股票,第i天什么也没做 + // 2、第i-1天持有股票,第i天刚卖出 + notHave = Math.max(notHave, have + prices[i]); + } + // 最后手中不持有股票,收益才能最大化 + return notHave; +}; ``` diff --git a/problems/0738.单调递增的数字.md b/problems/0738.单调递增的数字.md index 0db0db15..61175521 100644 --- a/problems/0738.单调递增的数字.md +++ b/problems/0738.单调递增的数字.md @@ -127,6 +127,7 @@ public: Java: ```java +版本1 class Solution { public int monotoneIncreasingDigits(int N) { String[] strings = (N + "").split(""); @@ -144,6 +145,31 @@ class Solution { } } ``` +java版本1中创建了String数组,多次使用Integer.parseInt了方法,这导致不管是耗时还是空间占用都非常高,用时12ms,下面提供一个版本在char数组上原地修改,用时1ms的版本 +```java +版本2 +class Solution { + public int monotoneIncreasingDigits(int n) { + if (n==0)return 0; + char[] chars= Integer.toString(n).toCharArray(); + int start=Integer.MAX_VALUE;//start初始值设为最大值,这是为了防止当数字本身是单调递增时,没有一位数字需要改成9的情况 + for (int i=chars.length-1;i>0;i--){ + if (chars[i]=start){ + res.append('9'); + }else res.append(chars[i]); + } + return Integer.parseInt(res.toString()); + } +} +``` Python: diff --git a/problems/二叉树中递归带着回溯.md b/problems/二叉树中递归带着回溯.md index 71a3ee5c..0a386fe1 100644 --- a/problems/二叉树中递归带着回溯.md +++ b/problems/二叉树中递归带着回溯.md @@ -145,22 +145,22 @@ if (cur->right) { } ``` -此时就没有回溯了,这个代码就是通过不了的了。 +因为在递归右子树之前需要还原path,所以在左子树递归后必须为了右子树而进行回溯操作。而只右子树自己不添加回溯也可以成功AC。 -如果想把回溯加上,就要 在上面代码的基础上,加上回溯,就可以AC了。 +因此,在上面代码的基础上,再加上左右子树的回溯代码,就可以AC了。 ```CPP if (cur->left) { path += "->"; traversal(cur->left, path, result); // 左 - path.pop_back(); // 回溯 - path.pop_back(); + path.pop_back(); // 回溯,抛掉val + path.pop_back(); // 回溯,抛掉-> } if (cur->right) { path += "->"; traversal(cur->right, path, result); // 右 - path.pop_back(); // 回溯 - path.pop_back(); + path.pop_back(); // 回溯(非必要) + path.pop_back(); } ```