Merge branch 'youngyangyang04:master' into patch-4

This commit is contained in:
Asterisk
2021-10-08 13:01:03 +08:00
committed by GitHub
12 changed files with 193 additions and 74 deletions

View File

@ -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] 表示到达ij 点的路径数
for (let i=1; i<m; i++) {
for (let j=1; j< n;j++) {
dp[i][j]=dp[i-1][j]+dp[i][j-1];
}
}
return dp[m-1][n-1];
};
```
-----------------------

View File

@ -88,7 +88,7 @@
以上分析完毕C++代码如下:
```
```CPP
class Solution {
public:
int climbStairs(int n) {

View File

@ -125,9 +125,10 @@ public:
1. 明确递归函数的参数和返回值
参数的话为传入节点指针,就没有其他参数需要传递了,返回值要返回传入节点为根节点树的深度
参数:当前传入节点。
返回值:以当前传入节点为根节点的树的高度。
那么如何标记左右子树是否差值大于1呢
那么如何标记左右子树是否差值大于1呢
如果当前传入节点为根节点的二叉树已经不是二叉平衡树了,还返回高度的话就没有意义了。
@ -136,9 +137,9 @@ public:
代码如下:
```
```CPP
// -1 表示已经不是平衡二叉树了,否则返回值是以该节点为根节点树的高度
int getDepth(TreeNode* node)
int getHeight(TreeNode* node)
```
2. 明确终止条件
@ -147,7 +148,7 @@ int getDepth(TreeNode* node)
代码如下:
```
```CPP
if (node == NULL) {
return 0;
}
@ -155,23 +156,23 @@ if (node == NULL) {
3. 明确单层递归的逻辑
如何判断当前传入节点为根节点的二叉树是否是平衡二叉树呢当然是左子树高度和右子树高度相差
如何判断当前传入节点为根节点的二叉树是否是平衡二叉树呢当然是左子树高度和右子树高度的差值
分别求出左右子树的高度然后如果差值小于等于1则返回当前二叉树的高度否则则返回-1表示已经不是二叉树了。
分别求出左右子树的高度然后如果差值小于等于1则返回当前二叉树的高度否则则返回-1表示已经不是二叉平衡树了。
代码如下:
```CPP
int leftDepth = depth(node->left); // 左
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)
```
迭代法:

View File

@ -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);
}
}
```

View File

@ -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.递归版本

View File

@ -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)
}

View File

@ -141,7 +141,7 @@ public:
Java:
```
```java
class Solution {
public boolean isSubsequence(String s, String t) {
int length1 = s.length(); int length2 = t.length();

View File

@ -227,7 +227,7 @@ class Solution:
```
Go
```
```go
func canPartition(nums []int) bool {
/**
动态五部曲:

View File

@ -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;

View File

@ -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;
};
```

View File

@ -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]<chars[i-1]){
chars[i-1]--;
start=i;
}
}
StringBuilder res=new StringBuilder();
for (int i=0;i<chars.length;i++){
if (chars[i]=='0'&&i==0)continue;//防止出现09这样的情况
if (i>=start){
res.append('9');
}else res.append(chars[i]);
}
return Integer.parseInt(res.toString());
}
}
```
Python

View File

@ -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();
}
```