无串线性问题
只有两个键的键盘
https://leetcode-cn.com/problems/2-keys-keyboard/
int minSteps(int n){int* dp = (int *)malloc(sizeof(int) * (n + 1));dp[1] = 0;for(int i = 2; i < n + 1; i++){dp[i] = INT_MAX;for(int j = 1; j * j <= i; j++){if(i % j == 0){//顺序不能颠倒,否则超出INT_MAX// j个复制i/j次dp[i] = fmin(dp[i], dp[j] + i / j);// i/j个复制j次dp[i] = fmin(dp[i], dp[i / j] + j);}}}return dp[n];}
完全平方数
https://leetcode-cn.com/problems/perfect-squares/
int numSquares(int n){int dp[n + 1];dp[0] = 0;for(int i = 1; i < n + 1; i++){int min = 10001;for(int j = 1; j * j <= i; j++){min = fmin(min, dp[i - j * j] + 1);}dp[i] = min;}return dp[n];}
单串问题
单串 LIS 系列
最长递增子序列
https://leetcode-cn.com/problems/longest-increasing-subsequence/
int lengthOfLIS(int* nums, int numsSize){int* dp = (int *)malloc(numsSize * sizeof(int));//dp[i]表示以dp[i]结尾的最长递增子序列dp[0] = 1;int max = 1;for(int i = 1; i < numsSize; i++){dp[i] = 1;for(int j = 0; j < i; j++){if(nums[j] < nums[i]){dp[i] = (dp[i] > dp[j] + 1) ? dp[i] : dp[j] + 1;}}max = max > dp[i] ? max : dp[i];}return max;}
class Solution {public int lengthOfLIS(int[] nums) {int[] dp = new int[nums.length];int max = 1;dp[0] = 1;for (int i = 1; i < nums.length; i++){dp[i] = 1;for (int j = 0; j < i; j++){if(nums[j] < nums[i]){dp[i] = Math.max(dp[j] + 1, dp[i]);}}max = Math.max(max, dp[i]);}return max;}}
最长递增子序列的个数
https://leetcode-cn.com/problems/number-of-longest-increasing-subsequence/
int findNumberOfLIS(int* nums, int numsSize){
int* dp = (int *)malloc(numsSize * sizeof(int));
int* count = (int *)malloc(numsSize * sizeof(int));
//count[i] 为 dp[i] 对应的最长递增子序列个数
dp[0] = count[0] = 1;
int max = 1;
for(int i = 1; i < numsSize; i++){
dp[i] = count[i] = 1;
for(int j = 0; j < i; j++){
if(nums[i] > nums[j]){
if(dp[i] == dp[j] + 1)
count[i] += count[j];
else if(dp[i] < dp[j] + 1){
dp[i] = dp[j] + 1;
count[i] = count[j];
}
}
}
if(dp[i] > max)
max = dp[i];
}
int result = 0;
for(int i = 0; i < numsSize; i++){
if(dp[i] == max)
result += count[i];
}
return result;
}
class Solution {
public int findNumberOfLIS(int[] nums) {
int[] dp = new int[nums.length];
//count[i] 为到 nums[i] 为止的最长递增子序列个数
int[] count = new int[nums.length];
Arrays.fill(dp, 1);
Arrays.fill(count, 1);
int max = 0;
for(int i = 0; i < nums.length; i++){
for(int j = 0; j < i; j++){
if(nums[j] < nums[i]){
if(dp[j] + 1 > dp[i]){
dp[i] = dp[j] + 1;
count[i] = count[j];
}
else if(dp[j] + 1 == dp[i]){
count[i] = count[i] + count[j];
}
}
}
max = Math.max(dp[i], max);
}
int ans = 0;
for(int i = 0; i < nums.length; i++){
if(dp[i] == max)
ans += count[i];
}
return ans;
}
}
俄罗斯套娃信封问题
https://leetcode-cn.com/problems/russian-doll-envelopes/
int compare(const void * a, const void * b);
int maxEnvelopes(int** envelopes, int envelopesSize, int* envelopesColSize){
qsort(envelopes, envelopesSize, sizeof(int *), compare);
int* dp = (int *)malloc(envelopesSize * sizeof(int));
dp[0] = 1;
int max = 1;
for(int i = 1; i < envelopesSize; i++){
dp[i] = 1;
for(int j = 0; j < i; j++){
if(**(envelopes + j) < **(envelopes + i) && *(*(envelopes + j) + 1) < *(*(envelopes + i) + 1)){
dp[i] = (dp[i] > dp[j] + 1) ? dp[i] : dp[j] + 1;
}
}
max = (dp[i] > max) ? dp[i] : max;
}
return max;
}
int compare(const void * a, const void * b){
const int ** m = (const int **)a;
const int ** n = (const int **)b;
if(**m < **n)
return -1;
else if(**m == **n){
if(*(*m + 1) < *(*n + 1))
return 1;
else return -1;
}
else return 1;
}
class Solution {
public int maxEnvelopes(int[][] envelopes) {
int n = envelopes.length;
if(n == 0)
return 0;
Arrays.sort(envelopes, new Comparator<int[]>(){
public int compare(int[] a, int[] b){
if(a[0] != b[0])
return a[0] - b[0];
else return b[1] - a[1];
}
});
int dp[] = new int[n];
Arrays.fill(dp, 1);
int max = 0;
for(int i = 0; i < n; i++){
for(int j = 0; j < i; j++){
if(envelopes[i][1] > envelopes[j][1])
dp[i] = Math.max(dp[i], dp[j] + 1);
}
max = Math.max(max, dp[i]);
}
return max;
}
}
最大子数组和系列
最大子序和
https://leetcode-cn.com/problems/maximum-subarray/
int maxSubArray(int* nums, int numsSize){
int* dp = (int *)malloc(sizeof(int) * numsSize);
//dp[i]表示以dp[i]结尾的最大子序和
dp[0] = nums[0];
int max = dp[0];
for(int i = 1; i < numsSize; i++){
if(dp[i - 1] < 0)
dp[i] = nums[i];
else
dp[i] = dp[i - 1] + nums[i];
max = (dp[i] > max) ? dp[i] : max;
}
return max;
}
class Solution {
public int maxSubArray(int[] nums) {
int n = nums.length;
if(n == 1)
return nums[0];
int[] dp = new int[n];
dp[0] = nums[0];
int max = dp[0];
for(int i = 1; i < n; i++){
if(dp[i - 1] < 0)
dp[i] = nums[i];
else dp[i] = dp[i - 1] + nums[i];
max = Math.max(max, dp[i]);
}
return max;
}
}
乘积最大子数组
https://leetcode-cn.com/problems/maximum-product-subarray/
int maxProduct(int* nums, int numsSize){
int* max = (int *)malloc(sizeof(int) * numsSize);
int* min = (int *)malloc(sizeof(int) * numsSize);
int result, temp;
result = max[0] = min[0] = nums[0];
for(int i = 1; i < numsSize; i++){
int a = nums[i];
int b = nums[i] * max[i - 1];
int c = nums[i] * min[i - 1];
if(a > b){
temp = a;
a = b;
b = temp;
}
if(b > c){
temp = b;
b = c;
c = temp;
}
if(a > b){
temp = a;
a = b;
b = temp;
}
max[i] = c;
min[i] = a;
result = (max[i] > result) ? max[i] : result;
}
return result;
}
class Solution {
public int maxProduct(int[] nums) {
int n = nums.length;
int min = nums[0];
int max = nums[0];
int ans = max;
for(int i = 1; i < nums.length; i++){
int temp = max; //由于下面要对max进行修改,需要暂存
max = Math.max(max * nums[i], Math.max(min * nums[i], nums[i]));
min = Math.min(temp * nums[i], Math.min(min * nums[i], nums[i]));
ans = Math.max(ans, max);
}
return ans;
}
}
打家劫舍系列
打家劫舍
https://leetcode-cn.com/problems/house-robber/
int rob(int* nums, int numsSize){
int* dp = (int *)malloc(sizeof(int) * numsSize);
dp[0] = nums[0];
int max = dp[0];
for(int i = 1; i < numsSize; i++){
if(i == 1){
dp[1] = nums[1] > dp[0] ? nums[1] : dp[0];
}
else if(i == 2){
dp[2] = nums[2] + dp[0] > dp[1] ? nums[2] + dp[0] : dp[1];
}
else{
dp[i] = nums[i] + dp[i - 2] > dp[i - 1] ? nums[i] + dp[i - 2] : dp[i - 1];
}
max = max > dp[i] ? max : dp[i];
}
return max;
}
class Solution {
public int rob(int[] nums) {
int n = nums.length;
if (n == 0)
return 0;
int[] dp = new int[nums.length];
dp[0] = nums[0];
int max = dp[0];
for (int i = 1; i < n; i++){
if(i >= 2){
dp[i] = nums[i] + dp[i - 2];
if(i >= 3){
dp[i] = nums[i] + Math.max(dp[i - 2], dp[i - 3]);
}
}
else dp[i] = nums[i];
max = Math.max(max, dp[i]);
}
return max;
}
}
打家劫舍 II
https://leetcode-cn.com/problems/house-robber-ii/
int rob(int* nums, int numsSize){
if(numsSize == 1)
return nums[0];
int* dp = (int *)malloc(sizeof(int) * numsSize);
dp[0] = nums[0];
int max = dp[0];
//0 ~ numsSize-2
for(int i = 1; i < numsSize - 1; i++){
if(i > 2){
dp[i] = nums[i] + dp[i - 2] > dp[i - 1] ? nums[i] + dp[i - 2] : dp[i - 1];
}
else if(i == 1){
dp[1] = nums[1] > dp[0] ? nums[1] : dp[0];
}
else if(i == 2){
dp[2] = nums[0] + nums[2] > nums[1] ? nums[0] + nums[2] : nums[1];
}
max = dp[i] > max ? dp[i] : max;
}
//1 ~ numsSize-1
dp[0] = nums[1];
max = dp[0] > max ? dp[0] : max;
for(int i = 1; i < numsSize - 1; i++){
if(i > 2){
dp[i] = nums[i + 1] + dp[i - 2] > dp[i - 1] ? nums[i + 1] + dp[i - 2] : dp[i - 1];
}
else if(i == 1){
dp[1] = nums[2] > dp[0] ? nums[2] : dp[0];
}
else if(i == 2){
dp[2] = nums[1] + nums[3] > nums[2] ? nums[1] + nums[3] : nums[2];
}
max = dp[i] > max ? dp[i] : max;
}
return max;
}
class Solution {
public int rob(int[] nums) {
int n = nums.length;
int[] dp = new int[nums.length];
dp[0] = nums[0];
int max = dp[0];
for (int i = 1; i < n - 1; i++){
if(i >= 3){
dp[i] = nums[i] + Math.max(dp[i - 2], dp[i - 3]);
}
else if(i >= 2){
dp[i] = nums[i] + dp[i - 2];
}
else dp[i] = nums[i];
max = Math.max(max, dp[i]);
}
if(n > 1){
max = Math.max(max, nums[1]);
for (int i = 2; i < n; i++){
if(i >= 4){
dp[i] = nums[i] + Math.max(dp[i - 2], dp[i - 3]);
}
else if(i >= 3){
dp[i] = nums[i] + dp[i - 2];
}
else dp[i] = nums[i];
max = Math.max(max, dp[i]);
}
}
return max;
}
}
双串问题
双串 LCS 系列
最长公共子序列
https://leetcode-cn.com/problems/longest-common-subsequence/
int longestCommonSubsequence(char * text1, char * text2){
int a = strlen(text1);
int b = strlen(text2);
int dp[a + 1][b + 1];
//从一个字符串为空开始考虑
for(int i = 0; i < a + 1; i++){
for(int j = 0; j < b + 1; j++){
if(i == 0 || j == 0)
dp[i][j] = 0;
else if(text1[i - 1] == text2[j - 1]){
dp[i][j] = dp[i - 1][j - 1] + 1;
}
else{
dp[i][j] = dp[i - 1][j] > dp[i][j - 1] ? dp[i - 1][j] : dp[i][j - 1];
}
}
}
return dp[a][b];
}
class Solution {
public int longestCommonSubsequence(String text1, String text2) {
int m = text1.length();
int n = text2.length();
int[][] dp = new int[m + 1][n + 1];
for(int i = 1; i < m + 1; i++){
char a = text1.charAt(i - 1);
for(int j = 1; j < n + 1; j++){
if(a == text2.charAt(j - 1))
dp[i][j] = dp[i - 1][j - 1] + 1;
else
dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);
}
}
return dp[m][n];
}
}
两个字符串的最小ASCII删除和
https://leetcode-cn.com/problems/minimum-ascii-delete-sum-for-two-strings/
int minimumDeleteSum(char * s1, char * s2){
int a = strlen(s1);
int b = strlen(s2);
int dp[a + 1][b + 1];
dp[0][0] = 0;
for(int i = 1; i < a + 1; i++)
dp[i][0] = dp[i - 1][0] + s1[i - 1];
for(int i = 1; i < b + 1; i++)
dp[0][i] = dp[0][i - 1] + s2[i - 1];
for(int i = 1; i < a + 1; i++){
for(int j = 1; j < b + 1; j++){
if(s1[i - 1] == s2[j - 1])
dp[i][j] = dp[i - 1][j - 1];
else
dp[i][j] = dp[i - 1][j] + s1[i - 1] < dp[i][j - 1] + s2[j - 1] ? dp[i - 1][j] + s1[i - 1] : dp[i][j - 1] + s2[j - 1];
}
}
return dp[a][b];
}
class Solution {
public int minimumDeleteSum(String s1, String s2) {
int m = s1.length();
int n = s2.length();
int[][] dp = new int[m + 1][n + 1];
dp[0][0] = 0;
for(int i = 1; i < m + 1; i++)
dp[i][0] = s1.charAt(i - 1) + dp[i - 1][0];
for(int j = 1; j < n + 1; j++)
dp[0][j] = s2.charAt(j - 1) + dp[0][j - 1];
for(int i = 1; i < m + 1; i++){
for(int j = 1; j < n + 1; j++){
if(s1.charAt(i - 1) == s2.charAt(j - 1))
dp[i][j] = dp[i - 1][j - 1];
else
dp[i][j] = Math.min(dp[i - 1][j] + s1.charAt(i - 1), dp[i][j - 1] + s2.charAt(j - 1));
}
}
return dp[m][n];
}
}
最长重复子数组
https://leetcode-cn.com/problems/maximum-length-of-repeated-subarray/
int findLength(int* nums1, int nums1Size, int* nums2, int nums2Size){
int dp[nums1Size + 1][nums2Size + 1];
int max = 0;
for(int i = 1; i < nums1Size + 1; i++){
for(int j = 0; j < nums2Size + 1; j++){
if(i == 0 || j == 0)
dp[i][j] = 0;
else if(nums1[i - 1] == nums2[j - 1])
dp[i][j] = dp[i - 1][j - 1] + 1;
else
dp[i][j] = 0;
max = max > dp[i][j] ? max : dp[i][j];
}
}
return max;
}
class Solution {
public int findLength(int[] A, int[] B) {
int m = A.length;
int n = B.length;
int[][] dp = new int[m + 1][n + 1];
int max = 0;
for(int i = 1; i < m + 1; i++){
for(int j = 1; j < n + 1; j++){
if(A[i - 1] == B[j - 1])
dp[i][j] = dp[i - 1][j - 1] + 1;
max = Math.max(max, dp[i][j]);
}
}
return max;
}
}
字符串匹配系列
编辑距离
https://leetcode-cn.com/problems/edit-distance/
int minDistance(char * word1, char * word2){
int a = strlen(word1);
int b = strlen(word2);
int dp[a + 1][b + 1];
dp[0][0] = 0;
for(int i = 1; i < a + 1; i++)
dp[i][0] = dp[i - 1][0] + 1;
for(int i = 1; i < b + 1; i++)
dp[0][i] = dp[0][i - 1] + 1;
for(int i = 1; i < a + 1; i++){
for(int j = 1; j < b + 1; j++){
if(word1[i - 1] != word2[j - 1]){
//增删
dp[i][j] = dp[i - 1][j] < dp[i][j - 1] ? dp[i - 1][j] + 1 : dp[i][j - 1] + 1;
//改
dp[i][j] = dp[i][j] < dp[i - 1][j - 1] + 1 ? dp[i][j] : dp[i - 1][j - 1] + 1;
}
else
dp[i][j] = dp[i - 1][j - 1];
}
}
return dp[a][b];
}
背包问题
一和零(二维0-1背包)
https://leetcode-cn.com/problems/ones-and-zeroes/
int findMaxForm(char ** strs, int strsSize, int m, int n){
int dp[strsSize + 1][m + 1][n + 1];
memset(dp, 0, sizeof(dp));
int zero, one;
for(int i = 1; i < strsSize + 1; i++){
zero = countZero(strs[i - 1]);
one = strlen(strs[i - 1]) - zero;
//注意循环从0开始,可以只包含一种物品
for(int j = 0; j < m + 1; j++){
for(int k = 0; k < n + 1; k++){
//拿
if(j - zero >= 0 && k - one >= 0)
dp[i][j][k] = dp[i - 1][j - zero][k - one] + 1;
//不拿
dp[i][j][k] = dp[i][j][k] > dp[i - 1][j][k] ? dp[i][j][k] : dp[i - 1][j][k];
}
}
}
return dp[strsSize][m][n];
}
int countZero(char * strs){
int count = 0;
for(int i = strlen(strs) - 1; i >= 0; i--){
if(strs[i] == '0')
count++;
}
return count;
}
最后一块石头的重量 II
https://leetcode-cn.com/problems/last-stone-weight-ii/
//要使最后一块石头的重量尽可能地小,需要在不超过 sum/2 的前提下尽可能地大。可以看作是背包容量为 sum/2 ,物品重量和价值均为 stones[i],其中 dp[i+1][j] 表示前 i 个石头能否凑出重量 j
int lastStoneWeightII(int* stones, int stonesSize){
int sum = 0;
for(int i = 0; i < stonesSize; i++)
sum += stones[i];
int weight = sum / 2;
int dp[stonesSize + 1][weight + 1];
memset(dp, 0, sizeof(dp));
dp[0][0] = 1;
for(int i = 1; i < stonesSize + 1; i++){
for(int j = 0; j < weight + 1; j++){ //当j = 0时,j < stones[i - 1],不用提前初始化
if(j < stones[i - 1])
dp[i][j] = dp[i - 1][j];
else
dp[i][j] = dp[i - 1][j] || dp[i - 1][j - stones[i - 1]];
}
}
int max;
for(int j = 0; j < weight + 1; j++){
if(dp[stonesSize][j] == 1)
max = j;
}
return sum - 2 * max;
}
分割等和子集(0-1背包、必须放满)
https://leetcode-cn.com/problems/partition-equal-subset-sum/
bool canPartition(int* nums, int numsSize){
int sum = 0;
for(int i = 0; i < numsSize; i++)
sum += nums[i];
int m = sum % 2;
if(m != 0)
return false;
else{
int dp[numsSize + 1][sum / 2 + 1];
memset(dp, 0, sizeof(dp));
dp[0][0] = 1;
for(int i = 1; i < numsSize + 1; i++){
for(int j = 0; j < sum / 2 + 1; j++){
if(j < nums[i - 1])
dp[i][j] = dp[i - 1][j];
else
dp[i][j] = dp[i - 1][j] || dp[i - 1][j - nums[i - 1]];
}
}
return dp[numsSize][sum / 2];
}
}
零钱兑换(完全背包、必须放满)
https://leetcode-cn.com/problems/coin-change/
int coinChange(int* coins, int coinsSize, int amount){
int dp[coinsSize + 1][amount + 1];
for(int j = 1; j < amount + 1; j++)
dp[0][j] = 10001;
dp[0][0] = 0;
for(int i = 1; i < coinsSize + 1; i++){
for(int j = 0; j < amount + 1; j++){
dp[i][j] = dp[i - 1][j];
if(j - coins[i - 1] >= 0 && dp[i][j] > dp[i][j - coins[i - 1]] + 1)
dp[i][j] = dp[i][j - coins[i - 1]] + 1;
}
}
if(dp[coinsSize][amount] == 10001)
return -1;
else
return dp[coinsSize][amount];
}
//优化为一维dp
int coinChange(int* coins, int coinsSize, int amount){
int dp[amount + 1];
dp[0] = 0;
//初始化为原二维数组第一行
for(int j = 1; j < amount + 1; j++)
dp[j] = 10001;
//循环不变,当前元素之前已修改为第i行,后为第i-1行
for(int i = 1; i < coinsSize + 1; i++){
for(int j = 1; j < amount + 1; j++){
if(j - coins[i - 1] >= 0 && dp[j - coins[i - 1]] + 1 < dp[j])
dp[j] = dp[j - coins[i - 1]] + 1;
}
}
if(dp[amount] == 10001)
return -1;
else
return dp[amount];
}
零钱兑换 II(完全背包、必须放满)
https://leetcode-cn.com/problems/coin-change-2/
int change(int amount, int* coins, int coinsSize){
int dp[coinsSize + 1][amount + 1];
memset(dp, 0, sizeof(dp));
dp[0][0] = 1;
for(int i = 1; i < coinsSize + 1; i++){
for(int j = 0; j < amount + 1; j++){
dp[i][j] = dp[i - 1][j];
if(j - coins[i - 1] >= 0)
dp[i][j] += dp[i][j - coins[i - 1]];
}
}
return dp[coinsSize][amount];
}
组合问题(求方案数)
组合总和 Ⅳ
https://leetcode-cn.com/problems/combination-sum-iv/solution/
