mirror of
https://github.com/youngyangyang04/leetcode-master.git
synced 2025-07-08 00:43:04 +08:00
更新代码块
This commit is contained in:
@ -67,7 +67,7 @@
|
||||
|
||||
以上三种情况分析完了,那么递归公式如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
if (s[i] == s[j]) {
|
||||
if (j - i <= 1) { // 情况一 和 情况二
|
||||
dp[i][j] = true;
|
||||
@ -81,7 +81,7 @@ if (s[i] == s[j]) {
|
||||
|
||||
在得到[i,j]区间是否是回文子串的时候,直接保存最长回文子串的左边界和右边界,代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
if (s[i] == s[j]) {
|
||||
if (j - i <= 1) { // 情况一 和 情况二
|
||||
dp[i][j] = true;
|
||||
@ -120,7 +120,7 @@ dp[i + 1][j - 1] 在 dp[i][j]的左下角,如图:
|
||||
|
||||
代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
for (int i = s.size() - 1; i >= 0; i--) { // 注意遍历顺序
|
||||
for (int j = i; j < s.size(); j++) {
|
||||
if (s[i] == s[j]) {
|
||||
@ -150,7 +150,7 @@ for (int i = s.size() - 1; i >= 0; i--) { // 注意遍历顺序
|
||||
|
||||
以上分析完毕,C++代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
string longestPalindrome(string s) {
|
||||
@ -181,7 +181,7 @@ public:
|
||||
```
|
||||
以上代码是为了凸显情况一二三,当然是可以简洁一下的,如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
string longestPalindrome(string s) {
|
||||
@ -226,7 +226,7 @@ public:
|
||||
|
||||
**这两种情况可以放在一起计算,但分别计算思路更清晰,我倾向于分别计算**,代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
int left = 0;
|
||||
|
@ -46,7 +46,7 @@ https://leetcode-cn.com/problems/3sum/
|
||||
大家可以尝试使用哈希法写一写,就知道其困难的程度了。
|
||||
|
||||
哈希法C++代码:
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
vector<vector<int>> threeSum(vector<int>& nums) {
|
||||
@ -107,7 +107,7 @@ public:
|
||||
|
||||
C++代码代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
vector<vector<int>> threeSum(vector<int>& nums) {
|
||||
|
@ -67,7 +67,7 @@ https://leetcode-cn.com/problems/4sum/
|
||||
|
||||
C++代码
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
vector<vector<int>> fourSum(vector<int>& nums, int target) {
|
||||
|
@ -58,7 +58,7 @@
|
||||
|
||||
此时不难写出如下C++代码:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
ListNode* removeNthFromEnd(ListNode* head, int n) {
|
||||
|
@ -108,7 +108,7 @@ cd a/b/c/../../
|
||||
实现C++代码如下:
|
||||
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
bool isValid(string s) {
|
||||
|
@ -43,7 +43,7 @@ https://leetcode-cn.com/problems/swap-nodes-in-pairs/
|
||||
|
||||
对应的C++代码实现如下: (注释中详细和如上图中的三步做对应)
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
ListNode* swapPairs(ListNode* head) {
|
||||
|
@ -48,7 +48,7 @@
|
||||
|
||||
代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
// 时间复杂度:O(n^2)
|
||||
// 空间复杂度:O(1)
|
||||
class Solution {
|
||||
@ -85,7 +85,7 @@ public:
|
||||
|
||||
后序都会一一介绍到,本题代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
// 时间复杂度:O(n)
|
||||
// 空间复杂度:O(1)
|
||||
class Solution {
|
||||
|
@ -315,7 +315,7 @@ next[i] = j;
|
||||
|
||||
最后整体构建next数组的函数代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
void getNext(int* next, const string& s){
|
||||
int j = -1;
|
||||
next[0] = j;
|
||||
@ -386,7 +386,7 @@ if (j == (t.size() - 1) ) {
|
||||
|
||||
那么使用next数组,用模式串匹配文本串的整体代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
int j = -1; // 因为next数组里记录的起始位置为-1
|
||||
for (int i = 0; i < s.size(); i++) { // 注意i就从0开始
|
||||
while(j >= 0 && s[i] != t[j + 1]) { // 不匹配
|
||||
@ -405,7 +405,7 @@ for (int i = 0; i < s.size(); i++) { // 注意i就从0开始
|
||||
|
||||
# 前缀表统一减一 C++代码实现
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
void getNext(int* next, const string& s) {
|
||||
@ -457,7 +457,7 @@ public:
|
||||
|
||||
我给出的getNext的实现为:(前缀表统一减一)
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
void getNext(int* next, const string& s) {
|
||||
int j = -1;
|
||||
next[0] = j;
|
||||
@ -479,7 +479,7 @@ void getNext(int* next, const string& s) {
|
||||
|
||||
那么前缀表不减一来构建next数组,代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
void getNext(int* next, const string& s) {
|
||||
int j = 0;
|
||||
next[0] = 0;
|
||||
@ -502,7 +502,7 @@ void getNext(int* next, const string& s) {
|
||||
|
||||
实现代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
void getNext(int* next, const string& s) {
|
||||
|
@ -75,7 +75,7 @@
|
||||
|
||||
对应的C++代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
void nextPermutation(vector<int>& nums) {
|
||||
|
@ -64,7 +64,7 @@
|
||||
|
||||
可以写出如下代码
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
// 二分查找,寻找target的右边界(不包括target)
|
||||
// 如果rightBorder为没有被赋值(即target在数组范围的左边,例如数组[3,3],target为2),为了处理情况一
|
||||
int getRightBorder(vector<int>& nums, int target) {
|
||||
@ -86,7 +86,7 @@ int getRightBorder(vector<int>& nums, int target) {
|
||||
|
||||
## 寻找左边界
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
// 二分查找,寻找target的左边界leftBorder(不包括target)
|
||||
// 如果leftBorder没有被赋值(即target在数组范围的右边,例如数组[3,3],target为4),为了处理情况一
|
||||
int getLeftBorder(vector<int>& nums, int target) {
|
||||
@ -110,7 +110,7 @@ int getLeftBorder(vector<int>& nums, int target) {
|
||||
|
||||
左右边界计算完之后,看一下主体代码,这里把上面讨论的三种情况,都覆盖了
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
vector<int> searchRange(vector<int>& nums, int target) {
|
||||
|
@ -116,7 +116,7 @@ public:
|
||||
|
||||
**大家要仔细看注释,思考为什么要写while(left <= right), 为什么要写right = middle - 1**。
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
int searchInsert(vector<int>& nums, int target) {
|
||||
@ -158,7 +158,7 @@ public:
|
||||
|
||||
**大家要仔细看注释,思考为什么要写while (left < right), 为什么要写right = middle**。
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
int searchInsert(vector<int>& nums, int target) {
|
||||
|
@ -90,7 +90,7 @@ bool backtracking(vector<vector<char>>& board)
|
||||
|
||||
代码如下:(**详细看注释**)
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
bool backtracking(vector<vector<char>>& board) {
|
||||
for (int i = 0; i < board.size(); i++) { // 遍历行
|
||||
for (int j = 0; j < board[0].size(); j++) { // 遍历列
|
||||
@ -125,7 +125,7 @@ bool backtracking(vector<vector<char>>& board) {
|
||||
|
||||
代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
bool isValid(int row, int col, char val, vector<vector<char>>& board) {
|
||||
for (int i = 0; i < 9; i++) { // 判断行里是否重复
|
||||
if (board[row][i] == val) {
|
||||
@ -154,7 +154,7 @@ bool isValid(int row, int col, char val, vector<vector<char>>& board) {
|
||||
|
||||
## C++代码
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
private:
|
||||
bool backtracking(vector<vector<char>>& board) {
|
||||
|
@ -73,7 +73,7 @@ candidates 中的数字可以无限制重复被选取。
|
||||
|
||||
代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
vector<vector<int>> result;
|
||||
vector<int> path;
|
||||
void backtracking(vector<int>& candidates, int target, int sum, int startIndex)
|
||||
@ -89,7 +89,7 @@ void backtracking(vector<int>& candidates, int target, int sum, int startIndex)
|
||||
|
||||
sum等于target的时候,需要收集结果,代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
if (sum > target) {
|
||||
return;
|
||||
}
|
||||
@ -107,7 +107,7 @@ if (sum == target) {
|
||||
|
||||
如何重复选取呢,看代码,注释部分:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
for (int i = startIndex; i < candidates.size(); i++) {
|
||||
sum += candidates[i];
|
||||
path.push_back(candidates[i]);
|
||||
@ -119,7 +119,7 @@ for (int i = startIndex; i < candidates.size(); i++) {
|
||||
|
||||
按照[关于回溯算法,你该了解这些!](https://mp.weixin.qq.com/s/gjSgJbNbd1eAA5WkA-HeWw)中给出的模板,不难写出如下C++完整代码:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
// 版本一
|
||||
class Solution {
|
||||
private:
|
||||
@ -179,7 +179,7 @@ for (int i = startIndex; i < candidates.size() && sum + candidates[i] <= target;
|
||||
|
||||
整体代码如下:(注意注释的部分)
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
private:
|
||||
vector<vector<int>> result;
|
||||
|
@ -90,7 +90,7 @@ candidates 中的每个数字在每个组合中只能使用一次。
|
||||
|
||||
代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
vector<vector<int>> result; // 存放组合集合
|
||||
vector<int> path; // 符合条件的组合
|
||||
void backtracking(vector<int>& candidates, int target, int sum, int startIndex, vector<bool>& used) {
|
||||
@ -102,7 +102,7 @@ void backtracking(vector<int>& candidates, int target, int sum, int startIndex,
|
||||
|
||||
代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
if (sum > target) { // 这个条件其实可以省略
|
||||
return;
|
||||
}
|
||||
@ -137,7 +137,7 @@ if (sum == target) {
|
||||
|
||||
那么单层搜索的逻辑代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
for (int i = startIndex; i < candidates.size() && sum + candidates[i] <= target; i++) {
|
||||
// used[i - 1] == true,说明同一树支candidates[i - 1]使用过
|
||||
// used[i - 1] == false,说明同一树层candidates[i - 1]使用过
|
||||
@ -161,7 +161,7 @@ for (int i = startIndex; i < candidates.size() && sum + candidates[i] <= target;
|
||||
|
||||
回溯三部曲分析完了,整体C++代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
private:
|
||||
vector<vector<int>> result;
|
||||
@ -206,7 +206,7 @@ public:
|
||||
|
||||
这里直接用startIndex来去重也是可以的, 就不用used数组了。
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
private:
|
||||
vector<vector<int>> result;
|
||||
|
@ -77,7 +77,7 @@
|
||||
一样的方法,只要从头遍历一遍所有的列,然后求出每一列雨水的体积,相加之后就是总雨水的体积了。
|
||||
|
||||
首先从头遍历所有的列,并且**要注意第一个柱子和最后一个柱子不接雨水**,代码如下:
|
||||
```C++
|
||||
```CPP
|
||||
for (int i = 0; i < height.size(); i++) {
|
||||
// 第一个柱子和最后一个柱子不接雨水
|
||||
if (i == 0 || i == height.size() - 1) continue;
|
||||
@ -86,7 +86,7 @@ for (int i = 0; i < height.size(); i++) {
|
||||
|
||||
在for循环中求左右两边最高柱子,代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
int rHeight = height[i]; // 记录右边柱子的最高高度
|
||||
int lHeight = height[i]; // 记录左边柱子的最高高度
|
||||
for (int r = i + 1; r < height.size(); r++) {
|
||||
@ -99,14 +99,14 @@ for (int l = i - 1; l >= 0; l--) {
|
||||
|
||||
最后,计算该列的雨水高度,代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
int h = min(lHeight, rHeight) - height[i];
|
||||
if (h > 0) sum += h; // 注意只有h大于零的时候,在统计到总和中
|
||||
```
|
||||
|
||||
整体代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
int trap(vector<int>& height) {
|
||||
@ -152,7 +152,7 @@ public:
|
||||
|
||||
代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
int trap(vector<int>& height) {
|
||||
@ -287,7 +287,7 @@ if (height[i] == height[st.top()]) { // 例如 5 5 1 7 这种情况
|
||||
|
||||
求当前凹槽雨水的体积代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
while (!st.empty() && height[i] > height[st.top()]) { // 注意这里是while,持续跟新栈顶元素
|
||||
int mid = st.top();
|
||||
st.pop();
|
||||
@ -301,7 +301,7 @@ while (!st.empty() && height[i] > height[st.top()]) { // 注意这里是while,
|
||||
|
||||
关键部分讲完了,整体代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
int trap(vector<int>& height) {
|
||||
@ -335,7 +335,7 @@ public:
|
||||
|
||||
以上代码冗余了一些,但是思路是清晰的,下面我将代码精简一下,如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
int trap(vector<int>& height) {
|
||||
|
@ -63,7 +63,7 @@
|
||||
|
||||
C++代码如下:(详细注释)
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
// 版本一
|
||||
class Solution {
|
||||
public:
|
||||
@ -106,7 +106,7 @@ public:
|
||||
|
||||
代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
// 版本二
|
||||
class Solution {
|
||||
public:
|
||||
|
@ -106,7 +106,7 @@ for (int i = 0; i < nums.size(); i++) {
|
||||
整体C++代码如下:
|
||||
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
vector<vector<int>> result;
|
||||
|
@ -171,7 +171,7 @@ bool isValid(int row, int col, vector<string>& chessboard, int n) {
|
||||
|
||||
## C++代码
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
private:
|
||||
vector<vector<string>> result;
|
||||
|
@ -25,7 +25,7 @@
|
||||
|
||||
时间复杂度:O(n^2)
|
||||
空间复杂度:O(1)
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
int maxSubArray(vector<int>& nums) {
|
||||
@ -81,7 +81,7 @@ if (count > result) result = count;
|
||||
|
||||
那么不难写出如下C++代码(关键地方已经注释)
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
int maxSubArray(vector<int>& nums) {
|
||||
@ -109,7 +109,7 @@ public:
|
||||
|
||||
那么先给出我的dp代码如下,有时间的录友可以提前做一做:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
int maxSubArray(vector<int>& nums) {
|
||||
|
@ -65,7 +65,7 @@ dp[0]应该是多少呢?
|
||||
|
||||
以上动规五部曲分析完毕,完整代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
int maxSubArray(vector<int>& nums) {
|
||||
|
@ -58,7 +58,7 @@ i每次移动只能在cover的范围内移动,每移动一个元素,cover得
|
||||
|
||||
C++代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
bool canJump(vector<int>& nums) {
|
||||
|
@ -56,7 +56,7 @@
|
||||
|
||||
C++代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
// 按照区间左边界从小到大排序
|
||||
@ -92,7 +92,7 @@ public:
|
||||
|
||||
当然以上代码有冗余一些,可以优化一下,如下:(思路是一样的)
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
vector<vector<int>> merge(vector<vector<int>>& intervals) {
|
||||
|
@ -66,7 +66,7 @@
|
||||
|
||||
整体C++代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
vector<vector<int>> generateMatrix(int n) {
|
||||
|
@ -59,7 +59,7 @@
|
||||
|
||||
此时问题就可以转化为求二叉树叶子节点的个数,代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
private:
|
||||
int dfs(int i, int j, int m, int n) {
|
||||
@ -128,7 +128,7 @@ for (int j = 0; j < n; j++) dp[0][j] = 1;
|
||||
|
||||
以上动规五部曲分析完毕,C++代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
int uniquePaths(int m, int n) {
|
||||
@ -149,7 +149,7 @@ public:
|
||||
|
||||
其实用一个一维数组(也可以理解是滚动数组)就可以了,但是不利于理解,可以优化点空间,建议先理解了二维,在理解一维,C++代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
int uniquePaths(int m, int n) {
|
||||
@ -187,7 +187,7 @@ public:
|
||||
|
||||
例如如下代码是不行的。
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
int uniquePaths(int m, int n) {
|
||||
@ -204,7 +204,7 @@ public:
|
||||
|
||||
需要在计算分子的时候,不断除以分母,代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
int uniquePaths(int m, int n) {
|
||||
|
@ -97,7 +97,7 @@ for (int j = 0; j < n; j++) dp[0][j] = 1;
|
||||
|
||||
所以本题初始化代码为:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
vector<vector<int>> dp(m, vector<int>(n, 0));
|
||||
for (int i = 0; i < m && obstacleGrid[i][0] == 0; i++) dp[i][0] = 1;
|
||||
for (int j = 0; j < n && obstacleGrid[0][j] == 0; j++) dp[0][j] = 1;
|
||||
@ -111,7 +111,7 @@ for (int j = 0; j < n && obstacleGrid[0][j] == 0; j++) dp[0][j] = 1;
|
||||
|
||||
代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
for (int i = 1; i < m; i++) {
|
||||
for (int j = 1; j < n; j++) {
|
||||
if (obstacleGrid[i][j] == 1) continue;
|
||||
@ -135,7 +135,7 @@ for (int i = 1; i < m; i++) {
|
||||
|
||||
动规五部分分析完毕,对应C++代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) {
|
||||
|
@ -109,7 +109,7 @@ dp[i]: 爬到第i层楼梯,有dp[i]种方法
|
||||
|
||||
以上五部分析完之后,C++代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
// 版本一
|
||||
class Solution {
|
||||
public:
|
||||
@ -130,7 +130,7 @@ public:
|
||||
|
||||
当然依然也可以,优化一下空间复杂度,代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
// 版本二
|
||||
class Solution {
|
||||
public:
|
||||
@ -163,7 +163,7 @@ public:
|
||||
|
||||
这里我先给出我的实现代码:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
int climbStairs(int n) {
|
||||
|
@ -123,7 +123,7 @@ if (word1[i - 1] != word2[j - 1])
|
||||
|
||||
递归公式代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
if (word1[i - 1] == word2[j - 1]) {
|
||||
dp[i][j] = dp[i - 1][j - 1];
|
||||
}
|
||||
@ -151,7 +151,7 @@ dp[i][0] :以下标i-1为结尾的字符串word1,和空字符串word2,最
|
||||
|
||||
所以C++代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
for (int i = 0; i <= word1.size(); i++) dp[i][0] = i;
|
||||
for (int j = 0; j <= word2.size(); j++) dp[0][j] = j;
|
||||
```
|
||||
@ -175,7 +175,7 @@ for (int j = 0; j <= word2.size(); j++) dp[0][j] = j;
|
||||
|
||||
代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
for (int i = 1; i <= word1.size(); i++) {
|
||||
for (int j = 1; j <= word2.size(); j++) {
|
||||
if (word1[i - 1] == word2[j - 1]) {
|
||||
@ -198,7 +198,7 @@ for (int i = 1; i <= word1.size(); i++) {
|
||||
|
||||
以上动规五部分析完毕,C++代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
int minDistance(string word1, string word2) {
|
||||
|
@ -173,7 +173,7 @@ for循环每次从startIndex开始遍历,然后用path保存取到的节点i
|
||||
|
||||
代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
for (int i = startIndex; i <= n; i++) { // 控制树的横向遍历
|
||||
path.push_back(i); // 处理节点
|
||||
backtracking(n, k, i + 1); // 递归:控制树的纵向遍历,注意下一层搜索要从i+1开始
|
||||
@ -188,7 +188,7 @@ backtracking的下面部分就是回溯的操作了,撤销本次处理的结
|
||||
关键地方都讲完了,组合问题C++完整代码如下:
|
||||
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
private:
|
||||
vector<vector<int>> result; // 存放符合条件结果的集合
|
||||
|
@ -120,7 +120,7 @@ void backtracking(参数) {
|
||||
|
||||
可以写出如下回溯算法C++代码:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
private:
|
||||
vector<vector<int>> result;
|
||||
|
@ -23,7 +23,7 @@
|
||||
|
||||
## 双指针解法
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
int largestRectangleArea(vector<int>& heights) {
|
||||
@ -56,7 +56,7 @@ public:
|
||||
|
||||
所以需要循环查找,也就是下面在寻找的过程中使用了while,详细请看下面注释,整理思路在题解:[42. 接雨水](https://mp.weixin.qq.com/s/QogENxhotboct9wn7GgYUw)中已经介绍了。
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
int largestRectangleArea(vector<int>& heights) {
|
||||
@ -125,7 +125,7 @@ public:
|
||||
|
||||
C++代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
// 版本一
|
||||
class Solution {
|
||||
public:
|
||||
@ -164,7 +164,7 @@ public:
|
||||
|
||||
代码精简之后:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
// 版本二
|
||||
class Solution {
|
||||
public:
|
||||
|
@ -124,7 +124,7 @@ public:
|
||||
|
||||
代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
private:
|
||||
vector<vector<int>> result;
|
||||
|
@ -183,7 +183,7 @@ void backtracking(参数) {
|
||||
|
||||
可以写出如下回溯算法C++代码:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
private:
|
||||
vector<string> result;// 记录结果
|
||||
|
@ -103,7 +103,7 @@ j相当于是头结点的元素,从1遍历到i为止。
|
||||
|
||||
代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
for (int i = 1; i <= n; i++) {
|
||||
for (int j = 1; j <= i; j++) {
|
||||
dp[i] += dp[j - 1] * dp[i - j];
|
||||
@ -123,7 +123,7 @@ n为5时候的dp数组状态如图:
|
||||
|
||||
综上分析完毕,C++代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
int numTrees(int n) {
|
||||
|
@ -32,7 +32,7 @@
|
||||
|
||||
可以递归中序遍历将二叉搜索树转变成一个数组,代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
vector<int> vec;
|
||||
void traversal(TreeNode* root) {
|
||||
if (root == NULL) return;
|
||||
@ -44,7 +44,7 @@ void traversal(TreeNode* root) {
|
||||
|
||||
然后只要比较一下,这个数组是否是有序的,**注意二叉搜索树中不能有重复元素**。
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
traversal(root);
|
||||
for (int i = 1; i < vec.size(); i++) {
|
||||
// 注意要小于等于,搜索树里不能有相同元素
|
||||
@ -55,7 +55,7 @@ return true;
|
||||
|
||||
整体代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
private:
|
||||
vector<int> vec;
|
||||
@ -163,7 +163,7 @@ return left && right;
|
||||
|
||||
整体代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
long long maxVal = LONG_MIN; // 因为后台测试数据中有int最小值
|
||||
@ -189,7 +189,7 @@ public:
|
||||
|
||||
代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
TreeNode* pre = NULL; // 用来记录前一个节点
|
||||
@ -214,7 +214,7 @@ public:
|
||||
|
||||
迭代法中序遍历稍加改动就可以了,代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
bool isValidBST(TreeNode* root) {
|
||||
|
@ -61,7 +61,7 @@ bool compare(TreeNode* tree1, TreeNode* tree2)
|
||||
此时tree1、tree2节点不为空,且数值也不相同的情况我们也处理了。
|
||||
|
||||
代码如下:
|
||||
```C++
|
||||
```CPP
|
||||
if (tree1 == NULL && tree2 != NULL) return false;
|
||||
else if (tree1 != NULL && tree2 == NULL) return false;
|
||||
else if (tree1 == NULL && tree2 == NULL) return true;
|
||||
@ -77,7 +77,7 @@ else if (tree1->val != tree2->val) return false; // 注意这里我没有
|
||||
|
||||
代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
bool left = compare(tree1->left, tree2->left); // 左子树:左、 右子树:左
|
||||
bool right = compare(tree1->right, tree2->right); // 左子树:右、 右子树:右
|
||||
bool isSame = left && right; // 左子树:中、 右子树:中(逻辑处理)
|
||||
@ -85,7 +85,7 @@ return isSame;
|
||||
```
|
||||
最后递归的C++整体代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
bool compare(TreeNode* tree1, TreeNode* tree2) {
|
||||
@ -119,7 +119,7 @@ public:
|
||||
|
||||
## 递归
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
bool compare(TreeNode* left, TreeNode* right) {
|
||||
@ -138,7 +138,7 @@ public:
|
||||
|
||||
## 迭代法
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
|
||||
|
@ -73,7 +73,7 @@ bool compare(TreeNode* left, TreeNode* right)
|
||||
此时左右节点不为空,且数值也不相同的情况我们也处理了。
|
||||
|
||||
代码如下:
|
||||
```C++
|
||||
```CPP
|
||||
if (left == NULL && right != NULL) return false;
|
||||
else if (left != NULL && right == NULL) return false;
|
||||
else if (left == NULL && right == NULL) return true;
|
||||
@ -93,7 +93,7 @@ else if (left->val != right->val) return false; // 注意这里我没有
|
||||
|
||||
代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
bool outside = compare(left->left, right->right); // 左子树:左、 右子树:右
|
||||
bool inside = compare(left->right, right->left); // 左子树:右、 右子树:左
|
||||
bool isSame = outside && inside; // 左子树:中、 右子树:中(逻辑处理)
|
||||
@ -104,7 +104,7 @@ return isSame;
|
||||
|
||||
最后递归的C++整体代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
bool compare(TreeNode* left, TreeNode* right) {
|
||||
@ -137,7 +137,7 @@ public:
|
||||
**盲目的照着抄,结果就是:发现这是一道“简单题”,稀里糊涂的就过了,但是真正的每一步判断逻辑未必想到清楚。**
|
||||
|
||||
当然我可以把如上代码整理如下:
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
bool compare(TreeNode* left, TreeNode* right) {
|
||||
@ -177,7 +177,7 @@ public:
|
||||
|
||||
代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
bool isSymmetric(TreeNode* root) {
|
||||
@ -212,7 +212,7 @@ public:
|
||||
|
||||
只要把队列原封不动的改成栈就可以了,我下面也给出了代码。
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
bool isSymmetric(TreeNode* root) {
|
||||
|
@ -60,7 +60,7 @@
|
||||
|
||||
C++代码:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
vector<vector<int>> levelOrder(TreeNode* root) {
|
||||
@ -245,7 +245,7 @@ var levelOrder = function(root) {
|
||||
|
||||
C++代码:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
vector<vector<int>> levelOrderBottom(TreeNode* root) {
|
||||
@ -422,7 +422,7 @@ var levelOrderBottom = function(root) {
|
||||
|
||||
C++代码:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
vector<int> rightSideView(TreeNode* root) {
|
||||
@ -599,7 +599,7 @@ var rightSideView = function(root) {
|
||||
|
||||
C++代码:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
vector<double> averageOfLevels(TreeNode* root) {
|
||||
@ -794,7 +794,7 @@ var averageOfLevels = function(root) {
|
||||
|
||||
C++代码:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
vector<vector<int>> levelOrder(Node* root) {
|
||||
@ -1003,7 +1003,7 @@ var levelOrder = function(root) {
|
||||
|
||||
C++代码:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
vector<int> largestValues(TreeNode* root) {
|
||||
@ -1147,7 +1147,7 @@ struct Node {
|
||||
|
||||
C++代码:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
Node* connect(Node* root) {
|
||||
@ -1269,7 +1269,7 @@ func connect(root *Node) *Node {
|
||||
|
||||
C++代码:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
Node* connect(Node* root) {
|
||||
@ -1451,7 +1451,7 @@ func connect(root *Node) *Node {
|
||||
|
||||
C++代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
int maxDepth(TreeNode* root) {
|
||||
@ -1491,7 +1491,7 @@ JavaScript:
|
||||
|
||||
代码如下:(详细注释)
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
int minDepth(TreeNode* root) {
|
||||
|
@ -59,7 +59,7 @@
|
||||
|
||||
不难写出如下代码:(先把框架写出来)
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
TreeNode* traversal (vector<int>& inorder, vector<int>& postorder) {
|
||||
|
||||
// 第一步
|
||||
@ -155,7 +155,7 @@ root->right = traversal(rightInorder, rightPostorder);
|
||||
|
||||
### C++完整代码
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
private:
|
||||
TreeNode* traversal (vector<int>& inorder, vector<int>& postorder) {
|
||||
@ -209,7 +209,7 @@ public:
|
||||
加了日志的代码如下:(加了日志的代码不要在leetcode上提交,容易超时)
|
||||
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
private:
|
||||
TreeNode* traversal (vector<int>& inorder, vector<int>& postorder) {
|
||||
@ -277,7 +277,7 @@ public:
|
||||
下面给出用下表索引写出的代码版本:(思路是一样的,只不过不用重复定义vector了,每次用下表索引来分割)
|
||||
|
||||
### C++优化版本
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
private:
|
||||
// 中序区间:[inorderBegin, inorderEnd),后序区间[postorderBegin, postorderEnd)
|
||||
@ -325,7 +325,7 @@ public:
|
||||
|
||||
那么这个版本写出来依然要打日志进行调试,打日志的版本如下:(**该版本不要在leetcode上提交,容易超时**)
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
private:
|
||||
TreeNode* traversal (vector<int>& inorder, int inorderBegin, int inorderEnd, vector<int>& postorder, int postorderBegin, int postorderEnd) {
|
||||
@ -419,7 +419,7 @@ public:
|
||||
|
||||
带日志的版本C++代码如下: (**带日志的版本仅用于调试,不要在leetcode上提交,会超时**)
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
private:
|
||||
TreeNode* traversal (vector<int>& inorder, int inorderBegin, int inorderEnd, vector<int>& preorder, int preorderBegin, int preorderEnd) {
|
||||
@ -493,7 +493,7 @@ public:
|
||||
|
||||
105.从前序与中序遍历序列构造二叉树,最后版本,C++代码:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
private:
|
||||
TreeNode* traversal (vector<int>& inorder, int inorderBegin, int inorderEnd, vector<int>& preorder, int preorderBegin, int preorderEnd) {
|
||||
|
@ -122,7 +122,7 @@ return root;
|
||||
|
||||
* 递归整体代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
private:
|
||||
TreeNode* traversal(vector<int>& nums, int left, int right) {
|
||||
@ -150,7 +150,7 @@ public:
|
||||
|
||||
模拟的就是不断分割的过程,C++代码如下:(我已经详细注释)
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
TreeNode* sortedArrayToBST(vector<int>& nums) {
|
||||
|
@ -57,7 +57,7 @@
|
||||
|
||||
在[104.二叉树的最大深度](https://mp.weixin.qq.com/s/jRaRcRerhEHepQbt-aKstw)中,如果真正求取二叉树的最大深度,代码应该写成如下:(前序遍历)
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
int result;
|
||||
@ -91,7 +91,7 @@ public:
|
||||
|
||||
注意以上代码是为了把细节体现出来,简化一下代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
int result;
|
||||
@ -161,7 +161,7 @@ if (node == NULL) {
|
||||
|
||||
代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
int leftDepth = depth(node->left); // 左
|
||||
if (leftDepth == -1) return -1;
|
||||
int rightDepth = depth(node->right); // 右
|
||||
@ -179,7 +179,7 @@ return result;
|
||||
|
||||
代码精简之后如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
int leftDepth = getDepth(node->left);
|
||||
if (leftDepth == -1) return -1;
|
||||
int rightDepth = getDepth(node->right);
|
||||
@ -191,7 +191,7 @@ return abs(leftDepth - rightDepth) > 1 ? -1 : 1 + max(leftDepth, rightDepth);
|
||||
|
||||
getDepth整体代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
int getDepth(TreeNode* node) {
|
||||
if (node == NULL) {
|
||||
return 0;
|
||||
@ -206,7 +206,7 @@ int getDepth(TreeNode* node) {
|
||||
|
||||
最后本题整体递归代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
// 返回以该节点为根节点的二叉树的高度,如果不是二叉搜索树了则返回-1
|
||||
@ -236,7 +236,7 @@ public:
|
||||
|
||||
代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
// cur节点的最大深度,就是cur的高度
|
||||
int getDepth(TreeNode* cur) {
|
||||
stack<TreeNode*> st;
|
||||
@ -267,7 +267,7 @@ int getDepth(TreeNode* cur) {
|
||||
|
||||
然后再用栈来模拟前序遍历,遍历每一个节点的时候,再去判断左右孩子的高度是否符合,代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
bool isBalanced(TreeNode* root) {
|
||||
stack<TreeNode*> st;
|
||||
if (root == NULL) return true;
|
||||
@ -287,7 +287,7 @@ bool isBalanced(TreeNode* root) {
|
||||
|
||||
整体代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
private:
|
||||
int getDepth(TreeNode* cur) {
|
||||
|
@ -87,7 +87,7 @@ return result;
|
||||
|
||||
代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
int leftDepth = getDepth(node->left); // 左
|
||||
int rightDepth = getDepth(node->right); // 右
|
||||
// 中
|
||||
@ -106,7 +106,7 @@ return result;
|
||||
遍历的顺序为后序(左右中),可以看出:**求二叉树的最小深度和求二叉树的最大深度的差别主要在于处理左右孩子不为空的逻辑。**
|
||||
|
||||
整体递归代码如下:
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
int getDepth(TreeNode* node) {
|
||||
@ -134,7 +134,7 @@ public:
|
||||
|
||||
精简之后代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
int minDepth(TreeNode* root) {
|
||||
@ -162,7 +162,7 @@ public:
|
||||
|
||||
代码如下:(详细注释)
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
|
||||
|
@ -91,7 +91,7 @@ if (!cur->left && !cur->right) return false; // 遇到叶子节点而没有找
|
||||
|
||||
代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
if (cur->left) { // 左 (空节点不遍历)
|
||||
// 遇到叶子节点返回true,则直接返回true
|
||||
if (traversal(cur->left, count - cur->left->val)) return true; // 注意这里有回溯的逻辑
|
||||
@ -109,7 +109,7 @@ return false;
|
||||
|
||||
为了把回溯的过程体现出来,可以改为如下代码:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
if (cur->left) { // 左
|
||||
count -= cur->left->val; // 递归,处理节点;
|
||||
if (traversal(cur->left, count)) return true;
|
||||
@ -126,7 +126,7 @@ return false;
|
||||
|
||||
整体代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
private:
|
||||
bool traversal(TreeNode* cur, int count) {
|
||||
@ -156,7 +156,7 @@ public:
|
||||
|
||||
以上代码精简之后如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
bool hasPathSum(TreeNode* root, int sum) {
|
||||
@ -186,7 +186,7 @@ C++就我们用pair结构来存放这个栈里的元素。
|
||||
|
||||
如下代码是使用栈模拟的前序遍历,如下:(详细注释)
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
|
||||
public:
|
||||
@ -243,7 +243,7 @@ public:
|
||||
|
||||
为了尽可能的把细节体现出来,我写出如下代码(**这份代码并不简洁,但是逻辑非常清晰**)
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
private:
|
||||
vector<vector<int>> result;
|
||||
|
@ -82,7 +82,7 @@ dp[0][0]应该是1,空字符串s,可以删除0个元素,变成空字符串
|
||||
|
||||
初始化分析完毕,代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
vector<vector<long long>> dp(s.size() + 1, vector<long long>(t.size() + 1));
|
||||
for (int i = 0; i <= s.size(); i++) dp[i][0] = 1;
|
||||
for (int j = 1; j <= t.size(); j++) dp[0][j] = 0; // 其实这行代码可以和dp数组初始化的时候放在一起,但我为了凸显初始化的逻辑,所以还是加上了。
|
||||
@ -97,7 +97,7 @@ for (int j = 1; j <= t.size(); j++) dp[0][j] = 0; // 其实这行代码可以和
|
||||
|
||||
代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
for (int i = 1; i <= s.size(); i++) {
|
||||
for (int j = 1; j <= t.size(); j++) {
|
||||
if (s[i - 1] == t[j - 1]) {
|
||||
@ -120,7 +120,7 @@ for (int i = 1; i <= s.size(); i++) {
|
||||
|
||||
动规五部曲分析完毕,代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
int numDistinct(string s, string t) {
|
||||
|
@ -52,7 +52,7 @@ struct Node {
|
||||
|
||||
图中cur节点为元素4,那么搭线的逻辑代码:(**注意注释中操作1和操作2和图中的对应关系**)
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
if (cur->left) cur->left->next = cur->right; // 操作1
|
||||
if (cur->right) {
|
||||
if (cur->next) cur->right->next = cur->next->left; // 操作2
|
||||
@ -63,7 +63,7 @@ if (cur->right) {
|
||||
理解到这里,使用前序遍历,那么不难写出如下代码:
|
||||
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
private:
|
||||
void traversal(Node* cur) {
|
||||
@ -93,7 +93,7 @@ public:
|
||||
|
||||
代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
Node* connect(Node* root) {
|
||||
|
@ -33,7 +33,7 @@
|
||||
|
||||
这道题目最直观的想法,就是暴力,找最优间距了。
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
int maxProfit(vector<int>& prices) {
|
||||
@ -59,7 +59,7 @@ public:
|
||||
|
||||
C++代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
int maxProfit(vector<int>& prices) {
|
||||
@ -139,7 +139,7 @@ dp[5][1]就是最终结果。
|
||||
|
||||
以上分析完毕,C++代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
// 版本一
|
||||
class Solution {
|
||||
public:
|
||||
@ -169,7 +169,7 @@ dp[i][1] = max(dp[i - 1][1], prices[i] + dp[i - 1][0]);
|
||||
|
||||
那么我们只需要记录 当前天的dp状态和前一天的dp状态就可以了,可以使用滚动数组来节省空间,代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
// 版本二
|
||||
class Solution {
|
||||
public:
|
||||
|
@ -80,7 +80,7 @@
|
||||
|
||||
对应C++代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
int maxProfit(vector<int>& prices) {
|
||||
@ -99,7 +99,7 @@ public:
|
||||
|
||||
动态规划将在下一个系列详细讲解,本题解先给出我的C++代码(带详细注释),感兴趣的同学可以自己先学习一下。
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
int maxProfit(vector<int>& prices) {
|
||||
|
@ -74,7 +74,7 @@
|
||||
|
||||
代码如下:(注意代码中的注释,标记了和121.买卖股票的最佳时机唯一不同的地方)
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
int maxProfit(vector<int>& prices) {
|
||||
@ -106,7 +106,7 @@ dp[i][0] = max(dp[i - 1][0], dp[i - 1][1] - prices[i]);
|
||||
|
||||
这里我依然给出滚动数组的版本,C++代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
// 版本二
|
||||
class Solution {
|
||||
public:
|
||||
|
@ -127,7 +127,7 @@ dp[i][4] = max(dp[i - 1][4], dp[i - 1][3] + prices[i]);
|
||||
|
||||
以上五部都分析完了,不难写出如下代码:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
// 版本一
|
||||
class Solution {
|
||||
public:
|
||||
@ -153,7 +153,7 @@ public:
|
||||
|
||||
当然,大家可以看到力扣官方题解里的一种优化空间写法,我这里给出对应的C++版本:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
// 版本二
|
||||
class Solution {
|
||||
public:
|
||||
|
@ -52,7 +52,7 @@ if (!cur->left && !cur->right) { // 遇到了叶子节点
|
||||
|
||||
这里vectorToInt函数就是把数组转成int,代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
int vectorToInt(const vector<int>& vec) {
|
||||
int sum = 0;
|
||||
for (int i = 0; i < vec.size(); i++) {
|
||||
@ -78,7 +78,7 @@ int vectorToInt(const vector<int>& vec) {
|
||||
|
||||
代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
// 中
|
||||
if (cur->left) { // 左 (空节点不遍历)
|
||||
path.push_back(cur->left->val);
|
||||
@ -94,7 +94,7 @@ if (cur->right) { // 右 (空节点不遍历)
|
||||
|
||||
这里要注意回溯和递归要永远在一起,一个递归,对应一个回溯,是一对一的关系,有的同学写成如下代码:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
if (cur->left) { // 左 (空节点不遍历)
|
||||
path.push_back(cur->left->val);
|
||||
traversal(cur->left); // 递归
|
||||
@ -111,7 +111,7 @@ path.pop_back(); // 回溯
|
||||
|
||||
关键逻辑分析完了,整体C++代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
private:
|
||||
int result;
|
||||
|
@ -70,7 +70,7 @@
|
||||
|
||||
代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
vector<vector<string>> result;
|
||||
vector<string> path; // 放已经回文的子串
|
||||
void backtracking (const string& s, int startIndex) {
|
||||
@ -88,7 +88,7 @@ void backtracking (const string& s, int startIndex) {
|
||||
|
||||
所以终止条件代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
void backtracking (const string& s, int startIndex) {
|
||||
// 如果起始位置已经大于s的大小,说明已经找到了一组分割方案了
|
||||
if (startIndex >= s.size()) {
|
||||
@ -108,7 +108,7 @@ void backtracking (const string& s, int startIndex) {
|
||||
|
||||
代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
for (int i = startIndex; i < s.size(); i++) {
|
||||
if (isPalindrome(s, startIndex, i)) { // 是回文子串
|
||||
// 获取[startIndex,i]在s中的子串
|
||||
@ -132,7 +132,7 @@ for (int i = startIndex; i < s.size(); i++) {
|
||||
|
||||
那么判断回文的C++代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
bool isPalindrome(const string& s, int start, int end) {
|
||||
for (int i = start, j = end; i < j; i++, j--) {
|
||||
if (s[i] != s[j]) {
|
||||
@ -151,7 +151,7 @@ for (int i = startIndex; i < s.size(); i++) {
|
||||
|
||||
根据Carl给出的回溯算法模板:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
void backtracking(参数) {
|
||||
if (终止条件) {
|
||||
存放结果;
|
||||
@ -169,7 +169,7 @@ void backtracking(参数) {
|
||||
|
||||
不难写出如下代码:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
private:
|
||||
vector<vector<string>> result;
|
||||
|
@ -101,7 +101,7 @@ dp[i]: 范围是[0, i]的回文子串,最少分割次数是dp[i]。
|
||||
|
||||
代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
vector<int> dp(s.size(), INT_MAX);
|
||||
dp[0] = 0;
|
||||
```
|
||||
@ -109,7 +109,7 @@ dp[0] = 0;
|
||||
其实也可以这样初始化,更具dp[i]的定义,dp[i]的最大值其实就是i,也就是把每个字符分割出来。
|
||||
|
||||
所以初始化代码也可以为:
|
||||
```C++
|
||||
```CPP
|
||||
vector<int> dp(s.size());
|
||||
for (int i = 0; i < s.size(); i++) dp[i] = i;
|
||||
```
|
||||
@ -122,7 +122,7 @@ j是在[0,i]之间,所以遍历i的for循环一定在外层,这里遍历j
|
||||
|
||||
代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
for (int i = 1; i < s.size(); i++) {
|
||||
if (isPalindromic[0][i]) { // 判断是不是回文子串
|
||||
dp[i] = 0;
|
||||
@ -149,7 +149,7 @@ for (int i = 1; i < s.size(); i++) {
|
||||
|
||||
代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
vector<vector<bool>> isPalindromic(s.size(), vector<bool>(s.size(), false));
|
||||
for (int i = s.size() - 1; i >= 0; i--) {
|
||||
for (int j = i; j < s.size(); j++) {
|
||||
@ -168,7 +168,7 @@ for (int i = s.size() - 1; i >= 0; i--) {
|
||||
|
||||
以上分析完毕,代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
int minCut(string s) {
|
||||
|
@ -65,7 +65,7 @@ cost = [3,4,3]
|
||||
|
||||
C++代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {
|
||||
@ -99,7 +99,7 @@ C++暴力解法在leetcode上提交也可以过。
|
||||
|
||||
C++代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {
|
||||
@ -160,7 +160,7 @@ i从0开始累加rest[i],和记为curSum,一旦curSum小于零,说明[0, i
|
||||
|
||||
C++代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {
|
||||
|
@ -47,7 +47,7 @@
|
||||
|
||||
代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
// 从前向后
|
||||
for (int i = 1; i < ratings.size(); i++) {
|
||||
if (ratings[i] > ratings[i - 1]) candyVec[i] = candyVec[i - 1] + 1;
|
||||
@ -80,7 +80,7 @@ for (int i = 1; i < ratings.size(); i++) {
|
||||
|
||||
所以该过程代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
// 从后向前
|
||||
for (int i = ratings.size() - 2; i >= 0; i--) {
|
||||
if (ratings[i] > ratings[i + 1] ) {
|
||||
@ -90,7 +90,7 @@ for (int i = ratings.size() - 2; i >= 0; i--) {
|
||||
```
|
||||
|
||||
整体代码如下:
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
int candy(vector<int>& ratings) {
|
||||
|
@ -45,7 +45,7 @@
|
||||
|
||||
那么这里我也给出回溯法C++代码:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
private:
|
||||
bool backtracking (const string& s, const unordered_set<string>& wordSet, int startIndex) {
|
||||
@ -86,7 +86,7 @@ public:
|
||||
|
||||
C++代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
private:
|
||||
bool backtracking (const string& s,
|
||||
@ -190,7 +190,7 @@ dp[s.size()]就是最终结果。
|
||||
|
||||
动规五部曲分析完毕,C++代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
bool wordBreak(string s, vector<string>& wordDict) {
|
||||
|
@ -45,7 +45,7 @@ fast和slow各自再走一步, fast和slow就相遇了
|
||||
|
||||
C++代码如下
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
bool hasCycle(ListNode *head) {
|
||||
|
@ -109,7 +109,7 @@ fast指针走过的节点数:` x + y + n (y + z)`,n为fast指针在环内走
|
||||
|
||||
代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
/**
|
||||
* Definition for singly-linked list.
|
||||
* struct ListNode {
|
||||
|
@ -24,7 +24,7 @@
|
||||
|
||||
代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
void reorderList(ListNode* head) {
|
||||
@ -63,7 +63,7 @@ public:
|
||||
|
||||
把链表放进双向队列,然后通过双向队列一前一后弹出数据,来构造新的链表。这种方法比操作数组容易一些,不用双指针模拟一前一后了
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
void reorderList(ListNode* head) {
|
||||
@ -108,7 +108,7 @@ public:
|
||||
|
||||
代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
private:
|
||||
// 反转链表
|
||||
|
@ -80,7 +80,7 @@ https://leetcode-cn.com/problems/evaluate-reverse-polish-notation/
|
||||
C++代码如下:
|
||||
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
int evalRPN(vector<string>& tokens) {
|
||||
|
@ -61,7 +61,7 @@ https://leetcode-cn.com/problems/reverse-words-in-a-string/
|
||||
|
||||
思路很明确了,我们说一说代码的实现细节,就拿移除多余空格来说,一些同学会上来写如下代码:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
void removeExtraSpaces(string& s) {
|
||||
for (int i = s.size() - 1; i > 0; i--) {
|
||||
if (s[i] == s[i - 1] && s[i] == ' ') {
|
||||
@ -93,7 +93,7 @@ erase操作上面还套了一个for循环,那么以上代码移除冗余空格
|
||||
|
||||
那么使用双指针来移除冗余空格代码如下: fastIndex走的快,slowIndex走的慢,最后slowIndex就标记着移除多余空格后新字符串的长度。
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
void removeExtraSpaces(string& s) {
|
||||
int slowIndex = 0, fastIndex = 0; // 定义快指针,慢指针
|
||||
// 去掉字符串前面的空格
|
||||
@ -141,7 +141,7 @@ void reverse(string& s, int start, int end) {
|
||||
本题C++整体代码
|
||||
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
// 版本一
|
||||
class Solution {
|
||||
public:
|
||||
|
@ -84,7 +84,7 @@ vector<vector<int>> dp(prices.size(), vector<int>(2 * k + 1, 0));
|
||||
|
||||
同理可以类比剩下的状态,代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
for (int j = 0; j < 2 * k - 1; j += 2) {
|
||||
dp[i][j + 1] = max(dp[i - 1][j + 1], dp[i - 1][j] - prices[i]);
|
||||
dp[i][j + 2] = max(dp[i - 1][j + 2], dp[i - 1][j + 1] + prices[i]);
|
||||
@ -117,7 +117,7 @@ for (int j = 0; j < 2 * k - 1; j += 2) {
|
||||
|
||||
代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
for (int j = 1; j < 2 * k; j += 2) {
|
||||
dp[0][j] = -prices[0];
|
||||
}
|
||||
@ -139,7 +139,7 @@ for (int j = 1; j < 2 * k; j += 2) {
|
||||
|
||||
以上分析完毕,C++代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
int maxProfit(int k, vector<int>& prices) {
|
||||
|
@ -69,7 +69,7 @@
|
||||
|
||||
C++代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
void rotate(vector<int>& nums, int k) {
|
||||
|
@ -59,7 +59,7 @@
|
||||
|
||||
代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
vector<int> dp(nums.size());
|
||||
dp[0] = nums[0];
|
||||
dp[1] = max(nums[0], nums[1]);
|
||||
@ -70,7 +70,7 @@ dp[1] = max(nums[0], nums[1]);
|
||||
dp[i] 是根据dp[i - 2] 和 dp[i - 1] 推导出来的,那么一定是从前到后遍历!
|
||||
|
||||
代码如下:
|
||||
```C++
|
||||
```CPP
|
||||
for (int i = 2; i < nums.size(); i++) {
|
||||
dp[i] = max(dp[i - 2] + nums[i], dp[i - 1]);
|
||||
}
|
||||
@ -86,7 +86,7 @@ for (int i = 2; i < nums.size(); i++) {
|
||||
|
||||
以上分析完毕,C++代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
int rob(vector<int>& nums) {
|
||||
|
@ -46,7 +46,7 @@ https://leetcode-cn.com/problems/happy-number/
|
||||
|
||||
C++代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
// 取数值各个位上的单数之和
|
||||
|
@ -89,7 +89,7 @@ https://leetcode-cn.com/problems/remove-linked-list-elements/
|
||||
|
||||
**直接使用原来的链表来进行移除节点操作:**
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
ListNode* removeElements(ListNode* head, int val) {
|
||||
@ -118,7 +118,7 @@ public:
|
||||
|
||||
**设置一个虚拟头结点在进行移除节点操作:**
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
ListNode* removeElements(ListNode* head, int val) {
|
||||
|
@ -39,7 +39,7 @@
|
||||
|
||||
C++代码 如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
bool isIsomorphic(string s, string t) {
|
||||
|
@ -48,7 +48,7 @@ https://leetcode-cn.com/problems/reverse-linked-list/
|
||||
# C++代码
|
||||
|
||||
## 双指针法
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
ListNode* reverseList(ListNode* head) {
|
||||
@ -74,7 +74,7 @@ public:
|
||||
关键是初始化的地方,可能有的同学会不理解, 可以看到双指针法中初始化 cur = head,pre = NULL,在递归法中可以从如下代码看出初始化的逻辑也是一样的,只不过写法变了。
|
||||
|
||||
具体可以看代码(已经详细注释),**双指针法写出来之后,理解如下递归写法就不难了,代码逻辑都是一样的。**
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
ListNode* reverse(ListNode* pre,ListNode* cur){
|
||||
|
@ -26,7 +26,7 @@
|
||||
|
||||
代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
int minSubArrayLen(int s, vector<int>& nums) {
|
||||
@ -86,7 +86,7 @@ public:
|
||||
|
||||
C++代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
int minSubArrayLen(int s, vector<int>& nums) {
|
||||
|
@ -59,7 +59,7 @@
|
||||
|
||||
代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
// 注意注释中的情况二情况三,以及把198.打家劫舍的代码抽离出来了
|
||||
class Solution {
|
||||
public:
|
||||
|
@ -94,7 +94,7 @@ void backtracking(int targetSum, int k, int sum, int startIndex)
|
||||
|
||||
所以 终止代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
if (path.size() == k) {
|
||||
if (sum == targetSum) result.push_back(path);
|
||||
return; // 如果path.size() == k 但sum != targetSum 直接返回
|
||||
@ -112,7 +112,7 @@ if (path.size() == k) {
|
||||
|
||||
代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
for (int i = startIndex; i <= 9; i++) {
|
||||
sum += i;
|
||||
path.push_back(i);
|
||||
@ -126,7 +126,7 @@ for (int i = startIndex; i <= 9; i++) {
|
||||
|
||||
参照[关于回溯算法,你该了解这些!](https://mp.weixin.qq.com/s/gjSgJbNbd1eAA5WkA-HeWw)中的模板,不难写出如下C++代码:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
private:
|
||||
vector<vector<int>> result; // 存放结果集
|
||||
|
@ -77,7 +77,7 @@ return treeNum;
|
||||
|
||||
所以整体C++代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
// 版本一
|
||||
class Solution {
|
||||
private:
|
||||
@ -96,7 +96,7 @@ public:
|
||||
```
|
||||
|
||||
代码精简之后C++代码如下:
|
||||
```C++
|
||||
```CPP
|
||||
// 版本二
|
||||
class Solution {
|
||||
public:
|
||||
@ -119,7 +119,7 @@ public:
|
||||
|
||||
那么只要模板少做改动,加一个变量result,统计节点数量就可以了
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
int countNodes(TreeNode* root) {
|
||||
@ -163,7 +163,7 @@ public:
|
||||
|
||||
C++代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
int countNodes(TreeNode* root) {
|
||||
|
@ -65,7 +65,7 @@ queue.empty();
|
||||
详细如代码注释所示:
|
||||
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class MyStack {
|
||||
public:
|
||||
queue<int> que1;
|
||||
@ -118,7 +118,7 @@ public:
|
||||
|
||||
C++优化代码
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class MyStack {
|
||||
public:
|
||||
queue<int> que;
|
||||
|
@ -89,7 +89,7 @@ invertTree(root->right);
|
||||
|
||||
基于这递归三步法,代码基本写完,C++代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
TreeNode* invertTree(TreeNode* root) {
|
||||
@ -111,7 +111,7 @@ public:
|
||||
|
||||
C++代码迭代法(前序遍历)
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
TreeNode* invertTree(TreeNode* root) {
|
||||
@ -136,7 +136,7 @@ public:
|
||||
|
||||
C++代码如下迭代法(前序遍历)
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
TreeNode* invertTree(TreeNode* root) {
|
||||
@ -168,7 +168,7 @@ public:
|
||||
|
||||
也就是层序遍历,层数遍历也是可以翻转这棵树的,因为层序遍历也可以把每个节点的左右孩子都翻转一遍,代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
TreeNode* invertTree(TreeNode* root) {
|
||||
@ -196,7 +196,7 @@ public:
|
||||
|
||||
如果非要使用递归中序的方式写,也可以,如下代码就可以避免节点左右孩子翻转两次的情况:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
TreeNode* invertTree(TreeNode* root) {
|
||||
@ -215,7 +215,7 @@ public:
|
||||
|
||||
代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
TreeNode* invertTree(TreeNode* root) {
|
||||
|
@ -67,7 +67,7 @@ queue.empty();
|
||||
|
||||
C++代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class MyQueue {
|
||||
public:
|
||||
stack<int> stIn;
|
||||
|
@ -30,7 +30,7 @@
|
||||
|
||||
代码也比较简单。如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
bool isPalindrome(ListNode* head) {
|
||||
@ -51,7 +51,7 @@ public:
|
||||
|
||||
上面代码可以在优化,就是先求出链表长度,然后给定vector的初始长度,这样避免vector每次添加节点重新开辟空间
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
bool isPalindrome(ListNode* head) {
|
||||
@ -95,7 +95,7 @@ public:
|
||||
|
||||
代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
bool isPalindrome(ListNode* head) {
|
||||
|
@ -93,7 +93,7 @@ if (cur == NULL) return cur;
|
||||
|
||||
代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
if (cur->val > p->val && cur->val > q->val) {
|
||||
TreeNode* left = traversal(cur->left, p, q);
|
||||
if (left != NULL) {
|
||||
@ -147,7 +147,7 @@ return cur;
|
||||
|
||||
那么整体递归代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
private:
|
||||
TreeNode* traversal(TreeNode* cur, TreeNode* p, TreeNode* q) {
|
||||
@ -177,7 +177,7 @@ public:
|
||||
|
||||
精简后代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
|
||||
@ -198,7 +198,7 @@ public:
|
||||
|
||||
迭代代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
|
||||
|
@ -150,7 +150,7 @@ TreeNode* right = lowestCommonAncestor(root->right, p, q);
|
||||
|
||||
代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
if (left == NULL && right != NULL) return right;
|
||||
else if (left != NULL && right == NULL) return left;
|
||||
else { // (left == NULL && right == NULL)
|
||||
@ -167,7 +167,7 @@ else { // (left == NULL && right == NULL)
|
||||
|
||||
整体代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
|
||||
@ -188,7 +188,7 @@ public:
|
||||
|
||||
稍加精简,代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
|
||||
|
@ -108,7 +108,7 @@ public:
|
||||
|
||||
基于刚刚说过的单调队列pop和push的规则,代码不难实现,如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class MyQueue { //单调队列(从大到小)
|
||||
public:
|
||||
deque<int> que; // 使用deque来实现单调队列
|
||||
@ -140,7 +140,7 @@ public:
|
||||
|
||||
C++代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
private:
|
||||
class MyQueue { //单调队列(从大到小)
|
||||
|
@ -61,7 +61,7 @@ https://leetcode-cn.com/problems/valid-anagram/
|
||||
|
||||
|
||||
C++ 代码如下:
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
bool isAnagram(string s, string t) {
|
||||
|
@ -77,7 +77,7 @@ if (cur->left == NULL && cur->right == NULL) {
|
||||
|
||||
这里我们先使用vector<int>结构的path容器来记录路径,那么终止处理逻辑如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
if (cur->left == NULL && cur->right == NULL) { // 遇到叶子节点
|
||||
string sPath;
|
||||
for (int i = 0; i < path.size() - 1; i++) { // 将path里记录的路径转为string格式
|
||||
@ -113,7 +113,7 @@ if (cur->right) {
|
||||
|
||||
那么回溯要怎么回溯呢,一些同学会这么写,如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
if (cur->left) {
|
||||
traversal(cur->left, path, result);
|
||||
}
|
||||
@ -129,7 +129,7 @@ path.pop_back();
|
||||
|
||||
那么代码应该这么写:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
if (cur->left) {
|
||||
traversal(cur->left, path, result);
|
||||
path.pop_back(); // 回溯
|
||||
@ -142,7 +142,7 @@ if (cur->right) {
|
||||
|
||||
那么本题整体代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
private:
|
||||
|
||||
@ -183,7 +183,7 @@ public:
|
||||
|
||||
那么如上代码可以精简成如下代码:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
private:
|
||||
|
||||
@ -217,20 +217,20 @@ public:
|
||||
|
||||
为了把这份精简代码的回溯过程展现出来,大家可以试一试把:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
if (cur->left) traversal(cur->left, path + "->", result); // 左 回溯就隐藏在这里
|
||||
```
|
||||
|
||||
改成如下代码:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
path += "->";
|
||||
traversal(cur->left, path, result); // 左
|
||||
```
|
||||
|
||||
即:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
if (cur->left) {
|
||||
path += "->";
|
||||
traversal(cur->left, path, result); // 左
|
||||
@ -245,7 +245,7 @@ if (cur->right) {
|
||||
|
||||
如果想把回溯加上,就要 在上面代码的基础上,加上回溯,就可以AC了。
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
if (cur->left) {
|
||||
path += "->";
|
||||
traversal(cur->left, path, result); // 左
|
||||
@ -276,7 +276,7 @@ if (cur->right) {
|
||||
|
||||
C++代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
vector<string> binaryTreePaths(TreeNode* root) {
|
||||
|
@ -76,7 +76,7 @@ dp[0]表示 和为0的完全平方数的最小数量,那么dp[0]一定是0。
|
||||
|
||||
我这里先给出外层遍历背包,里层遍历物品的代码:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
vector<int> dp(n + 1, INT_MAX);
|
||||
dp[0] = 0;
|
||||
for (int i = 0; i <= n; i++) { // 遍历背包
|
||||
@ -106,7 +106,7 @@ dp[5] = min(dp[4] + 1, dp[1] + 1) = 2
|
||||
|
||||
以上动规五部曲分析完毕C++代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
// 版本一
|
||||
class Solution {
|
||||
public:
|
||||
@ -125,7 +125,7 @@ public:
|
||||
|
||||
同样我在给出先遍历物品,在遍历背包的代码,一样的可以AC的。
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
// 版本二
|
||||
class Solution {
|
||||
public:
|
||||
|
@ -42,7 +42,7 @@
|
||||
|
||||
C++代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
void moveZeroes(vector<int>& nums) {
|
||||
|
@ -60,7 +60,7 @@ dp[i] 是有0到i-1各个位置的最长升序子序列 推导而来,那么遍
|
||||
|
||||
j其实就是0到i-1,遍历i的循环里外层,遍历j则在内层,代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
for (int i = 1; i < nums.size(); i++) {
|
||||
for (int j = 0; j < i; j++) {
|
||||
if (nums[i] > nums[j]) dp[i] = max(dp[i], dp[j] + 1);
|
||||
@ -80,7 +80,7 @@ for (int i = 1; i < nums.size(); i++) {
|
||||
|
||||
以上五部分析完毕,C++代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
int lengthOfLIS(vector<int>& nums) {
|
||||
|
@ -95,7 +95,7 @@ p[i][3] = dp[i - 1][2];
|
||||
|
||||
综上分析,递推代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
dp[i][0] = max(dp[i - 1][0], max(dp[i - 1][3], dp[i - 1][1]) - prices[i];
|
||||
dp[i][1] = max(dp[i - 1][1], dp[i - 1][3]);
|
||||
dp[i][2] = dp[i - 1][0] + prices[i];
|
||||
@ -129,7 +129,7 @@ dp[i][3] = dp[i - 1][2];
|
||||
|
||||
代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
int maxProfit(vector<int>& prices) {
|
||||
|
@ -112,7 +112,7 @@ dp[amount]为最终结果。
|
||||
## C++代码
|
||||
以上分析完毕,C++ 代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
// 版本一
|
||||
class Solution {
|
||||
public:
|
||||
@ -134,7 +134,7 @@ public:
|
||||
|
||||
对于遍历方式遍历背包放在外循环,遍历物品放在内循环也是可以的,我就直接给出代码了
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
// 版本二
|
||||
class Solution {
|
||||
public:
|
||||
|
@ -178,7 +178,7 @@ if (result.size() == ticketNum + 1) {
|
||||
|
||||
遍历过程如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
for (pair<const string, int>& target : targets[result[result.size() - 1]]) {
|
||||
if (target.second > 0 ) { // 记录到达机场是否飞过了
|
||||
result.push_back(target.first);
|
||||
@ -194,7 +194,7 @@ for (pair<const string, int>& target : targets[result[result.size() - 1]]) {
|
||||
|
||||
分析完毕,此时完整C++代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
private:
|
||||
// unordered_map<出发机场, map<到达机场, 航班次数>> targets
|
||||
|
@ -35,7 +35,7 @@
|
||||
|
||||
代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
int rob(TreeNode* root) {
|
||||
@ -65,7 +65,7 @@ public:
|
||||
|
||||
代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
unordered_map<TreeNode* , int> umap; // 记录计算过的结果
|
||||
@ -103,7 +103,7 @@ public:
|
||||
|
||||
参数为当前节点,代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
vector<int> robTree(TreeNode* cur) {
|
||||
```
|
||||
|
||||
@ -138,7 +138,7 @@ if (cur == NULL) return vector<int>{0, 0};
|
||||
|
||||
代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
// 下标0:不偷,下标1:偷
|
||||
vector<int> left = robTree(cur->left); // 左
|
||||
vector<int> right = robTree(cur->right); // 右
|
||||
@ -156,7 +156,7 @@ vector<int> right = robTree(cur->right); // 右
|
||||
|
||||
代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
vector<int> left = robTree(cur->left); // 左
|
||||
vector<int> right = robTree(cur->right); // 右
|
||||
|
||||
@ -179,7 +179,7 @@ return {val2, val1};
|
||||
|
||||
递归三部曲与动规五部曲分析完毕,C++代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
int rob(TreeNode* root) {
|
||||
|
@ -105,7 +105,7 @@ for (int i = 3; i <= n ; i++) {
|
||||
|
||||
以上动规五部曲分析完毕,C++代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
int integerBreak(int n) {
|
||||
@ -132,7 +132,7 @@ public:
|
||||
|
||||
给出我的C++代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
int integerBreak(int n) {
|
||||
@ -158,7 +158,7 @@ public:
|
||||
|
||||
其实这道题目的递推公式并不好想,而且初始化的地方也很有讲究,我在写本题的时候一开始写的代码是这样的:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
int integerBreak(int n) {
|
||||
|
@ -74,7 +74,7 @@ https://leetcode-cn.com/problems/reverse-string/
|
||||
|
||||
不难写出如下C++代码:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
void reverseString(vector<char>& s) {
|
||||
for (int i = 0, j = s.size() - 1; i < s.size()/2; i++, j--) {
|
||||
swap(s[i],s[j]);
|
||||
@ -90,7 +90,7 @@ swap可以有两种实现。
|
||||
|
||||
一种就是常见的交换数值:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
int tmp = s[i];
|
||||
s[i] = s[j];
|
||||
s[j] = tmp;
|
||||
@ -99,7 +99,7 @@ s[j] = tmp;
|
||||
|
||||
一种就是通过位运算:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
s[i] ^= s[j];
|
||||
s[j] ^= s[i];
|
||||
s[i] ^= s[j];
|
||||
@ -120,7 +120,7 @@ s[i] ^= s[j];
|
||||
|
||||
C++代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
void reverseString(vector<char>& s) {
|
||||
|
@ -76,7 +76,7 @@ https://leetcode-cn.com/problems/top-k-frequent-elements/
|
||||
我们来看一下C++代码:
|
||||
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
// 时间复杂度:O(nlogk)
|
||||
// 空间复杂度:O(n)
|
||||
class Solution {
|
||||
|
@ -54,7 +54,7 @@ std::set和std::multiset底层实现都是红黑树,std::unordered_set的底
|
||||
|
||||
C++代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
|
||||
|
@ -70,7 +70,7 @@
|
||||
|
||||
C++代码如下(和上图是对应的逻辑):
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
int wiggleMaxLength(vector<int>& nums) {
|
||||
|
@ -107,7 +107,7 @@ dp[i](考虑nums[j])可以由 dp[i - nums[j]](不考虑nums[j]) 推导
|
||||
|
||||
以上分析完毕,C++代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
int combinationSum4(vector<int>& nums, int target) {
|
||||
|
@ -40,7 +40,7 @@ canConstruct("aa", "aab") -> true
|
||||
|
||||
那么第一个思路其实就是暴力枚举了,两层for循环,不断去寻找,代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
// 时间复杂度: O(n^2)
|
||||
// 空间复杂度:O(1)
|
||||
class Solution {
|
||||
@ -79,7 +79,7 @@ public:
|
||||
|
||||
代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
// 时间复杂度: O(n)
|
||||
// 空间复杂度:O(1)
|
||||
class Solution {
|
||||
|
@ -107,7 +107,7 @@ dp[i][j]表示以下标i-1为结尾的字符串s和以下标j-1为结尾的字
|
||||
|
||||
动规五部曲分析完毕,C++代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
bool isSubsequence(string s, string t) {
|
||||
|
@ -65,7 +65,7 @@ if (root == NULL) return 0;
|
||||
|
||||
代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
int leftValue = sumOfLeftLeaves(root->left); // 左
|
||||
int rightValue = sumOfLeftLeaves(root->right); // 右
|
||||
// 中
|
||||
@ -81,7 +81,7 @@ return sum;
|
||||
|
||||
整体递归代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
int sumOfLeftLeaves(TreeNode* root) {
|
||||
@ -102,7 +102,7 @@ public:
|
||||
|
||||
以上代码精简之后如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
int sumOfLeftLeaves(TreeNode* root) {
|
||||
@ -123,7 +123,7 @@ public:
|
||||
|
||||
判断条件都是一样的,代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
|
||||
class Solution {
|
||||
public:
|
||||
|
@ -99,7 +99,7 @@
|
||||
|
||||
C++代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
// 版本一
|
||||
class Solution {
|
||||
public:
|
||||
@ -127,7 +127,7 @@ public:
|
||||
|
||||
改成链表之后,C++代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
// 版本二
|
||||
class Solution {
|
||||
public:
|
||||
|
@ -106,7 +106,7 @@
|
||||
|
||||
代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
// 题目中说:每个数组中的元素不会超过 100,数组的大小不会超过 200
|
||||
// 总和不会大于20000,背包最大只需要其中一半,所以10001大小就可以了
|
||||
vector<int> dp(10001, 0);
|
||||
@ -118,7 +118,7 @@ vector<int> dp(10001, 0);
|
||||
|
||||
代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
// 开始 01背包
|
||||
for(int i = 0; i < nums.size(); i++) {
|
||||
for(int j = target; j >= nums[i]; j--) { // 每一个元素一定是不可重复放入,所以从大到小遍历
|
||||
@ -141,7 +141,7 @@ dp[i]的数值一定是小于等于i的。
|
||||
|
||||
综上分析完毕,C++代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
bool canPartition(vector<int>& nums) {
|
||||
|
@ -126,7 +126,7 @@ public:
|
||||
|
||||
把[452.用最少数量的箭引爆气球](https://mp.weixin.qq.com/s/HxVAJ6INMfNKiGwI88-RFw)代码稍做修改,就可以AC本题。
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
// 按照区间右边界排序
|
||||
@ -152,7 +152,7 @@ public:
|
||||
```
|
||||
|
||||
这里按照 左区间遍历,或者按照右边界遍历,都可以AC,具体原因我还没有仔细看,后面有空再补充。
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
// 按照区间左边界排序
|
||||
|
@ -78,7 +78,7 @@ if (root == nullptr) return root;
|
||||
|
||||
代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
if (root->val == key) {
|
||||
// 第二种情况:左右孩子都为空(叶子节点),直接删除节点, 返回NULL为根节点
|
||||
// 第三种情况:其左孩子为空,右孩子不为空,删除节点,右孩子补位 ,返回右孩子为根节点
|
||||
@ -111,7 +111,7 @@ return root;
|
||||
|
||||
**整体代码如下:(注释中:情况1,2,3,4,5和上面分析严格对应)**
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
TreeNode* deleteNode(TreeNode* root, int key) {
|
||||
@ -156,7 +156,7 @@ public:
|
||||
|
||||
代码如下:(关键部分已经注释)
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
TreeNode* deleteNode(TreeNode* root, int key) {
|
||||
@ -186,7 +186,7 @@ public:
|
||||
|
||||
代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
private:
|
||||
// 将目标节点(删除节点)的左子树放到 目标节点的右子树的最左面节点的左孩子位置上
|
||||
|
@ -84,7 +84,7 @@
|
||||
|
||||
C++代码如下:
|
||||
|
||||
```C++
|
||||
```CPP
|
||||
class Solution {
|
||||
private:
|
||||
static bool cmp(const vector<int>& a, const vector<int>& b) {
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user