From 80dc27742439b6d1529c1aaefaad052dcdeab7b4 Mon Sep 17 00:00:00 2001
From: youngyangyang04 <826123027@qq.com>
Date: Tue, 24 Aug 2021 15:56:18 +0800
Subject: [PATCH] 20210824
---
README.md | 6 +
.../0052.N\347\232\207\345\220\216II.md" | 97 ++++++++++
...47\347\232\204\347\237\251\345\275\242.md" | 33 ++++
...11\346\220\234\347\264\242\346\240\221.md" | 40 ++--
...02\345\272\217\351\201\215\345\216\206.md" | 29 +++
...40\344\272\214\345\217\211\346\240\221.md" | 39 ++--
...54\344\272\214\345\217\211\346\240\221.md" | 2 +-
...36\347\216\260\351\230\237\345\210\227.md" | 47 -----
...53\345\206\267\345\206\273\346\234\237.md" | 4 +-
...\345\255\227\347\254\246\344\270\262II.md" | 2 +-
...66\344\272\214\345\217\211\346\240\221.md" | 23 +--
...47\344\272\214\345\217\211\346\240\221.md" | 41 ++--
...55\347\232\204\346\220\234\347\264\242.md" | 51 ++---
...60\347\233\256\346\216\222\345\272\217.md" | 177 +++++++-----------
...16\346\234\254\351\241\271\347\233\256.md" | 7 +
15 files changed, 331 insertions(+), 267 deletions(-)
create mode 100644 "problems/0052.N\347\232\207\345\220\216II.md"
create mode 100644 "problems/\345\205\266\344\273\226/\345\217\202\344\270\216\346\234\254\351\241\271\347\233\256.md"
diff --git a/README.md b/README.md
index 022a45e846..267d794e26 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,5 @@
👉 推荐 [在线阅读](http://programmercarl.com/) (Github在国内访问经常不稳定)
+👉 推荐 [Gitee同步](https://gitee.com/programmercarl/leetcode-master)
> 1. **介绍**:本项目是一套完整的刷题计划,旨在帮助大家少走弯路,循序渐进学算法,[关注作者](#关于作者)
> 2. **PDF版本** : [「代码随想录」算法精讲 PDF 版本](https://mp.weixin.qq.com/s/RsdcQ9umo09R6cfnwXZlrQ) 。
@@ -477,6 +478,11 @@
* [100.相同的树](./problems/0100.相同的树.md) 同101.对称二叉树 一个思路
* [116.填充每个节点的下一个右侧节点指针](./problems/0116.填充每个节点的下一个右侧节点指针.md)
+## 回溯算法
+
+* [52.N皇后II](./problems/0052.N皇后II.md)
+
+
## 贪心
* [649.Dota2参议院](./problems/0649.Dota2参议院.md) 有难度
diff --git "a/problems/0052.N\347\232\207\345\220\216II.md" "b/problems/0052.N\347\232\207\345\220\216II.md"
new file mode 100644
index 0000000000..81f5c7ea71
--- /dev/null
+++ "b/problems/0052.N\347\232\207\345\220\216II.md"
@@ -0,0 +1,97 @@
+
+
+
+
+
+
+
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+
+
+# 52. N皇后II
+
+题目链接:https://leetcode-cn.com/problems/n-queens-ii/
+
+n 皇后问题研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。
+
+上图为 8 皇后问题的一种解法。
+![51n皇后](https://img-blog.csdnimg.cn/20200821152118456.png)
+
+给定一个整数 n,返回 n 皇后不同的解决方案的数量。
+
+示例:
+
+输入: 4
+输出: 2
+解释: 4 皇后问题存在如下两个不同的解法。
+[
+ [".Q..", // 解法 1
+ "...Q",
+ "Q...",
+ "..Q."],
+
+ ["..Q.", // 解法 2
+ "Q...",
+ "...Q",
+ ".Q.."]
+]
+
+# 思路
+
+
+想看:[51.N皇后](https://mp.weixin.qq.com/s/lU_QwCMj6g60nh8m98GAWg) ,基本没有区别
+
+# C++代码
+
+```CPP
+class Solution {
+private:
+int count = 0;
+void backtracking(int n, int row, vector& chessboard) {
+ if (row == n) {
+ count++;
+ return;
+ }
+ for (int col = 0; col < n; col++) {
+ if (isValid(row, col, chessboard, n)) {
+ chessboard[row][col] = 'Q'; // 放置皇后
+ backtracking(n, row + 1, chessboard);
+ chessboard[row][col] = '.'; // 回溯
+ }
+ }
+}
+bool isValid(int row, int col, vector& chessboard, int n) {
+ int count = 0;
+ // 检查列
+ for (int i = 0; i < row; i++) { // 这是一个剪枝
+ if (chessboard[i][col] == 'Q') {
+ return false;
+ }
+ }
+ // 检查 45度角是否有皇后
+ for (int i = row - 1, j = col - 1; i >=0 && j >= 0; i--, j--) {
+ if (chessboard[i][j] == 'Q') {
+ return false;
+ }
+ }
+ // 检查 135度角是否有皇后
+ for(int i = row - 1, j = col + 1; i >= 0 && j < n; i--, j++) {
+ if (chessboard[i][j] == 'Q') {
+ return false;
+ }
+ }
+ return true;
+}
+
+public:
+ int totalNQueens(int n) {
+ std::vector chessboard(n, std::string(n, '.'));
+ backtracking(n, 0, chessboard);
+ return count;
+
+ }
+};
+```
+
+# 其他语言补充
+
diff --git "a/problems/0084.\346\237\261\347\212\266\345\233\276\344\270\255\346\234\200\345\244\247\347\232\204\347\237\251\345\275\242.md" "b/problems/0084.\346\237\261\347\212\266\345\233\276\344\270\255\346\234\200\345\244\247\347\232\204\347\237\251\345\275\242.md"
index 941888dba3..61910abf5d 100644
--- "a/problems/0084.\346\237\261\347\212\266\345\233\276\344\270\255\346\234\200\345\244\247\347\232\204\347\237\251\345\275\242.md"
+++ "b/problems/0084.\346\237\261\347\212\266\345\233\276\344\270\255\346\234\200\345\244\247\347\232\204\347\237\251\345\275\242.md"
@@ -195,6 +195,39 @@ public:
Java:
+动态规划
+```java
+class Solution {
+ public int largestRectangleArea(int[] heights) {
+ int length = heights.length;
+ int[] minLeftIndex = new int [length];
+ int[] maxRigthIndex = new int [length];
+ // 记录左边第一个小于该柱子的下标
+ minLeftIndex[0] = -1 ;
+ for (int i = 1; i < length; i++) {
+ int t = i - 1;
+ // 这里不是用if,而是不断向右寻找的过程
+ while (t >= 0 && heights[t] >= heights[i]) t = minLeftIndex[t];
+ minLeftIndex[i] = t;
+ }
+ // 记录每个柱子 右边第一个小于该柱子的下标
+ maxRigthIndex[length - 1] = length;
+ for (int i = length - 2; i >= 0; i--) {
+ int t = i + 1;
+ while(t < length && heights[t] >= heights[i]) t = maxRigthIndex[t];
+ maxRigthIndex[i] = t;
+ }
+ // 求和
+ int result = 0;
+ for (int i = 0; i < length; i++) {
+ int sum = heights[i] * (maxRigthIndex[i] - minLeftIndex[i] - 1);
+ result = Math.max(sum, result);
+ }
+ return result;
+ }
+}
+```
+
Python:
动态规划
diff --git "a/problems/0098.\351\252\214\350\257\201\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221.md" "b/problems/0098.\351\252\214\350\257\201\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221.md"
index 6f7e5c1465..9e31bfd6bb 100644
--- "a/problems/0098.\351\252\214\350\257\201\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221.md"
+++ "b/problems/0098.\351\252\214\350\257\201\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221.md"
@@ -7,7 +7,7 @@
欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
-## 98.验证二叉搜索树
+# 98.验证二叉搜索树
题目地址:https://leetcode-cn.com/problems/validate-binary-search-tree/
@@ -22,7 +22,7 @@
![98.验证二叉搜索树](https://img-blog.csdnimg.cn/20210203144334501.png)
-## 思路
+# 思路
要知道中序遍历下,输出的二叉搜索树节点的数值是有序序列。
@@ -121,7 +121,7 @@ if (root->val > root->left->val && root->val < root->right->val) {
要定义一个longlong的全局变量,用来比较遍历的节点是否有序,因为后台测试数据中有int最小值,所以定义为longlong的类型,初始化为longlong最小值。
-注意递归函数要有bool类型的返回值, 我们在[二叉树:递归函数究竟什么时候需要返回值,什么时候不要返回值?](https://mp.weixin.qq.com/s/6TWAVjxQ34kVqROWgcRFOg) 中讲了,只有寻找某一条边(或者一个节点)的时候,递归函数会有bool类型的返回值。
+注意递归函数要有bool类型的返回值, 我们在[二叉树:递归函数究竟什么时候需要返回值,什么时候不要返回值?](https://mp.weixin.qq.com/s/EJr_nZ31TnvZmptBjkDGqA) 中讲了,只有寻找某一条边(或者一个节点)的时候,递归函数会有bool类型的返回值。
其实本题是同样的道理,我们在寻找一个不符合条件的节点,如果没有找到这个节点就遍历了整个树,如果找到不符合的节点了,立刻返回。
@@ -210,7 +210,8 @@ public:
## 迭代法
-可以用迭代法模拟二叉树中序遍历,对前中后序迭代法生疏的同学可以看这两篇[二叉树:听说递归能做的,栈也能做!](https://mp.weixin.qq.com/s/c_zCrGHIVlBjUH_hJtghCg),[二叉树:前中后序迭代方式统一写法](https://mp.weixin.qq.com/s/WKg0Ty1_3SZkztpHubZPRg)
+
+可以用迭代法模拟二叉树中序遍历,对前中后序迭代法生疏的同学可以看这两篇[二叉树:听说递归能做的,栈也能做!](https://mp.weixin.qq.com/s/OH7aCVJ5-Gi32PkNCoZk4A),[二叉树:前中后序迭代方式统一写法](https://mp.weixin.qq.com/s/ATQMPCpBlaAgrqdLDMVPZA)
迭代法中序遍历稍加改动就可以了,代码如下:
@@ -240,9 +241,10 @@ public:
};
```
-在[二叉树:二叉搜索树登场!](https://mp.weixin.qq.com/s/vsKrWRlETxCVsiRr8v_hHg)中我们分明写出了痛哭流涕的简洁迭代法,怎么在这里不行了呢,因为本题是要验证二叉搜索树啊。
-## 总结
+在[二叉树:二叉搜索树登场!](https://mp.weixin.qq.com/s/muRjJulujBqZXW4apLkGpg)中我们分明写出了痛哭流涕的简洁迭代法,怎么在这里不行了呢,因为本题是要验证二叉搜索树啊。
+
+# 总结
这道题目是一个简单题,但对于没接触过的同学还是有难度的。
@@ -251,10 +253,10 @@ public:
只要把基本类型的题目都做过,总结过之后,思路自然就开阔了。
-## 其他语言版本
+# 其他语言版本
-Java:
+## Java
```Java
class Solution {
@@ -336,16 +338,10 @@ class Solution {
}
```
-Python:
+## Python
**递归** - 利用BST中序遍历特性,把树"压缩"成数组
```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 isValidBST(self, root: TreeNode) -> bool:
# 思路: 利用BST中序遍历的特性.
@@ -395,8 +391,9 @@ class Solution:
return is_left_valid and is_right_valid
return __isValidBST(root)
```
-```
-# 迭代-中序遍历
+
+```python
+迭代-中序遍历
class Solution:
def isValidBST(self, root: TreeNode) -> bool:
stack = []
@@ -415,7 +412,8 @@ class Solution:
return True
```
-Go:
+## Go
+
```Go
import "math"
@@ -458,9 +456,9 @@ func isValidBST(root *TreeNode) bool {
}
```
-JavaScript版本
+## JavaScript
-> 辅助数组解决
+辅助数组解决
```javascript
/**
@@ -493,7 +491,7 @@ var isValidBST = function (root) {
};
```
-> 递归中解决
+递归中解决
```javascript
/**
diff --git "a/problems/0102.\344\272\214\345\217\211\346\240\221\347\232\204\345\261\202\345\272\217\351\201\215\345\216\206.md" "b/problems/0102.\344\272\214\345\217\211\346\240\221\347\232\204\345\261\202\345\272\217\351\201\215\345\216\206.md"
index 0f9b2df659..954a19cd26 100644
--- "a/problems/0102.\344\272\214\345\217\211\346\240\221\347\232\204\345\261\202\345\272\217\351\201\215\345\216\206.md"
+++ "b/problems/0102.\344\272\214\345\217\211\346\240\221\347\232\204\345\261\202\345\272\217\351\201\215\345\216\206.md"
@@ -1573,6 +1573,35 @@ public:
Java:
+```java
+class Solution {
+ public int minDepth(TreeNode root){
+ if (root == null) {
+ return 0;
+ }
+ Queue queue = new LinkedList<>();
+ queue.offer(root);
+ int depth = 0;
+ while (!queue.isEmpty()){
+ int size = queue.size();
+ depth++;
+ TreeNode cur = null;
+ for (int i = 0; i < size; i++) {
+ cur = queue.poll();
+ //如果当前节点的左右孩子都为空,直接返回最小深度
+ if (cur.left == null && cur.right == null){
+ return depth;
+ }
+ if (cur.left != null) queue.offer(cur.left);
+ if (cur.right != null) queue.offer(cur.right);
+ }
+ }
+ return depth;
+ }
+}
+```
+
+
Python:
diff --git "a/problems/0106.\344\273\216\344\270\255\345\272\217\344\270\216\345\220\216\345\272\217\351\201\215\345\216\206\345\272\217\345\210\227\346\236\204\351\200\240\344\272\214\345\217\211\346\240\221.md" "b/problems/0106.\344\273\216\344\270\255\345\272\217\344\270\216\345\220\216\345\272\217\351\201\215\345\216\206\345\272\217\345\210\227\346\236\204\351\200\240\344\272\214\345\217\211\346\240\221.md"
index 4cfe28582a..b225807608 100644
--- "a/problems/0106.\344\273\216\344\270\255\345\272\217\344\270\216\345\220\216\345\272\217\351\201\215\345\216\206\345\272\217\345\210\227\346\236\204\351\200\240\344\272\214\345\217\211\346\240\221.md"
+++ "b/problems/0106.\344\273\216\344\270\255\345\272\217\344\270\216\345\220\216\345\272\217\351\201\215\345\216\206\345\272\217\345\210\227\346\236\204\351\200\240\344\272\214\345\217\211\346\240\221.md"
@@ -12,7 +12,7 @@
* 106.从中序与后序遍历序列构造二叉树
* 105.从前序与中序遍历序列构造二叉树
-## 106.从中序与后序遍历序列构造二叉树
+# 106.从中序与后序遍历序列构造二叉树
题目地址:https://leetcode-cn.com/problems/construct-binary-tree-from-inorder-and-postorder-traversal/
@@ -29,7 +29,7 @@
![106. 从中序与后序遍历序列构造二叉树1](https://img-blog.csdnimg.cn/20210203154316774.png)
-### 思路
+## 思路
首先回忆一下如何根据两个顺序构造一个唯一的二叉树,相信理论知识大家应该都清楚,就是以 后序数组的最后一个元素为切割点,先切中序数组,根据中序数组,反过来在切后序数组。一层一层切下去,每次后序数组最后一个元素就是节点元素。
@@ -95,7 +95,8 @@ TreeNode* traversal (vector& inorder, vector& postorder) {
**在切割的过程中会产生四个区间,把握不好不变量的话,一会左闭右开,一会左闭又闭,必然乱套!**
-我在[数组:每次遇到二分法,都是一看就会,一写就废](https://mp.weixin.qq.com/s/fCf5QbPDtE6SSlZ1yh_q8Q)和[数组:这个循环可以转懵很多人!](https://mp.weixin.qq.com/s/KTPhaeqxbMK9CxHUUgFDmg)中都强调过循环不变量的重要性,在二分查找以及螺旋矩阵的求解中,坚持循环不变量非常重要,本题也是。
+
+我在[704.二分查找](https://mp.weixin.qq.com/s/4X-8VRgnYRGd5LYGZ33m4w)和[59.螺旋矩阵II](https://mp.weixin.qq.com/s/Hn6-mlCPvKAdWbiFfQyaaw)中都强调过循环不变量的重要性,在二分查找以及螺旋矩阵的求解中,坚持循环不变量非常重要,本题也是。
首先要切割中序数组,为什么先切割中序数组呢?
@@ -105,7 +106,7 @@ TreeNode* traversal (vector& inorder, vector& postorder) {
中序数组相对比较好切,找到切割点(后序数组的最后一个元素)在中序数组的位置,然后切割,如下代码中我坚持左闭右开的原则:
-```
+```C++
// 找到中序遍历的切割点
int delimiterIndex;
for (delimiterIndex = 0; delimiterIndex < inorder.size(); delimiterIndex++) {
@@ -394,7 +395,7 @@ public:
};
```
-## 105.从前序与中序遍历序列构造二叉树
+# 105.从前序与中序遍历序列构造二叉树
题目地址:https://leetcode-cn.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/
@@ -411,7 +412,7 @@ public:
![105. 从前序与中序遍历序列构造二叉树](https://img-blog.csdnimg.cn/20210203154626672.png)
-### 思路
+## 思路
本题和106是一样的道理。
@@ -540,7 +541,7 @@ public:
};
```
-## 思考题
+# 思考题
前序和中序可以唯一确定一颗二叉树。
@@ -562,7 +563,7 @@ tree2 的前序遍历是[1 2 3], 后序遍历是[3 2 1]。
所以前序和后序不能唯一确定一颗二叉树!
-## 总结
+# 总结
之前我们讲的二叉树题目都是各种遍历二叉树,这次开始构造二叉树了,思路其实比较简单,但是真正代码实现出来并不容易。
@@ -578,9 +579,9 @@ tree2 的前序遍历是[1 2 3], 后序遍历是[3 2 1]。
-## 其他语言版本
+# 其他语言版本
-Java:
+## Java
106.从中序与后序遍历序列构造二叉树
@@ -653,7 +654,7 @@ class Solution {
}
```
-Python:
+## Python
105.从前序与中序遍历序列构造二叉树
@@ -685,7 +686,8 @@ class Solution:
root.right = self.buildTree(preorder_right, inorder_right)
return root
-```
+```
+
106.从中序与后序遍历序列构造二叉树
```python
@@ -716,9 +718,11 @@ class Solution:
root.right = self.buildTree(inorder_right, postorder_right)
return root
-```
-Go:
-> 106 从中序与后序遍历序列构造二叉树
+```
+
+## Go
+
+106 从中序与后序遍历序列构造二叉树
```go
/**
@@ -751,7 +755,7 @@ func findRootIndex(inorder []int,target int) (index int){
}
```
-> 105 从前序与中序遍历序列构造二叉树
+105 从前序与中序遍历序列构造二叉树
```go
/**
@@ -784,7 +788,8 @@ func findRootIndex(target int,inorder []int) int{
-JavaScript
+## JavaScript
+
```javascript
var buildTree = function(inorder, postorder) {
if (!postorder.length) return null
diff --git "a/problems/0226.\347\277\273\350\275\254\344\272\214\345\217\211\346\240\221.md" "b/problems/0226.\347\277\273\350\275\254\344\272\214\345\217\211\346\240\221.md"
index 6eb6f301f8..5bae8e3a94 100644
--- "a/problems/0226.\347\277\273\350\275\254\344\272\214\345\217\211\346\240\221.md"
+++ "b/problems/0226.\347\277\273\350\275\254\344\272\214\345\217\211\346\240\221.md"
@@ -43,7 +43,7 @@
**注意只要把每一个节点的左右孩子翻转一下,就可以达到整体翻转的效果**
-**这道题目使用前序遍历和后序遍历都可以,唯独中序遍历不行,因为中序遍历会把某些节点的左右孩子翻转了两次!建议拿纸画一画,就理解了**
+**这道题目使用前序遍历和后序遍历都可以,唯独中序遍历不方便,因为中序遍历会把某些节点的左右孩子翻转了两次!建议拿纸画一画,就理解了**
那么层序遍历可以不可以呢?**依然可以的!只要把每一个节点的左右孩子翻转一下的遍历方式都是可以的!**
diff --git "a/problems/0232.\347\224\250\346\240\210\345\256\236\347\216\260\351\230\237\345\210\227.md" "b/problems/0232.\347\224\250\346\240\210\345\256\236\347\216\260\351\230\237\345\210\227.md"
index 0df82d35b5..0da600fd54 100644
--- "a/problems/0232.\347\224\250\346\240\210\345\256\236\347\216\260\351\230\237\345\210\227.md"
+++ "b/problems/0232.\347\224\250\346\240\210\345\256\236\347\216\260\351\230\237\345\210\227.md"
@@ -176,53 +176,6 @@ class MyQueue {
}
```
-个人习惯写法,使用Deque通用api:
-```java
-class MyQueue {
- // java中的 Stack 有设计上的缺陷,官方推荐使用 Deque(双端队列) 代替 Stack
- // Deque 中的 addFirst、removeFirst、peekFirst 等方法等效于 Stack(堆栈) 中的 push、pop、peek
- Deque stIn;
- Deque stOut;
- /** Initialize your data structure here. */
- public MyQueue() {
- stIn = new ArrayDeque<>();
- stOut = new ArrayDeque<>();
- }
-
- /** Push element x to the back of queue. */
- public void push(int x) {
- stIn.addLast(x);
- }
-
- /** Removes the element from in front of queue and returns that element. */
- public int pop() {
- // 只要 stOut 为空,那么就应该将 stIn 中所有的元素倒腾到 stOut 中
- if (stOut.isEmpty()) {
- while (!stIn.isEmpty()) {
- stOut.addLast(stIn.pollLast());
- }
- }
- // 再返回 stOut 中的元素
- return stOut.pollLast();
- }
-
- /** Get the front element. */
- public int peek() {
- // 直接使用已有的pop函数
- int res = this.pop();
- // 因为pop函数弹出了元素res,所以再添加回去
- stOut.addLast(res);
- return res;
- }
-
- /** Returns whether the queue is empty. */
- public boolean empty() {
- // 当 stIn 栈为空时,说明没有元素可以倒腾到 stOut 栈了
- // 并且 stOut 栈也为空时,说明没有以前从 stIn 中倒腾到的元素了
- return stIn.isEmpty() && stOut.isEmpty();
- }
-}
-```
```java
class MyQueue {
diff --git "a/problems/0309.\346\234\200\344\275\263\344\271\260\345\215\226\350\202\241\347\245\250\346\227\266\346\234\272\345\220\253\345\206\267\345\206\273\346\234\237.md" "b/problems/0309.\346\234\200\344\275\263\344\271\260\345\215\226\350\202\241\347\245\250\346\227\266\346\234\272\345\220\253\345\206\267\345\206\273\346\234\237.md"
index 3b1b65003c..60f6ed8e57 100644
--- "a/problems/0309.\346\234\200\344\275\263\344\271\260\345\215\226\350\202\241\347\245\250\346\227\266\346\234\272\345\220\253\345\206\267\345\206\273\346\234\237.md"
+++ "b/problems/0309.\346\234\200\344\275\263\344\271\260\345\215\226\350\202\241\347\245\250\346\227\266\346\234\272\345\220\253\345\206\267\345\206\273\346\234\237.md"
@@ -10,7 +10,9 @@
题目链接:https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-with-cooldown/
-给定一个整数数组,其中第 i 个元素代表了第 i 天的股票价格 。
+[https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-with-cooldown/](https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-with-cooldown/)
+
+给定一个整数数组,其中第 i 个元素代表了第 i 天的股票价格 。
设计一个算法计算出最大利润。在满足以下约束条件下,你可以尽可能地完成更多的交易(多次买卖一支股票):
diff --git "a/problems/0541.\345\217\215\350\275\254\345\255\227\347\254\246\344\270\262II.md" "b/problems/0541.\345\217\215\350\275\254\345\255\227\347\254\246\344\270\262II.md"
index ab1ef16afa..386c2ed2c4 100644
--- "a/problems/0541.\345\217\215\350\275\254\345\255\227\347\254\246\344\270\262II.md"
+++ "b/problems/0541.\345\217\215\350\275\254\345\255\227\347\254\246\344\270\262II.md"
@@ -65,7 +65,7 @@ public:
};
```
-那么我们也可以实现自己的reverse函数,其实和题目[344. 反转字符串](https://mp.weixin.qq.com/s/_rNm66OJVl92gBDIbGpA3w)道理是一样的。
+那么我们也可以实现自己的reverse函数,其实和题目[344. 反转字符串](https://programmercarl.com/0541.反转字符串II.html)道理是一样的。
下面我实现的reverse函数区间是左闭右闭区间,代码如下:
diff --git "a/problems/0617.\345\220\210\345\271\266\344\272\214\345\217\211\346\240\221.md" "b/problems/0617.\345\220\210\345\271\266\344\272\214\345\217\211\346\240\221.md"
index b24a934b66..4714288def 100644
--- "a/problems/0617.\345\220\210\345\271\266\344\272\214\345\217\211\346\240\221.md"
+++ "b/problems/0617.\345\220\210\345\271\266\344\272\214\345\217\211\346\240\221.md"
@@ -7,7 +7,7 @@
欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
-## 617.合并二叉树
+# 617.合并二叉树
题目地址:https://leetcode-cn.com/problems/merge-two-binary-trees/
@@ -21,7 +21,7 @@
注意: 合并必须从两个树的根节点开始。
-## 思路
+# 思路
相信这道题目很多同学疑惑的点是如何同时遍历两个二叉树呢?
@@ -165,7 +165,8 @@ public:
使用迭代法,如何同时处理两棵树呢?
-思路我们在[二叉树:我对称么?](https://mp.weixin.qq.com/s/Kgf0gjvlDlNDfKIH2b1Oxg)中的迭代法已经讲过一次了,求二叉树对称的时候就是把两个树的节点同时加入队列进行比较。
+
+思路我们在[二叉树:我对称么?](https://mp.weixin.qq.com/s/5voTWHFuB9szmXGcJUzOPQ)中的迭代法已经讲过一次了,求二叉树对称的时候就是把两个树的节点同时加入队列进行比较。
本题我们也使用队列,模拟的层序遍历,代码如下:
@@ -209,7 +210,7 @@ public:
};
```
-## 拓展
+# 拓展
当然也可以秀一波指针的操作,这是我写的野路子,大家就随便看看就行了,以防带跑遍了。
@@ -241,21 +242,21 @@ public:
};
```
-## 总结
+# 总结
合并二叉树,也是二叉树操作的经典题目,如果没有接触过的话,其实并不简单,因为我们习惯了操作一个二叉树,一起操作两个二叉树,还会有点懵懵的。
-这不是我们第一次操作两颗二叉树了,在[二叉树:我对称么?](https://mp.weixin.qq.com/s/Kgf0gjvlDlNDfKIH2b1Oxg)中也一起操作了两棵二叉树。
+这不是我们第一次操作两颗二叉树了,在[二叉树:我对称么?](https://mp.weixin.qq.com/s/5voTWHFuB9szmXGcJUzOPQ)中也一起操作了两棵二叉树。
迭代法中,一般一起操作两个树都是使用队列模拟类似层序遍历,同时处理两个树的节点,这种方式最好理解,如果用模拟递归的思路的话,要复杂一些。
最后拓展中,我给了一个操作指针的野路子,大家随便看看就行了,如果学习C++的话,可以在去研究研究。
-## 其他语言版本
+# 其他语言版本
-Java:
+## Java
```Java
class Solution {
@@ -311,7 +312,7 @@ class Solution {
}
```
-Python:
+## Python
**递归法 - 前序遍历**
```python
@@ -374,7 +375,7 @@ class Solution:
return root1
```
-Go:
+## Go
```go
/**
@@ -468,7 +469,7 @@ func mergeTrees(root1 *TreeNode, root2 *TreeNode) *TreeNode {
}
```
-JavaScript:
+## JavaScript
```javascript
/**
diff --git "a/problems/0654.\346\234\200\345\244\247\344\272\214\345\217\211\346\240\221.md" "b/problems/0654.\346\234\200\345\244\247\344\272\214\345\217\211\346\240\221.md"
index 8c310a21f3..8c89064e9d 100644
--- "a/problems/0654.\346\234\200\345\244\247\344\272\214\345\217\211\346\240\221.md"
+++ "b/problems/0654.\346\234\200\345\244\247\344\272\214\345\217\211\346\240\221.md"
@@ -7,7 +7,7 @@
欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
-## 654.最大二叉树
+# 654.最大二叉树
题目地址:https://leetcode-cn.com/problems/maximum-binary-tree/
@@ -27,7 +27,7 @@
给定的数组的大小在 [1, 1000] 之间。
-## 思路
+# 思路
最大二叉树的构建过程如下:
@@ -41,7 +41,7 @@
代码如下:
-```
+```CPP
TreeNode* constructMaximumBinaryTree(vector& nums)
```
@@ -53,7 +53,7 @@ TreeNode* constructMaximumBinaryTree(vector& nums)
代码如下:
-```
+```CPP
TreeNode* node = new TreeNode(0);
if (nums.size() == 1) {
node->val = nums[0];
@@ -68,7 +68,7 @@ if (nums.size() == 1) {
1. 先要找到数组中最大的值和对应的下表, 最大的值构造根节点,下表用来下一步分割数组。
代码如下:
-```
+```CPP
int maxValue = 0;
int maxValueIndex = 0;
for (int i = 0; i < nums.size(); i++) {
@@ -86,7 +86,7 @@ node->val = maxValue;
这里要判断maxValueIndex > 0,因为要保证左区间至少有一个数值。
代码如下:
-```
+```CPP
if (maxValueIndex > 0) {
vector newVec(nums.begin(), nums.begin() + maxValueIndex);
node->left = constructMaximumBinaryTree(newVec);
@@ -99,7 +99,7 @@ if (maxValueIndex > 0) {
代码如下:
-```
+```CPP
if (maxValueIndex < (nums.size() - 1)) {
vector newVec(nums.begin() + maxValueIndex + 1, nums.end());
node->right = constructMaximumBinaryTree(newVec);
@@ -143,7 +143,7 @@ public:
以上代码比较冗余,效率也不高,每次还要切割的时候每次都要定义新的vector(也就是数组),但逻辑比较清晰。
-和文章[二叉树:构造二叉树登场!](https://mp.weixin.qq.com/s/7r66ap2s-shvVvlZxo59xg)中一样的优化思路,就是每次分隔不用定义新的数组,而是通过下表索引直接在原数组上操作。
+和文章[二叉树:构造二叉树登场!](https://mp.weixin.qq.com/s/Dza-fqjTyGrsRw4PWNKdxA)中一样的优化思路,就是每次分隔不用定义新的数组,而是通过下表索引直接在原数组上操作。
优化后代码如下:
@@ -177,7 +177,7 @@ public:
};
```
-## 拓展
+# 拓展
可以发现上面的代码看上去简洁一些,**主要是因为第二版其实是允许空节点进入递归,所以不用在递归的时候加判断节点是否为空**
@@ -209,10 +209,9 @@ root->right = traversal(nums, maxValueIndex + 1, right);
第二版相应的终止条件,是遇到空节点,也就是数组区间为0,就终止了。
+# 总结
-## 总结
-
-这道题目其实和 [二叉树:构造二叉树登场!](https://mp.weixin.qq.com/s/7r66ap2s-shvVvlZxo59xg) 是一个思路,比[二叉树:构造二叉树登场!](https://mp.weixin.qq.com/s/7r66ap2s-shvVvlZxo59xg) 还简单一些。
+这道题目其实和 [二叉树:构造二叉树登场!](https://mp.weixin.qq.com/s/Dza-fqjTyGrsRw4PWNKdxA) 是一个思路,比[二叉树:构造二叉树登场!](https://mp.weixin.qq.com/s/Dza-fqjTyGrsRw4PWNKdxA) 还简单一些。
**注意类似用数组构造二叉树的题目,每次分隔尽量不要定义新的数组,而是通过下表索引直接在原数组上操作,这样可以节约时间和空间上的开销。**
@@ -220,10 +219,10 @@ root->right = traversal(nums, maxValueIndex + 1, right);
其实就是不同代码风格的实现,**一般情况来说:如果让空节点(空指针)进入递归,就不加if,如果不让空节点进入递归,就加if限制一下, 终止条件也会相应的调整。**
-## 其他语言版本
+# 其他语言版本
-Java:
+## Java
```Java
class Solution {
@@ -255,14 +254,9 @@ class Solution {
}
```
-Python:
+## Python
+
```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 constructMaximumBinaryTree(self, nums: List[int]) -> TreeNode:
@@ -276,9 +270,8 @@ class Solution:
return root
```
-Go:
+## Go
-> 654. 最大二叉树
```go
/**
@@ -311,7 +304,7 @@ func findMax(nums []int) (index int){
}
```
-JavaScript版本
+## JavaScript
```javascript
/**
diff --git "a/problems/0700.\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\344\270\255\347\232\204\346\220\234\347\264\242.md" "b/problems/0700.\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\344\270\255\347\232\204\346\220\234\347\264\242.md"
index 68d30e3f85..ec050fefc7 100644
--- "a/problems/0700.\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\344\270\255\347\232\204\346\220\234\347\264\242.md"
+++ "b/problems/0700.\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\344\270\255\347\232\204\346\220\234\347\264\242.md"
@@ -7,7 +7,7 @@
欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
-## 700.二叉搜索树中的搜索
+# 700.二叉搜索树中的搜索
题目地址:https://leetcode-cn.com/problems/search-in-a-binary-search-tree/
@@ -19,11 +19,12 @@
在上述示例中,如果要找的值是 5,但因为没有节点值为 5,我们应该返回 NULL。
-## 思路
+# 思路
之前我们讲了都是普通二叉树,那么接下来看看二叉搜索树。
-在[关于二叉树,你该了解这些!](https://mp.weixin.qq.com/s/_ymfWYvTNd2GvWvC5HOE4A)中,我们已经讲过了二叉搜索树。
+
+在[关于二叉树,你该了解这些!](https://mp.weixin.qq.com/s/q_eKfL8vmSbSFcptZ3aeRA)中,我们已经讲过了二叉搜索树。
二叉搜索树是一个有序树:
@@ -73,7 +74,7 @@ return NULL;
这里可能会疑惑,在递归遍历的时候,什么时候直接return 递归函数的返回值,什么时候不用加这个 return呢。
-我们在[二叉树:递归函数究竟什么时候需要返回值,什么时候不要返回值?](https://mp.weixin.qq.com/s/6TWAVjxQ34kVqROWgcRFOg)中讲了,如果要搜索一条边,递归函数就要加返回值,这里也是一样的道理。
+我们在[二叉树:路径总和](https://mp.weixin.qq.com/s/EJr_nZ31TnvZmptBjkDGqA)中讲了,如果要搜索一条边,递归函数就要加返回值,这里也是一样的道理。
**因为搜索到目标节点了,就要立即return了,这样才是找到节点就返回(搜索某一条边),如果不加return,就是遍历整棵树了。**
@@ -125,7 +126,7 @@ public:
第一次看到了如此简单的迭代法,是不是感动的痛哭流涕,哭一会~
-## 总结
+# 总结
本篇我们介绍了二叉搜索树的遍历方式,因为二叉搜索树的有序性,遍历的时候要比普通二叉树简单很多。
@@ -138,9 +139,9 @@ public:
-## 其他语言版本
+# 其他语言版本
-Java:
+## Java
```Java
class Solution {
@@ -207,17 +208,11 @@ class Solution {
}
```
-Python:
+## Python
递归法:
```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 searchBST(self, root: TreeNode, val: int) -> TreeNode:
# 为什么要有返回值:
@@ -248,19 +243,11 @@ class Solution:
```
-Go:
+## Go
-> 递归法
+递归法:
```go
-/**
- * Definition for a binary tree node.
- * type TreeNode struct {
- * Val int
- * Left *TreeNode
- * Right *TreeNode
- * }
- */
//递归法
func searchBST(root *TreeNode, val int) *TreeNode {
if root==nil||root.Val==val{
@@ -273,17 +260,9 @@ func searchBST(root *TreeNode, val int) *TreeNode {
}
```
-> 迭代法
+迭代法:
```go
-/**
- * Definition for a binary tree node.
- * type TreeNode struct {
- * Val int
- * Left *TreeNode
- * Right *TreeNode
- * }
- */
//迭代法
func searchBST(root *TreeNode, val int) *TreeNode {
for root!=nil{
@@ -299,9 +278,9 @@ func searchBST(root *TreeNode, val int) *TreeNode {
}
```
-JavaScript版本
+## JavaScript
-> 递归
+递归:
```javascript
/**
@@ -329,7 +308,7 @@ var searchBST = function (root, val) {
};
```
-> 迭代
+迭代:
```javascript
/**
diff --git "a/problems/1356.\346\240\271\346\215\256\346\225\260\345\255\227\344\272\214\350\277\233\345\210\266\344\270\2131\347\232\204\346\225\260\347\233\256\346\216\222\345\272\217.md" "b/problems/1356.\346\240\271\346\215\256\346\225\260\345\255\227\344\272\214\350\277\233\345\210\266\344\270\2131\347\232\204\346\225\260\347\233\256\346\216\222\345\272\217.md"
index 300aa0e256..e94a32d3f9 100644
--- "a/problems/1356.\346\240\271\346\215\256\346\225\260\345\255\227\344\272\214\350\277\233\345\210\266\344\270\2131\347\232\204\346\225\260\347\233\256\346\216\222\345\272\217.md"
+++ "b/problems/1356.\346\240\271\346\215\256\346\225\260\345\255\227\344\272\214\350\277\233\345\210\266\344\270\2131\347\232\204\346\225\260\347\233\256\346\216\222\345\272\217.md"
@@ -7,112 +7,113 @@
欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
-# 1365.有多少小于当前数字的数字
-题目链接:https://leetcode-cn.com/problems/sort-integers-by-the-number-of-1-bits/
+# 1356. 根据数字二进制下 1 的数目排序
-给你一个数组 nums,对于其中每个元素 nums[i],请你统计数组中比它小的所有数字的数目。
+题目链接:https://leetcode-cn.com/problems/sort-integers-by-the-number-of-1-bits/
-换而言之,对于每个 nums[i] 你必须计算出有效的 j 的数量,其中 j 满足 j != i 且 nums[j] < nums[i] 。
+给你一个整数数组 arr 。请你将数组中的元素按照其二进制表示中数字 1 的数目升序排序。
-以数组形式返回答案。
+如果存在多个数字二进制中 1 的数目相同,则必须将它们按照数值大小升序排列。
+请你返回排序后的数组。
示例 1:
-输入:nums = [8,1,2,2,3]
-输出:[4,0,1,1,3]
-解释:
-对于 nums[0]=8 存在四个比它小的数字:(1,2,2 和 3)。
-对于 nums[1]=1 不存在比它小的数字。
-对于 nums[2]=2 存在一个比它小的数字:(1)。
-对于 nums[3]=2 存在一个比它小的数字:(1)。
-对于 nums[4]=3 存在三个比它小的数字:(1,2 和 2)。
+* 输入:arr = [0,1,2,3,4,5,6,7,8]
+* 输出:[0,1,2,4,8,3,5,6,7]
+* 解释:[0] 是唯一一个有 0 个 1 的数。
+[1,2,4,8] 都有 1 个 1 。
+[3,5,6] 有 2 个 1 。
+[7] 有 3 个 1 。按照 1 的个数排序得到的结果数组为 [0,1,2,4,8,3,5,6,7]
+
示例 2:
-输入:nums = [6,5,4,8]
-输出:[2,1,0,3]
+* 输入:arr = [1024,512,256,128,64,32,16,8,4,2,1]
+* 输出:[1,2,4,8,16,32,64,128,256,512,1024]
+* 解释:数组中所有整数二进制下都只有 1 个 1 ,所以你需要按照数值大小将它们排序。
示例 3:
-输入:nums = [7,7,7,7]
-输出:[0,0,0,0]
-
-提示:
-* 2 <= nums.length <= 500
-* 0 <= nums[i] <= 100
-
-# 思路
-
-两层for循环暴力查找,时间复杂度明显为O(n^2)。
-
-那么我们来看一下如何优化。
+* 输入:arr = [10000,10000]
+* 输出:[10000,10000]
-首先要找小于当前数字的数字,那么从小到大排序之后,该数字之前的数字就都是比它小的了。
+示例 4:
+* 输入:arr = [2,3,5,7,11,13,17,19]
+* 输出:[2,3,5,17,7,11,13,19]
-所以可以定义一个新数组,将数组排个序。
+示例 5:
+* 输入:arr = [10,100,1000,10000]
+* 输出:[10,100,10000,1000]
-**排序之后,其实每一个数值的下标就代表这前面有几个比它小的了**。
-代码如下:
-```
-vector vec = nums;
-sort(vec.begin(), vec.end()); // 从小到大排序之后,元素下标就是小于当前数字的数字
-```
+# 思路
-此时用一个哈希表hash(本题可以就用一个数组)来做数值和下标的映射。这样就可以通过数值快速知道下标(也就是前面有几个比它小的)。
+这道题其实是考察如何计算一个数的二进制中1的数量。
-此时有一个情况,就是数值相同怎么办?
+我提供两种方法:
-例如,数组:1 2 3 4 4 4 ,第一个数值4的下标是3,第二个数值4的下标是4了。
+* 方法一:
-这里就需要一个技巧了,**在构造数组hash的时候,从后向前遍历,这样hash里存放的就是相同元素最左面的数值和下标了**。
-代码如下:
+朴实无华挨个计算1的数量,最多就是循环n的二进制位数,32位。
-```CPP
-int hash[101];
-for (int i = vec.size() - 1; i >= 0; i--) { // 从后向前,记录 vec[i] 对应的下标
- hash[vec[i]] = i;
+```C++
+int bitCount(int n) {
+ int count = 0; // 计数器
+ while (n > 0) {
+ if((n & 1) == 1) count++; // 当前位是1,count++
+ n >>= 1 ; // n向右移位
+ }
+ return count;
}
```
-最后在遍历原数组nums,用hash快速找到每一个数值 对应的 小于这个数值的个数。存放在将结果存放在另一个数组中。
+* 方法二
-代码如下:
+这种方法,只循环n的二进制中1的个数次,比方法一高效的多
-```CPP
-// 此时hash里保存的每一个元素数值 对应的 小于这个数值的个数
-for (int i = 0; i < nums.size(); i++) {
- vec[i] = hash[nums[i]];
+```C++
+int bitCount(int n) {
+ int count = 0;
+ while (n) {
+ n &= (n - 1); // 清除最低位的1
+ count++;
+ }
+ return count;
}
```
+以计算12的二进制1的数量为例,如图所示:
-流程如图:
+
-
+下面我就使用方法二,来做这道题目:
-关键地方讲完了,整体C++代码如下:
+## C++代码
-```CPP
+```C++
class Solution {
-public:
- vector smallerNumbersThanCurrent(vector& nums) {
- vector vec = nums;
- sort(vec.begin(), vec.end()); // 从小到大排序之后,元素下标就是小于当前数字的数字
- int hash[101];
- for (int i = vec.size() - 1; i >= 0; i--) { // 从后向前,记录 vec[i] 对应的下标
- hash[vec[i]] = i;
- }
- // 此时hash里保存的每一个元素数值 对应的 小于这个数值的个数
- for (int i = 0; i < nums.size(); i++) {
- vec[i] = hash[nums[i]];
+private:
+ static int bitCount(int n) { // 计算n的二进制中1的数量
+ int count = 0;
+ while(n) {
+ n &= (n -1); // 清除最低位的1
+ count++;
}
- return vec;
+ return count;
+ }
+ static bool cmp(int a, int b) {
+ int bitA = bitCount(a);
+ int bitB = bitCount(b);
+ if (bitA == bitB) return a < b; // 如果bit中1数量相同,比较数值大小
+ return bitA < bitB; // 否则比较bit中1数量大小
+ }
+public:
+ vector sortByBits(vector& arr) {
+ sort(arr.begin(), arr.end(), cmp);
+ return arr;
}
};
```
-可以排序之后加哈希,时间复杂度为O(nlogn)
-
# 其他语言版本
@@ -120,48 +121,8 @@ public:
## Java
```java
-/**
-* 解法一:暴力
-* 时间复杂度:O(n^2)
-* 空间复杂度:O(n)
-*/
-class Solution {
- public int[] smallerNumbersThanCurrent(int[] nums) {
- int[] res = new int[nums.length];
- for (int i = 0; i < nums.length; i++) {
- for (int j = 0; j < nums.length; j++) {
- if (nums[j] < nums[i] && j != i) { // 注意 j 不能和 i 重合
- res[i]++;
- }
- }
- }
- return res;
- }
-}
```
-```java
-/**
-* 优化:排序 + 哈希表
-* 时间复杂度:O(nlogn)
-* 空间复杂度:O(n)
-*/
-class Solution {
- public int[] smallerNumbersThanCurrent(int[] nums) {
- int[] res = Arrays.copyOf(nums, nums.length);
- Arrays.sort(res); // 是对 res 排序,nums 中顺序还要保持
- int[] hash = new int[101]; // 使用哈希表,记录比当前元素小的元素个数
- for (int i = res.length - 1; i >= 0; i--) { // 注意:从后向前
- hash[res[i]] = i; // 排序后,当前下标即表示比当前元素小的元素个数
- }
- // 此时 hash中保存的每一个元素数值 便是 小于这个数值的个数
- for (int i = 0; i < res.length; i++) {
- res[i] = hash[nums[i]];
- }
- return res;
- }
-}
-```
diff --git "a/problems/\345\205\266\344\273\226/\345\217\202\344\270\216\346\234\254\351\241\271\347\233\256.md" "b/problems/\345\205\266\344\273\226/\345\217\202\344\270\216\346\234\254\351\241\271\347\233\256.md"
new file mode 100644
index 0000000000..69cb855532
--- /dev/null
+++ "b/problems/\345\205\266\344\273\226/\345\217\202\344\270\216\346\234\254\351\241\271\347\233\256.md"
@@ -0,0 +1,7 @@
+
+优化已有代码
+![](https://code-thinking-1253855093.file.myqcloud.com/pics/20210821161813.png)
+
+**push代码之前 一定要 先pull最新代码**,否则提交的pr可能会有删除其他录友代码的操作。
+
+一个pr 不要修改过多文件,因为一旦有一个 文件修改有问题,就不能合入,影响其他文件的合入了。