动态规划专栏

动态规划(100道)

分类说明

以下题目均来源于力扣,其汇总主要是按照难易程度进行划分,大家可以选择适合自己的部分进入。

题目难度:容易

  1. 53.最大子序和 (C++实现)
  2. 70.爬楼梯(C++实现)
  3. 118.杨辉三角(C++实现)
  4. 119.杨辉三角 Ⅱ(C++实现)
  5. 121.买卖股票的最佳时机(C++实现)
  6. 338.比特位计数(C++实现)
  7. 392.判断子序列(C++实现)
  8. 509.斐波那契数列(C++实现)

题目难度:中等

  1. 230. 二叉搜索树中第K小的元素(C++实现)
  2. 5. 最长回文子串
  3. 22. 括号生成(C++实现)
  4. 45. 跳跃游戏 II
  5. 55. 跳跃游戏
  6. 62. 不同路径(C++实现)
  7. 63. 不同路径 II(C++实现)
  8. 64. 最小路径和(C++实现)
  9. 91. 解码方法(C++实现)
  10. 95. 不同的二叉搜索树 II
  11. 96. 不同的二叉搜索树
  12. 97. 交错字符串
  13. 120. 三角形最小路径和
  14. 122. 买卖股票的最佳时机 II(C++实现)
  15. 131. 分割回文串
  16. 139. 单词拆分
  17. 152. 乘积最大子数组
  18. 198. 打家劫舍
  19. 213. 打家劫舍 II
  20. 221. 最大正方形
  21. 241. 为运算表达式设计优先级
  22. 264. 丑数 II
  23. 279. 完全平方数
  24. 300. 最长递增子序列
  25. 309. 最佳买卖股票时机含冷冻期
  26. 313. 超级丑数
  27. 322. 零钱兑换
  28. 337. 打家劫舍 III
  29. 343. 整数拆分
  30. 357. 计算各个位数不同的数字个数
  31. 368. 最大整除子集
  32. 375. 猜数字大小 II
  33. 376. 摆动序列
  34. 377. 组合总和 Ⅳ
  35. 396. 旋转函数
  36. 397. 整数替换
  37. 413. 等差数列划分
  38. 416. 分割等和子集
  39. 435. 无重叠区间
  40. 464. 我能赢吗
  41. 467. 环绕字符串中唯一的子字符串
  42. 473. 火柴拼正方形
  43. 474. 一和零
  44. 486. 预测赢家
  45. 494. 目标和
  46. 516. 最长回文子序列
  47. 518. 零钱兑换 II
  48. 526. 优美的排列
  49. 542. 01 矩阵
  50. 553. 最优除法
  51. 576.出界的路径数
  52. 583. 两个字符串的删除操作
  53. 638. 大礼包
  54. 647. 回文子串
  55. 650. 只有两个键的键盘
  56. 673. 最长递增子序列的个数
  57. 678. 有效的括号字符串
  58. 688. “马”在棋盘上的概率
  59. 剑指offer 14 剪绳子((C++实现)

题目难度:困难

  1. 10. 正则表达式匹配
  2. 32. 最长有效括号
  3. 42. 接雨水
  4. 44. 通配符匹配
  5. 72. 编辑距离
  6. 85. 最大矩形
  7. 87. 扰乱字符串
  8. 115. 不同的子序列
  9. 123. 买卖股票的最佳时机 III
  10. 124. 二叉树中的最大路径和
  11. 132. 分割回文串 II
  12. 140. 单词拆分 II
  13. 174. 地下城游戏
  14. 188. 买卖股票的最佳时机 IV
  15. 数字 1 的个数
  16. 312. 戳气球
  17. 329. 矩阵中的最长递增路径
  18. 354. 俄罗斯套娃信封问题
  19. 363. 矩形区域不超过 K 的最大数值和
  20. 403. 青蛙过河
  21. 410. 分割数组的最大值
  22. 446. 等差数列划分 II - 子序列
  23. 458. 可怜的小猪
  24. 466. 统计重复个数
  25. 472. 连接词
  26. 514. 自由之路
  27. 546. 移除盒子
  28. 552. 学生出勤记录 II
  29. 600. 不含连续1的非负整数
  30. 629. K个逆序对数组
  31. 639. 解码方法 II
  32. 646. 最长数对链
  33. 664. 奇怪的打印机
  34. 689. 三个无重叠子数组的最大和
  35. 691. 贴纸拼词

题目讲解

53.

int maxSubArray(vector<int>& nums)
{
	int dp = nums[0];//如果只有一个元素,则为它本身;
	int result = dp;

	for (int i = 1; i < nums.size(); ++i)
	{
		dp = max(nums[i], nums[i] + dp);//当前元素最大子序列和要么是它本身,要么是前面的最大和加它
		result = max(result, dp);//最终的最大子序列和为:在当前元素最大子序列和前面所有元素最大子序列和取最大值
	}
	return result;
}

70.

int climbStairs(int n) 
{
	vector<int> v;
	v.push_back(1);//1个台阶,有1种方法
	v.push_back(2);//2个台阶,有2种方法
	for (int i = 2; i < n; ++i)
	{
		v.push_back(v[i - 1] + v[i - 2]);//n个台阶的方法数=(n-1)个台阶方法数+(n-2)个台阶方法数
	}
	return v[n - 1];
}

//递归调用,会超时
if (n == 1)
		return 1;
	if (n == 2)
		return 2;
	return climbStairs(n - 1) + climbStairs(n - 2);

118.

vector<vector<int>> generate(int numRows)
{
	vector<vector<int>> v;
	v.resize(numRows);//vector采用[]赋值,需要提前指定vector大小
	v[0].resize(1);
	v[0][0] = 1;//第一行的元素为1
	for (int i = 1; i < numRows; ++i)
	{
		v[i].resize(i + 1);
		v[i][0] = 1;//第i行的第1个元素为1
		int j = 1;
		for (; j < i; ++j)
		{
			v[i][j] = v[i - 1][j - 1] + v[i - 1][j];//第i行的第j个元素=第i-1行的第j个元素+第i-1行的第j-1个元素
		}
		v[i][j] = 1;//第i行的最后一个元素为1
	}
	return v;
}

119.

vector<int> getRow(int rowIndex)
{
	vector<vector<int>> v;
	v.resize(rowIndex+1);//vector采用[]赋值,需要提前指定vector大小
	v[0].resize(1);
	v[0][0] = 1;//第一行的元素为1
	for (int i = 1; i <= rowIndex; ++i)
	{
		v[i].resize(i + 1);
		v[i][0] = 1;//第i行的第1个元素为1
		int j = 1;
		for (; j < i; ++j)
		{
			v[i][j] = v[i - 1][j - 1] + v[i - 1][j];//第i行的第j个元素=第i-1行的第j个元素+第i-1行的第j-1个元素
		}
		v[i][j] = 1;//第i行的最后一个元素为1
	}

	return v[rowIndex];//返回第rowIndex+1行的所有元素
}

121.

int maxProfit(vector<int>& prices) {
	int min = prices[0];//记录前n-1天价格的最小值
	int income = 0;//income=(买入-卖出)=-利润
	for (int i = 1; i < prices.size(); ++i)
	{
		if (income > (min - prices[i]))//前n-1天最小的买入价格-第n天的价格=可以求出最大的利润
		{
			income = min - prices[i];
		}
		if (min > prices[i])
		{
			min = prices[i];//更新前n-1天最小的买入价格
		}
	}
	return -income;
}

338.

vector<int> countBits(int n) {
	vector<int> v;
	v.resize(n + 1);
	v[0] = 0;
	for (int i = 1; i <= n; ++i)
	{
		if (i % 2 == 0)//n为偶数时,1比特个数=(n/2)的1比特个数
		{
			v[i] = v[i / 2];
		}
		else 
		{
			v[i] = v[i - 1] + 1;//n为奇数时,1比特个数=(n-1)的1比特个数+1
		}
	}
	
	return v;
}

392.

bool isSubsequence(string s, string t) {
    int slength = s.length();
    int tlength = t.length();
    int j = 0;
    for (int i = 0; i < slength; ++i)
    {
        for (; j < tlength; j++)
        {
            if (s[i] == t[j])//s[i]若在t中找到,则跳出循环
            {
                break;
            }
        }
        if (j == tlength)//t序列指针到达末尾,说明未找到
        {
            return false;
        }
        j++;//找到了则t序列指针下移,为寻找s序列的下一个元素做准备
    }
    return true;
}

509.

int fib(int n) {
        if (n == 0 || n == 1)
            return n;
        int mya = 0, myb = 1, myc;
        for (int i = 2; i<= n; i++)//从n=2开始满足该规律
        {
            myc = mya + myb;
            mya = myb;
            myb = myc;
        }
        return myc;
    }

230.

int kthSmallest(TreeNode* root, int k) {
        stack<TreeNode*> s;
        TreeNode* r = root;
        while (r != NULL)
        {
            s.push(r);
            r = r->left;
        }
        int count = 0;
        while (!s.empty())
        {
            TreeNode* tmp = s.top();
            s.pop();
            count++;
            if (count == k)
            {
                return tmp->val;
            }
            if (tmp->right != NULL)
            {
                tmp = tmp->right;
                while (tmp != NULL)
                {
                    s.push(tmp);
                    tmp = tmp->left;
                } 
            }
        }
        return count;
    }

22.

void findPare(int lPare, int rPare, int n, string s, vector<string>* v)
{
	if (lPare + rPare == 2 * n)//左右括号都为n时,表示结束
	{
		v->push_back(s);
		return;
	}

	if (rPare > lPare)//当右括号多余左括号时,违反规则
	{
		return;
	}

	if (rPare < lPare)//右括号少于左括号,便可以添加右括号
	{
		s = s + ')';
		findPare(lPare, rPare + 1, n, s, v);
		s.pop_back();//回溯时,需要将添加的右括号删除
	}

	if (lPare < n)//左括号只需要少于n,便可一直添加左括号
	{
		s= s + '(';
		findPare(lPare + 1, rPare, n, s, v);
		s.pop_back();
	}


}

vector<string> generateParenthesis(int n) {
	
	vector<string> v;
	string s;
	findPare(0,0,n,s,&v);
	return v;
}

62.

写法一:
int uniquePaths(int m, int n) {
        int arr[100][100];
        for(int i=0;i<m;i++)//第一行只能横着走,只有一种方法到达
        {
            arr[i][0]=1;
        }
        for(int j=0;j<n;j++)//第一列只能竖着走,只有一种方法到达
        {
            arr[0][j]=1;
        }
        for(int i=1;i<m;i++)
        {
            for(int j=1;j<n;j++)
            {
                arr[i][j]=arr[i-1][j]+arr[i][j-1];//每个位置i,j的到达方法等于上面位置的到达方法+左边位置的到达方法
            }
        }
        return arr[m-1][n-1];
    }

写法二:
    int uniquePaths(int m, int n) {
        int arr[100][100]={0};//要初始化
        arr[0][0]=1;
        for(int i=0;i<m;i++)
        {
            for(int j=0;j<n;j++)
            {
                if(i+1<m)
                {
                    arr[i+1][j]+=arr[i][j];//遍历每一个i,j,计算右边的和下面的路径数
                }
                if(j+1<n)
                {
                    arr[i][j+1]+=arr[i][j];
                }
            }

        }
        return arr[m-1][n-1];
    }

63.

 int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) {
      int arr[100][100]={0};
      if(obstacleGrid[0][0]==1)//如果该位置有障碍物,则该位置处的路径数为0
      {
          arr[0][0]=0;
      }else
      {
          arr[0][0]=1;
      }

      for(int i=0;i<obstacleGrid.size();i++)
      {
          for(int j=0;j<obstacleGrid[0].size();j++)
          {
              if(i+1<obstacleGrid.size())
              {
                  if(obstacleGrid[i+1][j]==1)
                  {
                     arr[i+1][j]=0;
                  }else
                  {
                      arr[i+1][j]+=arr[i][j];
                  }
              }
              if(j+1<obstacleGrid[0].size())
              {
                  if(obstacleGrid[i][j+1]==1)
                  {
                     arr[i][j+1]=0;
                  }else
                  {
                      arr[i][j+1]+=arr[i][j];
                  }
              }
          }
      }
      return arr[obstacleGrid.size()-1][obstacleGrid[0].size()-1];
    }

