第一题 Leetcode110.平衡二叉树
题解
class Solution {
public:
bool isBalanced(TreeNode* root) {
return getHeight(root) == -1 ? false : true;
}
int getHeight(TreeNode* root) {
if (root == nullptr)
return 0;
int HL = getHeight(root->left);
if (HL == -1)
return -1;
int HR = getHeight(root->right);
if (HR == -1)
return -1;
return abs(HR - HL) > 1 ? -1 : 1 + max(HR, HL);
}
};
第二题 Leetcode257. 二叉树的所有路径
题解
class Solution {
public:
vector<string> ans;
vector<string> binaryTreePaths(TreeNode* root) {
if (root == nullptr)
return ans;
string str = "";
bT(root, str, 0);
return ans;
}
void bT(TreeNode* root, string str, int time) {
if (time > 0)
str += "->";
str += to_string(root->val);
if (root->left == nullptr && root->right == nullptr)
ans.push_back(str);
if (root->left)
bT(root->left, str,1);
if (root->right)
bT(root->right, str,1);
}
};
要点
- 回溯算法,回溯特点:使用函数参数的传值
-
函数参数含义:str 为已有路径,time 为是否是第一个数字,用于控制 “->” 的输出void bT(TreeNode* root, string str, int time)
- to_string() 函数将数字转成字符串,位于<string>头文件中;atoi 函数将字符串转成整数,如果不能转换则返回0,位于 <stdlib.h>,对于string字符串,需要使用 str.c_str() 函数将其转成char*;atof 类似。
第三题:Leetcode404.左叶子之和
题解
class Solution {
public:
int sumOfLeftLeaves(TreeNode* root) {
if (root == nullptr ||
(root->left == nullptr && root->right == nullptr))
return 0;
int leftV = sumOfLeftLeaves(root->left);
if (root->left != nullptr && root->left->left == nullptr &&
root->left->right == nullptr)
// 左子树就是左叶子,这时候leftV取值必定为0
leftV = root->left->val;
int rightV = sumOfLeftLeaves(root->right);
// cout << leftV << endl << rightV << endl;
return rightV + leftV;
}
};
要点
- 左叶子定义:节点A的左孩子不为空,且左孩子的左右孩子都为空(说明是叶子节点),那么A节点的左孩子为左叶子节点。
- 当遇到左叶子节点的时候,记录数值,然后通过递归求取左子树左叶子之和,和 右子树左叶子之和,相加便是整个树的左叶子之和。
疑惑
如果将
if (root == nullptr || (root->left == nullptr && root->right == nullptr))
return 0;
换成
if (root == nullptr)
return 0;
if (root->left == nullptr && root->right == nullptr)
return 0;
运行时间就会由 0ms 提高到 9ms,影响有这么大?
第四题:Leetcode222. 完全二叉树的节点个数
题解
class Solution {
public:
int countNodes(TreeNode* root) {
if (root == nullptr)
return 0;
return 1 + countNodes(root->left) + countNodes(root->right);
}
};
第五题:Leetcode746. 使用最小花费爬楼梯——动态规划
题目描述

思路
动态规划的要点
1. 确定dp数组(dp table)以及下标的含义
2. 确定递推公式
3. dp数组如何初始化
4. 确定遍历顺序
5. 举例推导dp数组动态规划题目牢牢抓紧这五个步骤解题。
- 本题中,dp 数组被初始化为 n+1 大小的int数组,最后返回 dp[n] 元素,dp[i] 表示到达下标为i的台阶的最低花费。
- 初始化:dp[0] = dp[1] = 0 ,表示下标为0和下标为1的台阶代价为0。
- 递推公式:要到达下标为 i 的台阶,可以在 i-1 花费代价 cost[i-1] 到达,也可以在 i-2 花费代价cost[i-2] 到达,因此递归公式为
,从而遍历顺序为从低到高。
- 优化:由于只使用 dp[i-1] 和 dp[i-2] ,因此使用两个变量代替dp数组即可,将空间复杂度降到O(1),时间复杂度仍然是O(n)。
题解
class Solution {
public:
int minCostClimbingStairs(vector<int>& cost) {
int dp0 = 0, dp1 = 0;
int dpi;
for (int i = 2; i <= cost.size(); i++) {
dpi = min(dp0 + cost[i - 2], dp1 + cost[i - 1]);
dp0 = dp1;
dp1 = dpi;
}
return dp1;
}
};
第六题:Leetcode62. 不同路径
题目描述

