- 完全平方数(完全背包)
给你一个整数 n ,返回 和为 n 的完全平方数的最少数量 。
完全平方数 是一个整数,其值等于另一个整数的平方;换句话说,其值等于一个整数自乘的积。例如,1、4、9 和 16 都是完全平方数,而 3 和 11 不是。
示例 1:
输入:n = 12
输出:3
解释:12 = 4 + 4 + 4
public int numSquares(int n) {
int[] dp = new int[n + 1];
dp[0] = 0; // 初始化
for(int j = 1;j<=n;j++)
dp[j] = Integer.MAX_VALUE;
int m = (int)Math.sqrt(n);
for (int i = 1; i <= m; i++) // 枚举每个数
{
for (int j = i*i; j <= n; j++) // ⽤⼩于 i 的完全平⽅数划分区间
dp[j] = Math.min(dp[j], dp[j- i * i] + 1); // 拿到所有划分区间内的
}
// 返回结果
return dp[n];
}
- 零钱兑换(完全背包)
给你一个整数数组 coins ,表示不同面额的硬币;以及一个整数 amount ,表示总金额。
计算并返回可以凑成总金额所需的 最少的硬币个数 。如果没有任何一种硬币组合能组成总金额,返回 -1(题目给暗示了) 。
你可以认为每种硬币的数量是无限的。
示例 1:
输入:coins = [1, 2, 5], amount = 11
输出:3
解释:11 = 5 + 5 + 1
public int coinChange(int[] coins, int amount) {
int n = coins.length, INF = 0x3f3f3f3f;
int[] dp = new int[amount + 1];
for (int j = 1; j <= amount; j++)
dp[j] = INF;
for (int i = 1; i <= n; i++)
for (int j =coins[i - 1]; j <= amount; j++)
dp[j] = Math.min(dp[j], dp[j - coins[i - 1]] + 1);
return dp[amount] >= INF ? -1 : dp[amount];
}
- 分隔等和子集(01背包)
给你一个 只包含正整数 的 非空 数组 nums 。请你判断是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。
示例 1:
输入:nums = [1,5,11,5]
输出:true
解释:数组可以分割成 [1, 5, 5] 和 [11] 。
public boolean canPartition(int[] nums) {
int n = nums.length;
int sum = 0;
for (int x : nums)
sum += x;
if (sum % 2 == 1 || sum < 0)
return false;
int target = sum / 2;
boolean[] dp = new boolean[target + 1]; // 建表
dp[0] = true;
for (int i = 1; i <= n; i++) {
for (int j = target; j >= nums[i - 1]; j--) {
dp[j] = dp[j] || dp[j - nums[i - 1]];
}
}
return dp[target];
}
- 单词拆分
输入: s = "leetcode", wordDict = ["leet", "code"]
输出: true
解释: 返回 true 因为 "leetcode" 可以由 "leet" 和 "code" 拼接成。
public boolean wordBreak(String s, List<String> wordDict) {
int n = s.length();
boolean[]dp = new boolean[n+1];
dp[0] = true;
s = " "+s;
for(int i = 1;i<=n;i++){
for(int j = 0;j<i;j++){
if(dp[j]&&wordDict.contains(s.substring(j+1,i+1))){
dp[i] = true;
}
}
}
return dp[n];
}
- 乘积最大子数组
输入: nums = [2,3,-2,4]
输出: 6
解释: 子数组 [2,3] 有最大乘积 6。
public int maxProduct(int[] nums) {
int n = nums.length;
int[] f = new int[n + 1];
int[] g = new int[n + 1];
f[0] = g[0] = 1;
int ret = Integer.MIN_VALUE;
for (int i = 1; i <= n; i++) {
int x = nums[i - 1], y = f[i - 1] * nums[i - 1], z = g[i - 1] * nums[i - 1];
f[i] = Math.max(x, Math.max(y, z));
g[i] = Math.min(x, Math.min(y, z));
ret = Math.max(ret, f[i]);
}
return ret;
}
20.编辑距离
如果是增操作,即是word1要增加一个字符才跟word2一样, 说明word1的[0..i]跟word2的[0..j - 1]是一样的 , dp[i][j] = dp[i][j - 1] + 1 如果是删操作,也是word1要删除一个字符才跟word2一样,说明word1的[0..i - 1]跟word2的[0..j]是一样的, dp[i][j] = dp[i - 1][j] + 1 替换的话就也好理解 , 说明word1的[0..i - 1]跟word2的[0..j - 1]是一样的
增,dp[i][j] = dp[i][j - 1] + 1
删,dp[i][j] = dp[i - 1][j] + 1
改,dp[i][j] = dp[i - 1][j - 1] + 1
输入:word1 = "horse", word2 = "ros"
输出:3
解释:
horse -> rorse (将 'h' 替换为 'r')
rorse -> rose (删除 'r')
rose -> ros (删除 'e')
public int minDistance(String word1, String word2) {
int m = word1.length();
int n = word2.length();
int[][]dp = new int[m+1][n+1];
for(int i = 0;i<=m;i++)
dp[i][0] = i;
for(int j = 0;j<=n;j++)
dp[0][j] = j;
for(int i = 1;i<=m;i++){
for(int j = 1;j<=n;j++){
dp[i][j] = Math.min(dp[i-1][j],Math.min(dp[i-1][j-1],dp[i][j-1]))+1;
if(word1.charAt(i-1)==word2.charAt(j-1)){
dp[i][j] = Math.min(dp[i][j],dp[i-1][j-1]);
}
}
}
return dp[m][n];
}
- 最长有效括号