目录
1.背包问题
1.1 题目描述
有 n 个物品和一个大小为 m 的背包. 给定数组 A 表示每个物品的大小
和数组 V 表示每个物品的价值.问最多能装入背包的总价值是多大?
1.A[i], V[i], n, m 均为整数
2.你不能将物品进行切分
3.你所挑选的要装入背包的物品的总大小不能超过 m
4.每个物品只能取一次
5.m <= 1000
len(A),len(V)<=100
1.2 画图分析
- 第 i 个商品放入包中的价值
此时两个等式其实都可以由 F(i, j) = F(i - 1, j - a[i -1]) + v[i -1] 来代替
- 第 i 个商品的大小 > 包的大小
此时 F(i, j) = F(i - 1, j)
1.3 思路分析
状态 F(i, j):从前 i 个商品中选择,包的大小为 j 时的最大价值。(商品的索引从 1 开始,数组的索引从 0 开始)
状态转移方程:
- a[i - 1] > j F(i, j) = F(i - 1, j)
- a[i - 1] <= j F(i, j) = F(i - 1, j - a[i - 1]) + v[i - 1]
初始状态:F(i, 0) = F(0, j) = 0,由于每一个商品的价值都可能和前一行的某一列有关,为了防止数组越界,我们申请一个行,列比商品数、包都大一的二维数组 array[n + 1][m + 1].
返回结果:array[n][m].
结合具体示例理解:
1.4 代码示例
public class Solution {
public static int backPackII(int m, int[] a, int[] v) {
int number = a.length;
int[][] array = new int[number + 1][m + 1];
// 初始状态 array[0][j] = array[i][0] = 0
for(int i = 1; i < number + 1; i++) {
for(int j = 1; j < m + 1; j++) {
// 状态转移方程
if(a[i - 1] > j) {
array[i][j] = array[i - 1][j];
} else {
array[i][j] = Math.max(array[i -1][j], array[i - 1][j - a[i - 1]] + v[i - 1]);
}
}
}
// 返回结果
return array[number][m];
}
}
【优化】一维数组
上述代码可以优化为只用一个一维数组,循环还是两层,但是要注意的是:内层循环需要从后往前走,因为状态方程需要用未更新之前的值,如果从小到大更新的话,我们是先更新前面这些列的值,那么后面使用的就都是更新过的值了;但是对于二维数组,从前往后,从后往前都是可以的。
public class Solution {
public int backPackII(int m, int[] a, int[] v) {
int number = a.length;
// 省去行
int[] array = new int[m + 1];
for(int i = 1; i < number + 1; i++) {
// 注意从后往前更新
for(int j = m; j > 0; j--) {
if(a[i - 1] <= j) {
// 状态转移方程
array[j] = Math.max(array[j], array[j - a[i - 1]] + v[i - 1]);
}
}
}
return array[m];
}
}
2. 回文串分割
2.1 题目描述
给出一个字符串s,分割s使得分割出的每一个子串都是回文串
计算将字符串s分割成回文分割结果的最小切割数
例如:给定字符串s="aab",
返回1,因为回文分割结果["aa","b"]是切割一次生成的。
示例1:
输入:"aab"
返回值:1
2.2 思路分析
问题:s 的最小分割次数
状态 F(i) :s 的前 i 个字符最小的分割次数
状态转移方程:
- [1, i] 是回文串 array[i] = 0;
- [1, i] 不是回文串,且 i < j && [j + 1, i] 是回文串 min(F(i), F(j) + 1);
初始状态:F(i) = i - 1 ,i 从 1 开始
返回结果:F(s.length())
结合具体实例理解 min(F(i), F(j) + 1) :
2.3 代码示例
public class Solution {
public boolean isPal(String s) {
int left = 0;
int right = s.length() - 1;
while(left < right) {
if(s.charAt(left) != s.charAt(right)) {
return false;
}
left++;
right--;
}
return true;
}
public int minCut (String s) {
if(s.length() == 0 || s.length() == 1) {
return 0;
}
int[] array = new int[s.length() + 1];
// 初始状态
for(int i = 1; i < array.length; i++) {
array[i] = i - 1;
}
for(int i = 2; i < array.length; i++) {
// 判断整体是否为回文串
if(isPal(s.substring(0,i))) {
array[i] = 0;
} else {
for(int j = 1; j < i; j++) {
// j < i && [j + 1, i] 是否为回文串
if(isPal(s.substring(j, i))) {
// 状态转移方程
array[i] = Math.min(array[i], array[j] + 1);
}
}
}
}
return array[s.length()];
}
}
本文含有隐藏内容,请 开通VIP 后查看