【动态规划】数组部分和相关问题
求数组的部分和,以及相关问题,最容易想到的是回溯算法,也就是深度优先搜索,这个算法的复杂度一向比较高,O(2^n),在online judge平台上往往和超时相伴。今天我的一个同学做自己跳动公司的笔试题,就遇到了这类题。
题目是:给定一个数组nums和一个目标值m,可以在数组里不重复地选择任意个数字,输出这些数字的和对m取余的最大值。
这道题出在4道笔试题里的第4题,一般来说会有以下几个特点:1.略难;2.时间不太够了;3.脑子有点昏。我同学知道回溯肯定超时,于是选择了放弃,但在放弃之前,他简单地返回了 m-1,获得了20%的分数,真是机智如我。但他笔试完后还是没有思路,觉得这是一道很有难度的题。我也没怎么见过类似的题,简单搜索之后,发现可以用0-1背包的思路做数组部分和的题。选中的就是1,没选中的就是0。话不多说,上代码:
// 求数组部分和为 k 的不同方案数
public int partSum(int[] nums, int k) {
int n = nums.length;
int[] dp = new int[k+1];
dp[0] = 1;
for (int i = 0; i < n; i++) {
for (int j = k; j >= nums[i]; j--) {
dp[j] += dp[j - nums[i]];
}
}
return dp[k];
}
// 求数组部分和对 m 取余的最大值
public int partSum2(int[] nums, int m) {
int n = nums.length;
boolean[] dp = new boolean[m];
dp[0] = true;
for (int i = 0; i < n; i++) {
for (int j = m-1; j >= 0; j--) {
int index = getIndex(j - nums[i], m);
dp[j] |= dp[index];
}
}
for (int j = m-1; j >= 0; j--) {
if (dp[j])
return j;
}
return 0;
}
private int getIndex(int k, int m) {
int res = k % m;
if (res < 0)
res += m;
return res;
}

浙公网安备 33010602011771号