Merge branch 'master' of github.com:youngyangyang04/leetcode-master

This commit is contained in:
youngyangyang04
2021-11-25 11:20:15 +08:00
7 changed files with 258 additions and 80 deletions

View File

@ -607,29 +607,23 @@ func abs(a int)int{
## JavaScript
```javascript
var isBalanced = function(root) {
//还是用递归三部曲 + 后序遍历 左右中 当前左子树右子树高度相差大于1就返回-1
//还是用递归三部曲 + 后序遍历 左右中 当前左子树右子树高度相差大于1就返回-1
// 1. 确定递归函数参数以及返回值
const getDepth=function(node){
// 2. 确定递归函数终止条件
if(node===null){
return 0;
const getDepth = function(node) {
// 2. 确定递归函数终止条件
if(node === null) return 0;
// 3. 确定单层递归逻辑
let leftDepth = getDepth(node.left); //左子树高度
let rightDepth = getDepth(node.right); //右子树高度
if(leftDepth === -1) return -1;
if(rightDepth === -1) return -1;
if(Math.abs(leftDepth - rightDepth) > 1) {
return -1;
} else {
return 1 + Math.max(leftDepth, rightDepth);
}
// 3. 确定单层递归逻辑
let leftDepth=getDepth(node.left);//左子树高度
if(leftDepth===-1){
return -1;
}
let rightDepth=getDepth(node.right);//右子树高度
if(rightDepth===-1){
return -1;
}
if(Math.abs(leftDepth-rightDepth)>1){
return -1;
}else{
return 1+Math.max(leftDepth,rightDepth);
}
}
return getDepth(root)===-1?false:true;
return !(getDepth(root) === -1);
};
```

View File

@ -614,6 +614,7 @@ func haspathsum(root *treenode,sumnodes *[]int,targetsum int,result *[][]int){
0112.路径总和
**递归**
```javascript
/**
* @param {treenode} root
@ -643,9 +644,38 @@ let haspathsum = function (root, targetsum) {
// return haspathsum(root.left, targetsum - root.val) || haspathsum(root.right, targetsum - root.val);
};
```
**迭代**
```javascript
let hasPathSum = function(root, targetSum) {
if(root === null) return false;
let nodeArr = [root];
let valArr = [0];
while(nodeArr.length) {
let curNode = nodeArr.shift();
let curVal = valArr.shift();
curVal += curNode.val;
// 为叶子结点且和等于目标数返回true
if (curNode.left === null && curNode.right === null && curVal === targetSum) {
return true;
}
// 左节点,将当前的数值也对应记录下来
if (curNode.left) {
nodeArr.push(curNode.left);
valArr.push(curVal);
}
// 右节点,将当前的数值也对应记录下来
if (curNode.right) {
nodeArr.push(curNode.right);
valArr.push(curVal);
}
}
return false;
};
```
0113.路径总和-ii
**递归**
```javascript
let pathsum = function (root, targetsum) {
// 递归法
@ -677,7 +707,7 @@ let pathsum = function (root, targetsum) {
return res;
};
```
113 路径总和 精简版
**递归 精简版**
```javascript
var pathsum = function(root, targetsum) {
//递归方法
@ -701,6 +731,41 @@ var pathsum = function(root, targetsum) {
return resPath;
};
```
**迭代**
```javascript
let pathSum = function(root, targetSum) {
if(root === null) return [];
let nodeArr = [root];
let resArr = []; // 记录符合目标和的返回路径
let tempArr = [[]]; // 对应路径
let countArr = [0]; //对应和
while(nodeArr.length) {
let curNode = nodeArr.shift();
let curVal = countArr.shift();
let curNodeArr = tempArr.shift();
curVal += curNode.val;
curNodeArr.push(curNode.val);
// 为叶子结点且和等于目标数将此次结果数组push进返回数组中
if (curNode.left === null && curNode.right === null && curVal === targetSum) {
resArr.push(curNodeArr);
}
// 左节点,将当前的和及对应路径也对应记录下来
if (curNode.left) {
nodeArr.push(curNode.left);
countArr.push(curVal);
tempArr.push([...curNodeArr]);
}
// 右节点,将当前的和及对应路径也对应记录下来
if (curNode.right) {
nodeArr.push(curNode.right);
countArr.push(curVal);
tempArr.push([...curNodeArr]);
}
}
return resArr;
};
```

View File

@ -195,23 +195,26 @@ public:
## 其他语言版本
Java
> 贪心法:
```java
// 贪心思路
class Solution {
public int maxProfit(int[] prices) {
int minprice = Integer.MAX_VALUE;
int maxprofit = 0;
for (int i = 0; i < prices.length; i++) {
if (prices[i] < minprice) {
minprice = prices[i];
} else if (prices[i] - minprice > maxprofit) {
maxprofit = prices[i] - minprice;
}
// 找到一个最小的购入点
int low = Integer.MAX_VALUE;
// res不断更新直到数组循环完毕
int res = 0;
for(int i = 0; i < prices.length; i++){
low = Math.min(prices[i], low);
res = Math.max(prices[i] - low, res);
}
return maxprofit;
return res;
}
}
```
> 动态规划:版本一
```java
// 解法1
class Solution {
@ -233,30 +236,30 @@ class Solution {
}
```
> 动态规划:版本二
``` java
class Solution { // 动态规划解法
public int maxProfit(int[] prices) {
// 可交易次数
int k = 1;
// [天数][交易次数][是否持有股票]
int[][][] dp = new int[prices.length][k + 1][2];
// bad case
dp[0][0][0] = 0;
dp[0][0][1] = Integer.MIN_VALUE;
dp[0][1][0] = Integer.MIN_VALUE;
dp[0][1][1] = -prices[0];
for (int i = 1; i < prices.length; i++) {
for (int j = k; j >= 1; j--) {
// dp公式
dp[i][j][0] = Math.max(dp[i - 1][j][0], dp[i - 1][j][1] + prices[i]);
dp[i][j][1] = Math.max(dp[i - 1][j][1], dp[i - 1][j - 1][0] - prices[i]);
}
}
return dp[prices.length - 1][k][0] > 0 ? dp[prices.length - 1][k][0] : 0;
class Solution {
public int maxProfit(int[] prices) {
int[] dp = new int[2];
dp[0] = -prices[0];
dp[1] = 0;
// 可以参考斐波那契问题的优化方式
// dp[0] 和 dp[1], 其实是第 0 天的数据
// 所以我们从 i=1 开始遍历数组,一共有 prices.length 天,
// 所以是 i<=prices.length
for (int i = 1; i <= prices.length; i++) {
// 前一天持有;或当天买入
dp[0] = Math.max(dp[0], -prices[i - 1]);
// 如果 dp[0] 被更新,那么 dp[1] 肯定会被更新为正数的 dp[1]
// 而不是 dp[0]+prices[i-1]==0 的0
// 所以这里使用会改变的dp[0]也是可以的
// 当然 dp[1] 初始值为 0 ,被更新成 0 也没影响
// 前一天卖出;或当天卖出, 当天要卖出,得前一天持有才行
dp[1] = Math.max(dp[1], dp[0] + prices[i - 1]);
}
return dp[1];
}
}
```

View File

@ -167,6 +167,25 @@ class Solution { // 动态规划
}
```
```java
// 优化空间
class Solution {
public int maxProfit(int[] prices) {
int[] dp=new int[2];
// 0表示持有1表示卖出
dp[0]=-prices[0];
dp[1]=0;
for(int i=1; i<=prices.length; i++){
// 前一天持有; 或当天卖出然后买入
dp[0]=Math.max(dp[0], dp[1]-prices[i-1]);
// 前一天卖出; 或当天卖出,当天卖出,得先持有
dp[1]=Math.max(dp[1], dp[0]+prices[i-1]);
}
return dp[1];
}
}
```
### Python

View File

@ -188,7 +188,7 @@ dp[1] = max(dp[1], dp[0] - prices[i]); 如果dp[1]取dp[1],即保持买入股
## 其他语言版本
Java
### Java
```java
// 版本一
@ -221,25 +221,30 @@ class Solution {
// 版本二: 空间优化
class Solution {
public int maxProfit(int[] prices) {
int len = prices.length;
int[] dp = new int[5];
dp[1] = -prices[0];
dp[3] = -prices[0];
for (int i = 1; i < len; i++) {
dp[1] = Math.max(dp[1], dp[0] - prices[i]);
dp[2] = Math.max(dp[2], dp[1] + prices[i]);
dp[3] = Math.max(dp[3], dp[2] - prices[i]);
dp[4] = Math.max(dp[4], dp[3] + prices[i]);
int[] dp=new int[4];
// 存储两天的状态就行了
// dp[0]代表第一次买入
dp[0]=-prices[0];
// dp[1]代表第一次卖出
dp[1]=0;
// dp[2]代表第二次买入
dp[2]=-prices[0];
// dp[3]代表第二次卖出
dp[3]=0;
for(int i=1; i<=prices.length; i++){
// 要么保持不变,要么没有就买,有了就卖
dp[0]=Math.max(dp[0], -prices[i-1]);
dp[1]=Math.max(dp[1], dp[0]+prices[i-1]);
// 这已经是第二天了,所以得加上前一天卖出去的价格
dp[2]=Math.max(dp[2], dp[1]-prices[i-1]);
dp[3]=Math.max(dp[3], dp[2]+prices[i-1]);
}
return dp[4];
return dp[3];
}
}
```
Python
### Python
> 版本一:
```python
@ -308,7 +313,7 @@ func max(a,b int)int{
JavaScript
### JavaScript
> 版本一:
@ -347,7 +352,7 @@ const maxProfit = prices => {
};
```
Go:
### Go
> 版本一:
```go
@ -381,5 +386,7 @@ func max(a, b int) int {
```
-----------------------
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>

View File

@ -222,19 +222,32 @@ class Solution {
//版本三:一维 dp数组
class Solution {
public int maxProfit(int k, int[] prices) {
//在版本二的基础上,由于我们只关心前一天的股票买入情况,所以只存储前一天的股票买入情况
if(prices.length==0)return 0;
int[] dp=new int[2*k+1];
for (int i = 1; i <2*k ; i+=2) {
dp[i]=-prices[0];
if(prices.length == 0){
return 0;
}
for (int i = 0; i <prices.length ; i++) {
for (int j = 1; j <2*k ; j+=2) {
dp[j]=Math.max(dp[j],dp[j-1]-prices[i]);
dp[j+1]=Math.max(dp[j+1],dp[j]+prices[i]);
if(k == 0){
return 0;
}
// 其实就是123题的扩展123题只用记录2天的状态
// 这里记录k天的状态就行了
// 每天都有买入,卖出两个状态,所以要乘 2
int[] dp = new int[2 * k];
// 按123题解题格式那样做一个初始化
for(int i = 0; i < dp.length / 2; i++){
dp[i * 2] = -prices[0];
}
for(int i = 1; i <= prices.length; i++){
dp[0] = Math.max(dp[0], -prices[i - 1]);
dp[1] = Math.max(dp[1], dp[0] + prices[i - 1]);
// 还是与123题一样与123题对照来看
// 就很容易啦
for(int j = 2; j < dp.length; j += 2){
dp[j] = Math.max(dp[j], dp[j - 1] - prices[i-1]);
dp[j + 1] = Math.max(dp[j + 1], dp[j] + prices[i - 1]);
}
}
return dp[2*k];
// 返回最后一天卖出状态的结果就行了
return dp[dp.length - 1];
}
}
```

View File

@ -349,6 +349,83 @@ MyQueue.prototype.empty = function() {
};
```
C:
```C
/*
1.两个type为int的数组大小为100
第一个栈stackIn用来存放数据第二个栈stackOut作为辅助用来输出数据
2.两个指针stackInTop和stackOutTop分别指向栈顶
*/
typedef struct {
int stackInTop, stackOutTop;
int stackIn[100], stackOut[100];
} MyQueue;
/*
1.开辟一个队列的大小空间
2.将指针stackInTop和stackOutTop初始化为0
3.返回开辟的队列
*/
MyQueue* myQueueCreate() {
MyQueue* queue = (MyQueue*)malloc(sizeof(MyQueue));
queue->stackInTop = 0;
queue->stackOutTop = 0;
return queue;
}
/*
将元素存入第一个栈中,存入后栈顶指针+1
*/
void myQueuePush(MyQueue* obj, int x) {
obj->stackIn[(obj->stackInTop)++] = x;
}
/*
1.若输出栈为空且当第一个栈中有元素stackInTop>0时将第一个栈中元素复制到第二个栈中stack2[stackTop2++] = stack1[--stackTop1])
2.将栈顶元素保存
3.当stackTop2>0时将第二个栈中元素复制到第一个栈中(stack1[stackTop1++] = stack2[--stackTop2])
*/
int myQueuePop(MyQueue* obj) {
//优化:复制栈顶指针,减少对内存的访问次数
int stackInTop = obj->stackInTop;
int stackOutTop = obj->stackOutTop;
//若输出栈为空
if(stackOutTop == 0) {
//将第一个栈中元素复制到第二个栈中
while(stackInTop > 0) {
obj->stackOut[stackOutTop++] = obj->stackIn[--stackInTop];
}
}
//将第二个栈中栈顶元素(队列的第一个元素)出栈,并保存
int top = obj->stackOut[--stackOutTop];
//将输出栈中元素放回输入栈中
while(stackOutTop > 0) {
obj->stackIn[stackInTop++] = obj->stackOut[--stackOutTop];
}
//更新栈顶指针
obj->stackInTop = stackInTop;
obj->stackOutTop = stackOutTop;
//返回队列中第一个元素
return top;
}
//返回输入栈中的栈底元素
int myQueuePeek(MyQueue* obj) {
return obj->stackIn[0];
}
//若栈顶指针均为0则代表队列为空
bool myQueueEmpty(MyQueue* obj) {
return obj->stackInTop == 0 && obj->stackOutTop == 0;
}
//将栈顶指针置0
void myQueueFree(MyQueue* obj) {
obj->stackInTop = 0;
obj->stackOutTop = 0;
}
```
-----------------------
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>