给定一个非负的数组arr,和一个正数m,返回arr中所有子序列累加和对m求余数之后的最大值
1.如果arr中每个数字不大,怎么做这道题?
2.如果arr中m的值很小,怎么做这道题?
3.如果arr的长度很短,但是每个arr中数字比较大并且m比较大?
如何求解所有的子序列问题?
1.暴力解法复杂度O(2 ^ N)
2.背包解法(为什么能想到这个问题)复杂度O(N*SUM) N代表数组的长度,SUM代表数组累加和
子序列和背包问题的关系:
使用动态规划何求出数组arr所有的累加和
累加和数组不能太大;
dp[i][j]的含义:数组在arr[0…i]的之间的元素的累加和能否为j
状态转移方程:
dp[i][j] = dp[i-1][j] // 不选择第i个元素
| dp[i-1][j-arr[i]] //选择第i个元素
3.重新定义动态规划的状态:时间复杂度O(M*N) N代表数组的长度
dp[i][j] 代表的含义是:在数组arr[0…i]之间的元素是否存在累加和对m求余数的结果为j
4.二分解法,采用分治的思想;
暴力解法:
//第一种方式也就是暴力求解
//共有2^n次方中可能性;每个位置都有两种可能性,选择或者不选择
//时间复杂度过高
private int getSubsequenceMaxModMForce(int[] arr, int m) {
int res = 0;
Set<Integer> set = new HashSet<>();
processForce(arr, 0, 0, set);
for (Integer num : set) {
res = Math.max(res, num % m);
}
return res;
}
/**
* 参数说明
*
* @param arr 原数组
* @param cur 当前待处理的角标位置
* @param sum 累加和
* @param set 所有累加和的集合
*/
private void processForce(int[] arr, int cur, int sum, Set<Integer> set) {
if (cur == arr.length) {
set.add(sum);
return;
}
processForce(arr, cur + 1, sum, set);
processForce(arr, cur + 1, sum + arr[cur], set);