64.

 int minPathSum(vector<vector<int>>& grid) {
        int m=grid.size();
        int n=grid[0].size();
        int arr[200][200]={0};
        arr[0][0]=grid[0][0];//(i,j)表示所有路径到达当前路径的最小值
        for(int i=0;i<m;i++)
        {
            for(int j=0;j<n;j++)
            {
                int tmp1,tmp2;
                if(i-1>=0)
                {
                    tmp1=arr[i-1][j]+grid[i][j];
                }
                if(j-1>=0)
                {
                    tmp2=arr[i][j-1]+grid[i][j];
                }
                if(i==0&&j!=0)
                {
                    arr[i][j]=tmp2;
                }
                if(j==0&&i!=0)
                {
                    arr[i][j]=tmp1;
                }
                if(i!=0&&j!=0)
                {
                    arr[i][j]=min(tmp1,tmp2);//该最小值为min(上方位置的路径最小值,左边位置路径最小值)
                }
            }
        }
        return arr[m-1][n-1];
    }

91.

int numDecodings(string s) {
        int len=s.length();
        vector<int> arr(len);

        if(s[0]=='0') return 0;
        arr[0]=1;
        for(int i=1;i<len;i++)
        {
            if(s[i]!='0')
            {
                arr[i]+=arr[i-1];
            }
            if((s[i-1]=='1')||(s[i-1]=='2'&&s[i]<='6'))
            {
                if(i-2>=0)
                    arr[i]+=arr[i-2];
                else
                    arr[i]++;
            }

        }
        return arr[len-1];
    }

122.

/*贪心:
如果你知道明天股价会跌,那你今天肯定不会入手;同理如果你知道明天会涨,那你今天肯定会买;*/
int maxProfit(vector<int>& prices) {
        int tmp;
        int sum=0;
        for(int i=1;i<prices.size();i++)
        {
            tmp=prices[i]-prices[i-1];
            if(tmp>0)
            sum=sum+tmp;
        }
        return sum;
    }

59.

	int cuttingRope(int n) {
	        int* dp = new int[n+1];
	        dp[1]=1;
	        dp[2]=1;//如果绳子长2m,因为剪的段数至少为2个,所以只能时1*1
	        for(int i=3;i<=n;i++)//从绳子长为3开始计算,直到n
	        {
	            for(int j=2;j<i;j++)//每次剪得绳子长度至少为2,但又必须剪,所以小于i
	            {
	                dp[i]=max(dp[i],max(j*(i-j),j*dp[i-j]));
	                //内部max是比较剪了一段j长的绳子后,如果不减,和继续剪,哪个更大;
	                //外部max是比较这一次剪不同的j,哪次乘机最大;
	            }
	        }
	        return dp[n];
	    }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值