题解1——数论组合
总共需要走m+n-2步,其中m-1步向下,n-1步向右,因此是
如果使用连乘算出来分子,int会溢出,因此需要一边乘,一边除。
class Solution {
public:
int uniquePaths(int m, int n) {
long long fenzi=1;
int fenmu = m - 1;
int count = m - 1;
int t = n + m - 2;
while (count-- > 0) {
fenzi *= t;
while (fenmu != 0 && fenzi % fenmu == 0) {
fenzi /= fenmu;
fenmu--;
}
cout<<"分子;"<<fenzi <<endl;
t--;
}
return fenzi;
}
};
题解2——动态规划
动态规划的要点
1. 确定dp数组(dp table)以及下标的含义
2. 确定递推公式
3. dp数组如何初始化
4. 确定遍历顺序
5. 举例推导dp数组动态规划题目牢牢抓紧这五个步骤解题。
- dp数组为
,
表示从
到
的不同路径数。
- 对于
,可以从
下移一步或者从
右移一步,因此递推公式为
。
- 初始化:
从
遍历到
,
从
遍历到
,返回
。
class Solution {
public:
int uniquePaths(int m, int n) {
vector<vector<int>> dp(m, vector<int>(n, 1));
for (int i = 1; i < m; i++) {
for (int j = 1; j < n; j++) {
dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
}
}
return dp[m - 1][n - 1];
}
};
第七题:Leetcode63. 不同路径 II
题目描述
思路
与62题类似,仅仅修改一下初始化和递推逻辑。
和
在遇到obstacle之前初始化为1,在遇到obstacle之后(包括obstacle)初始化为0。
为obstacle时,
= 0,否则递推公式为:
。
题解
class Solution {
public:
int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) {
const int m = obstacleGrid.size();
const int n = obstacleGrid[0].size();
vector<vector<int>> dp(m, vector<int>(n, 0));
for (int i = 0; i < m; i++) {
if (obstacleGrid[i][0] == 1)
break;
dp[i][0] = 1;
}
for (int j = 0; j < n; j++) {
if (obstacleGrid[0][j] == 1)
break;
dp[0][j] = 1;
}
for (int i = 1; i < m; i++)
for (int j = 1; j < n; j++)
if (obstacleGrid[i][j] == 1)
dp[i][j] = 0;
else {
dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
}
return dp[m - 1][n - 1];
}
};
第八题:Leetcode343. 整数拆分
题目描述
思路
- 递推数组
,
表示数字
拆分的最大值。
- 对于
,遍历
,在元素
进行拆分,
,第一项
代表将
拆分为
和
两个数字,第二项代表将
拆分成
、并且将
也拆分成多项。
初始化为
。
从3开始遍历到n,j从1遍历到n-1。
- 优化:对于
,根据常识,将其拆分为最接近的两个数,乘积会更大一些,因此j遍历区间改为[1,i/2]。
题解
class Solution {
public:
int integerBreak(int n) {
vector<int> dp(n + 1, 0);
dp[2] = 1;
for (int i = 3; i <= n; i++) {
for (int j = 1; j <= i / 2; j++) {
// max(j * (i - j), j * dp[i - j]),前者是将i拆解成j和i-j两个数
// 后者是将i拆解成 j和(i-j拆解的结果)
// 第一个dp[i]是不同的j的结果
dp[i] = max(dp[i], max(j * (i - j), j * dp[i - j]));
}
}
return dp[n];
}
};