283. Move Zeroes
27. Remove Element
26. Remove Duplicates from Sorted Array
80. Remove Duplicates from Sorted Array II
// 解法一:最直观的解法,新建一个vector res,遍历nums,将非0元素依次赋值入res即可
// 时间复杂度O(n),空间复杂度O(n)
class Solution {
public:
void moveZeroes(vector<int>& nums) {
vector<int> res(nums.size(), 0);
int index = 0;
for(auto it = nums.begin(); it != nums.end(); ++it){
if(*it != 0){
res[index] = *it;
++index;
}
}
nums = res;
}
};
动态规划
// 解法一:递归
class Solution {
public:
int climbStairs(int n) {
if( n == 0 || n == 1)
return 1;
return climbStairs(n-1) + climbStairs(n-2);
}
};
// 解法二:递归+记忆化搜索
class Solution {
private:
vector<int> memo;
int calcWays(int n){
if(n == 0 || n == 1)
return 1;
if(memo[n] == -1){
memo[n] = calcWays(n-1) + calcWays(n-2);
}
return memo[n];
}
public:
int climbStairs(int n) {
memo = vector<int>(n+1, -1);
return calcWays(n);
}
};
// 解法三:动态规划
class Solution {
public:
int climbStairs(int n) {
// n >= 1
vector<int> memo(n+1, -1);
memo[0] = 1;
memo[1] = 1;
for( int i = 2 ; i <= n ; i ++ )
memo[i] = memo[i-1] + memo[i-2];
return memo[n];
}
};
// 自上向下
class Solution {
public:
int minimumTotal(vector<vector<int>>& triangle) {
vector<vector<int>> res(triangle.size(), vector<int>(triangle.size(), -1));
for(int i = 0; i < triangle.size(); ++i){
for(int j = 0; j < triangle[i].size(); ++j){
if(i == 0)
res[i][j] = triangle[i][j];
else if(j == 0)
res[i][j] = res[i-1][j] + triangle[i][j];
else if(j >= triangle[i-1].size())
res[i][j] = res[i-1][j-1] + triangle[i][j];
else
res[i][j] = min(res[i-1][j-1], res[i-1][j]) + triangle[i][j];
}
}
return *min_element(res[triangle.size()-1].begin(), res[triangle.size()-1].end());
}
};
// 创建一个和输入矩阵同等大小的矩阵res
// res[row][col]存储从左上角到达这个点的最小距离
// res[row][col] = min(grid[row-1][col], grid[row][col-1]) + grid[row][col]
class Solution {
public:
int minPathSum(vector<vector<int>>& grid) {
if(grid.size() == 0)
return 0;
vector<vector<int>> res(grid.size(), vector<int>(grid[0].size(), -1));
for(int row = 0; row < grid.size(); ++row){
for(int col = 0; col < grid[0].size(); ++col){
// min(grid[row-1][col], grid[row][col-1]) + grid[row][col]
// 处于第一行,第一列
if(row == 0 && col == 0){
res[row][col] = grid[row][col];
}
// 第一行,没有上侧元素
else if(row == 0){
res[row][col] = res[row][col-1] + grid[row][col];
}
// 第一列,没有左侧元素
else if(col == 0){
res[row][col] = res[row-1][col] + grid[row][col];
}
else{
res[row][col] = min(res[row-1][col], res[row][col-1]) + grid[row][col];
}
}
}
return res[grid.size() - 1][grid[0].size() - 1];
}
};
// n = 1 n = 2 n = 3比较特殊,单独考虑
// n >= 4 : f(n) = max(f(n-1)*f(1), f(n-2)*f(2),...,f(1)*f(n-1))
// f(n-1)f(1) 与 f(1)f(n-1)重复计算,算一半就可以了,循环条件j <= i/2即可
class Solution {
public:
int integerBreak(int n) {
if(n == 2)
return 1;
if(n == 3)
return 2;
// n >= 4
vector<int> res(n+1, -1);
res[1] = 1; // n = 1
res[2] = 2; // n = 2
res[3] = 3; // n = 3
for(int i = 4; i <= n; ++i){
int temp = 0;
for(int j = 1; j <= i/2; ++j){
temp = max(temp, res[j] * res[i-j]);
}
res[i] = temp;
}
return res[n];
}
};
// 简单的动态规划思想,但leetcode超时了
class Solution {
public:
int numSquares(int n) {
if(n < 1)
return 0;
vector<int> res(n+1, 0);
res[0] = 0;
res[1] = 1;
for(int i = 2; i <= n; ++i){
// n本身就是一个完全平方数,不需要拆开,结果直接置为1
if(int(sqrt(i)) * int(sqrt(i)) == i)
res[i] = 1;
else{
int min_count = INT_MAX;
// 需要拆成两个数
for(int j = 1; j <= i/2; ++j){
min_count = min(res[j]+res[i-j], min_count);
}
res[i] = min_count;
}
}
return res[n];
}
};
// 改进一下:
// 通过leetcode
class Solution {
public:
/* 如果一个数x可以表示为一个任意数a加上一个平方数bxb,也就是x = a + bxb,
* 那么能组成这个数x最少的平方数个数,就是能组成a最少的平方数个数加上1(因为b*b已经是平方数了)。
*/
int numSquares(int n) {
// 将所有非平方数的结果置最大,保证之后比较的时候不被选中
vector<int> nums(n + 1, INT_MAX);
// 将所有整平方数的结果置1
for (int i = 0; i*i <= n; ++i)
nums[i*i] = 1;
// 从小到大找任意数a
for (int a = 0; a <= n; ++a){
// 从小到大找平方数b*b
for (int b = 0; a + b*b <= n; ++b){
// 因为a+b*b可能本身就是平方数,所以我们要取两个中较小的
nums[a + b*b] = min(nums[a] + 1, nums[a + b*b]);
}
}
return nums[n];
}
};
// 和青蛙跳台阶很像
// f(n) = f(n-1) + f(n-2)
// 但是多了限制条件,需要检查最后一个或两个数字是否能构成有效的编码
class Solution {
public:
int numDecodings(string s) {
if (s.empty())
return 0;
vector<int> res(s.size() + 1, 0);
if (s.size() >= 1 && isValidForOneBit(int(s[0] - '0')))
res[1] = 1;
if (s.size() >= 2){
if (isValidForOneBit(s[0] - '0') && isValidForOneBit(int(s[1] - '0')))
res[2] += 1;
if (isValidForTwoBit(atoi(s.substr(0, 2).c_str())))
res[2] += 1;
}
for (int i = 2; i < s.size(); ++i){
if (isValidForOneBit(int(s[i] - '0')))
res[i + 1] += res[i];
if (isValidForTwoBit(atoi(s.substr(i - 1, 2).c_str())))
res[i + 1] += res[i - 1];
}
return res[s.size()];
}
bool isValidForOneBit(int n){
return n >= 1 && n <= 9;
}
bool isValidForTwoBit(int n){
return n >= 10 && n <= 26;
}
};
// 这题动态规划就很简单了
// res[row][col] += res[row-1][col] + res[row][col-1]
// 注意边界条件即可
class Solution {
public:
int uniquePaths(int m, int n) {
if(m <= 0 || n <= 0)
return 0;
vector<vector<int>> res(m, vector<int>(n, 0));
for(int i = 0; i < n; ++i)
res[0][i] = 1;
for(int i = 0; i < m; ++i)
res[i][0] = 1;
for(int row = 1; row < m; ++row){
for(int col = 1; col < n; ++col)
res[row][col] += res[row-1][col] + res[row][col-1];
}
return res[m-1][n-1];
}
};
// 相比上一题,多了一点点限制条件而已
class Solution {
public:
int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) {
if(obstacleGrid.size() <= 0 || obstacleGrid[0].size() <= 0)
return 0;
vector<vector<int>> res(obstacleGrid.size(), vector<int>(obstacleGrid[0].size(), 0));
if(obstacleGrid[0][0] == 1)
return 0;
res[0][0] = 1;
// 第一行
for(int col = 1; col < obstacleGrid[0].size(); ++col){
if(obstacleGrid[0][col] != 1)
res[0][col] = res[0][col-1];
else
res[0][col] = 0;
}
// 第一列
for(int row = 1; row < obstacleGrid.size(); ++row){
if(obstacleGrid[row][0] != 1)
res[row][0] = res[row-1][0];
else
res[row][0] = 0;
}
// 其他
for(int row = 1; row < obstacleGrid.size(); ++row){
for(int col = 1; col < obstacleGrid[0].size(); ++col)
if(obstacleGrid[row][col] != 1)
res[row][col] += res[row-1][col] + res[row][col-1];
else
res[row][col] = 0;
}
return res[obstacleGrid.size()-1][obstacleGrid[0].size()-1];
}
};
198. House Robber
213. House Robber II
337. House Robber III
309. Best Time to Buy and Sell Stock with Cooldown