石子游戏
亚历克斯和李用几堆石子在做游戏。偶数堆石子排成一行,每堆都有正整数颗石子 piles[i] 。游戏以谁手中的石子最多来决出胜负。石子的总数是奇数,所以没有平局。亚历克斯和李轮流进行,亚历克斯先开始。 每回合,玩家从行的开始或结束处取走整堆石头。 这种情况一直持续到没有更多的石子堆为止,此时手中石子最多的玩家获胜。假设亚历克斯和李都发挥出最佳水平,当亚历克斯赢得比赛时返回 true ,当李赢得比赛时返回 false 。
class Solution {public:bool stoneGame(vector<int>& piles) {const int length = piles.size();int result[length][length];//只有一个人的时候最多得分for(int i = 0; i < length; i++){result[i][i] = piles[i];}//当集合中有两个数的时候,先选的人拿大数for(int i = 0; i < length - 1; i++){result[i][i + 1] = abs(piles[i] - piles[i + 1]);}for(int i = length - 3; i >= 0; i--){for(int j = i + 2; j < length; j++){result[i][j] = max(piles[i] - result[i + 1][j], piles[j] - result[i][j - 1]);}}return result[0][length - 1] > 0;}};
最大带权路径
在一个 m*n 的棋盘的每一格都放有一个礼物,每个礼物都有一定的价值(价值大于 0)。你可以从棋盘的左上角开始拿格子里的礼物,并每次向右或者向下移动一格、直到到达棋盘的右下角。给定一个棋盘及其上面的礼物的价值,请计算你最多能拿到多少价值的礼物?
我这种写法是把棋盘横过来了
class Solution {public:int maxValue(vector<vector<int>>& grid) {const int len1 = grid.size();const int len2 = grid[0].size();int dp[len1][len2];//初始化边界数据dp[0][0] = grid[0][0];for(int i = 1; i < len1; i++){dp[i][0] = grid[i][0] + dp[i - 1][0];}for(int i = 1; i < len2; i++){dp[0][i] = grid[0][i] + dp[0][i - 1];}for(int i = 1; i < len1; i++){for(int j = 1; j < len2; j++){dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]) + grid[i][j];}}return dp[len1 - 1][len2 - 1];}};
最大正方形
在一个由 0 和 1 组成的二维矩阵内,找到只包含 1 的最大正方形,并返回其面积。示例:输入:1 0 1 0 01 0 1 1 11 1 1 1 11 0 0 1 0输出: 4
class Solution {public:int maximalSquare(vector<vector<char>>& matrix) {const int m = matrix.size();if(m == 0) return 0;const int n = matrix[0].size();int dp[m][n], ans = 0;for (int i = 0; i < m; i++) {for (int j = 0; j < n; j++) {dp[i][j] = matrix[i][j] == '1' ? 1 : 0;ans = max(ans, dp[i][j]);}}for(int i = 1; i < m; i++){for(int j = 1; j < n; j++){if(matrix[i][j] == '1'){dp[i][j] = min(dp[i - 1][j], min(dp[i - 1][j - 1], dp[i][j - 1])) + 1;ans = max(ans, dp[i][j]);}}}return ans * ans;}};
全为1的正方形
给你一个 m * n 的矩阵,矩阵中的元素不是 0 就是 1,请你统计并返回其中完全由 1 组成的 正方形 子矩阵的个数。示例 1:输入:matrix =[[0,1,1,1],[1,1,1,1],[0,1,1,1]]输出:15解释:边长为 1 的正方形有 10 个。边长为 2 的正方形有 4 个。边长为 3 的正方形有 1 个。正方形的总数 = 10 + 4 + 1 = 15.
class Solution {public:int countSquares(vector<vector<int>>& matrix) {int m = matrix.size();if(m == 0) return 0;int n = matrix[0].size();for(int i = 1; i < m; i++){for(int j = 1; j < n; j++){if(matrix[i][j] == 1){matrix[i][j] = min(min(matrix[i - 1][j], matrix[i][j - 1]), matrix[i - 1][j - 1]) + 1;}}}int ans = 0;for(int i = m - 1; i >= 0; i--){for(int j = n - 1; j >= 0; j--){ans += matrix[i][j];}}return ans;}};
不同的二叉搜索树
输入: 3输出: 5解释:给定 n = 3, 一共有 5 种不同结构的二叉搜索树:1 3 3 2 1\ / / / \ \3 2 1 1 3 2/ / \ \2 1 2 3
class Solution {public:int numTrees(int n) {int G[100] = {0};G[0] = 1;G[1] = 1;G[2] = 2;for (int i = 3; i <= n; ++i) {for (int j = 1; j <= i; ++j) {G[i] += G[j - 1] * G[i - j];}}return G[n];}};
最小路径和
给定一个包含非负整数的 m x n 网格,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。说明:每次只能向下或者向右移动一步。示例:输入:[[1,3,1],[1,5,1],[4,2,1]]输出: 7解释: 因为路径 1→3→1→1→1 的总和最小。
class Solution {public:int minPathSum(vector<vector<int>>& grid) {const int m = grid.size();if(m == 0) return 0;const int n = grid[0].size();int dp[m][n];dp[0][0] = grid[0][0];for(int i = 1; i < n; i++) dp[0][i] = grid[0][i] + dp[0][i - 1];for(int i = 1; i < m; i++) dp[i][0] = grid[i][0] + dp[i - 1][0];for(int i = 1; i < m; i++){for(int j = 1; j < n; j++){dp[i][j] = min(dp[i - 1][j], dp[i][j - 1]) + grid[i][j];}}return dp[m - 1][n - 1];}};
数塔问题
给定一个三角形,找出自顶向下的最小路径和。每一步只能移动到下一行中相邻的结点上。例如,给定三角形:[[2],[3,4],[6,5,7],[4,1,8,3]]自顶向下的最小路径和为 11(即,2 + 3 + 5 + 1 = 11)。
class Solution {public:int minimumTotal(vector<vector<int>>& triangle) {const int maxn = triangle.size();int dp[maxn][maxn];for(int i = 0; i < maxn; i++){dp[maxn - 1][i] = triangle[maxn - 1][i];}for(int i = maxn - 2; i >= 0; i--){for(int j = 0; j <= i; j++){dp[i][j] = min(dp[i + 1][j], dp[i + 1][j + 1]) + triangle[i][j];}}return dp[0][0];}};
股票问题
假设把某股票的价格按照时间先后顺序存储在数组中,请问买卖该股票一次可能获得的最大利润是多少?示例 1:输入: [7,1,5,3,6,4]输出: 5解释: 在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格。
class Solution {public:int maxProfit(vector<int>& prices) {const int len = prices.size();if(len == 0) return 0;int dp[len][2];dp[0][0] = 0;dp[0][1] = -prices[0];for(int i = 1; i < len; i++){dp[i][0] = max(dp[i - 1][0], dp[i - 1][1] + prices[i]);dp[i][1] = max(dp[i - 1][1], - prices[i]);}return dp[len - 1][0];}};
最长上升子序列
这题以前写过,这里再写一遍熟悉一下题目
把动态规划题目的步骤在扩展一点:
- 定义数组含义
- 定义计算方式
- 给初值
- 考虑输出结果(这一步之前一直忽略,其实有很多题目都是输出过程中的最大值的)
class Solution {public:int lengthOfLIS(vector<int>& nums) {const int len = nums.size();if(len == 0) return 0;int dp[len], max_len = -1;fill(dp, dp + len, 1);for(int i = 0; i < len; i++){for(int j = 0; j < i; j++){if(nums[i] > nums[j] && (dp[j] + 1 > dp[i])){dp[i] = dp[j] + 1;}}max_len = max(max_len, dp[i]);}return max_len;}};
最长回文子串
题目:https://leetcode-cn.com/problems/longest-palindromic-substring/submissions/
要点:
- 初始化长度为1、2的字串
- 最外层循环,长度从3开始
步骤:
- 下定义:dp[i][j]的含义是从第i个到第j个的子串是否是回文
- 给数组:如果头尾相等且掐头去尾的子串是回文,那么当前的也是回文
- 给初值:先初始化单个字符以及长度为2的字符串
- 输出:需要在判断的过程中就记录最大的长度
class Solution {public:string longestPalindrome(string s) {const int len = s.size();if(len == 0) return "";int dp[len + 1][len + 1];int ans = 1, ans_i = 0;memset(dp, 0, sizeof(dp));dp[0][0] = 1;for(int i = 1; i < len; i++){dp[i][i] = 1;if(s[i - 1] == s[i]){dp[i - 1][i] = 1;ans_i = i - 1;ans = 2;}}for(int L = 3; L <= len; L++){for(int i = 0; i + L - 1 < len; i++){int j = i + L - 1;if(s[i] == s[j] && dp[i + 1][j - 1] == 1) {dp[i][j] = 1;ans_i = i;ans = max(ans, L);}}}return s.substr(ans_i, ans);}};
买卖股票的最佳时机含冷冻期
题目:https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-with-cooldown/submissions/
与原始版本不同的地方是,这题初值需要额外定义第一天的,另外就是持有股票的转移是从前天开始,而不是昨天
class Solution {public:int maxProfit(vector<int>& prices) {const int len = prices.size();if(len <= 1) return 0;int dp[len][2];dp[0][0] = 0;dp[0][1] = - prices[0];dp[1][0] = max(dp[0][0], dp[0][1] + prices[1]);dp[1][1] = max(dp[0][1], dp[0][0]- prices[1]);for(int i = 2; i < len; i++){dp[i][0] = max(dp[i - 1][0], dp[i - 1][1] + prices[i]);dp[i][1] = max(dp[i - 1][1], dp[i - 2][0] - prices[i]);}return dp[len - 1][0];}};
完全平方数
题目:https://leetcode-cn.com/problems/perfect-squares/submissions/
这题算是自己独立写出来的8,还挺有成就感的
class Solution {public:int numSquares(int n) {// 下定义:dp[i]的含义是组成i这个数的时候,所需要的最少的完全平方数// 找关系:先找出小于i的最大的一个完全平方数a,那么有dp[i] = dp[i - a] + 1;// 给初值:dp[0] = 0, dp[1] = 1const int num = n;int dp[num + 1];dp[0] = 0, dp[1] = 1;for(int i = 2; i <= num; i++){int a = (int)sqrt(i);dp[i] = 999999999;for(int j = 1; j <= a; j++){dp[i] = min(dp[i], dp[i - j * j] + 1);}}return dp[num];}};
整数拆分
题目:https://leetcode-cn.com/problems/integer-break/submissions/
这题感觉有点考数学水平了,记住转移方程,下次遇到会做就行了
class Solution {public:int integerBreak(int n) {// 下定义:dp[i]是正整数i的最大乘积// 找关系:dp[i] =const int num = n;int dp[num + 1];fill(dp, dp + num + 1, 1);for(int i = 3; i <= num; i++){for(int j = 1; j < i; j++){dp[i] = max(dp[i], j * max(i - j, dp[i - j]));}}return dp[num];}};
