给定一个非负的数组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);}

第一种动态规划

 /*** 动态规划一,适用于arr数组中每个元素都不大的* <p>* boolean dp[i][j]:表达的含义是在数组范围arr[0...i]是否能够累加和为j*/private int getSubsequenceMaxModMDpSum(int[] arr, int m) {int sum = 0;for (int num : arr) {sum += num;}boolean[][] dp = new boolean[arr.length][sum + 1];// base case// 第0行元素 第0个元素是 dp[0][0] = true dp[0][arr[0]] = true// 第0列元素 都是true,这是因为这一列存在一种什么元素都不选的情况dp[0][arr[0]] = true;for (int i = 0; i < arr.length; i++) {dp[i][0] = true;}//状态转移方程 选择或者选择for (int i = 1; i < arr.length; i++) {for (int j = 1; j <= sum; j++) {dp[i][j] = dp[i - 1][j];if (j >= arr[i]) {dp[i][j] = dp[i][j] || dp[i - 1][j - arr[i]];}}}int res = 0;for (int i = 0; i <= sum; i++) {if (!dp[arr.length - 1][i]) continue;res = Math.max(res, i % m);}return res;}

第二种动态规划的方式

/*** 动态规划的第二种方式* boolean[] dp[i][j]:表达的这种含义是在数组arr[0...j]的范围内,是否存在累加和的余数为j*/private int getSubsequenceMaxModMDpM(int[] arr, int m) {boolean[][] dp = new boolean[arr.length][m];//base case//当第0行元素的时候,只有dp[0][arr[0] % m] = true;//当第0列的时候,只有有一个为0也都为truedp[0][arr[0] % m] = true;for (int i = 0; i < arr.length; i++) {dp[i][0] = true;}//状态转移方程为for (int i = 1; i < arr.length; i++) {for (int j = 1; j < m; j++) {//不选择dp[i][j] = dp[i - 1][j];//选择int cur = arr[i] % m;if (j >= cur) {dp[i][j] = dp[i][j] || dp[i - 1][j - cur];} else {dp[i][j] = dp[i][j] || dp[i - 1][j - cur + m];}}}for (int i = m - 1; i >= 0; i--) {if (dp[arr.length - 1][i]) return i;}return 0;}

第三种分治的思想:

 /*** 分治算法,使用数组的长度不大的情况下*/private int getSubsequenceMaxModMDivide(int[] arr,int m){if(arr.length == 1){return arr[0] % m;}int mid = (arr.length - 1) / 2;TreeSet<Integer> sort1 = new TreeSet<>();processDivide(arr,0,0,m,sort1,mid + 1);TreeSet<Integer> sort2 = new TreeSet<>();processDivide(arr,mid + 1,0,m,sort2,arr.length);int res = 0;for(int left : sort1){res = Math.max(res,left + sort2.floor(m - left - 1));}return res;}private void processDivide(int[] arr,int cur,int sum,int m,Set<Integer> set,int end){if(cur == end){set.add(sum % m);return;}processDivide(arr,cur + 1,sum,m,set,end);processDivide(arr,cur + 1,sum + arr[cur],m,set,end);}

数组子序列累加和求余数之后的最大值问题详解相关推荐

  1. 307. Range Sum Query - Mutable | 307. 区域和检索 - 数组可修改(数据结构:线段树,图文详解)

    题目 https://leetcode.com/problems/range-sum-query-mutable/ 吐槽官方题解 这题的 英文版官方题解,配图和代码不一致,而且描述不清:力扣国内版题解 ...

  2. C语言求最大公约数三种方法详解

    C语言求最大公约数三种方法详解 题目要求 常用写法(穷举法) 辗转相减法 辗转相除法 main函数 整体代码 题目要求 运行最大公约数的常用算法,并进行程序的调式与测试. 常用写法(穷举法) 从两个数 ...

  3. 数字三角形,最长上升子序列,背包模型 AcWing算法提高课 (详解)

    目录 数字三角形模型(只能向右和向下或向左和向上) AcWing 1015. 摘花生 AcWing 1018. 最低通行费(曼哈顿距离-向右和向下-求最小值-初始化) AcWing 1027. 方格取 ...

  4. java数组是行优先还是列优先的语言_详解C语言数组中是以列优先吗

    如果我们按照C语言的方式存储它,也就是行优先存储的话,那么在内存中,它的形状是这样的: 这种存储方式又被称作C contiguous array. C语言数组结构列优先顺序存储的实现 (GCC编译). ...

  5. c语言定义不定长数组初始化_大学C语言期末考试练习题(带详解答案)(1)

    链接:https://pan.baidu.com/s/1d2Bb1vNTyBNpFGneIAicVw 提取码:y7uw 单项选择题 C语言的基本单位是 函数 1.(A  )是构成C语言程序的基本单位. ...

  6. C语言结构体的定义与使用、结构体数组、指向结构体的指针(有代码详解)

    1.结构体的定义与使用 结构体是一种构造数据类型 把不同类型的数据组合成一个整体 结构体的定义形式: struct 结构体名{结构体所包含的变量或数组 }; 结构体是一种集合,它里面包含了多个变量或数 ...

  7. C语言【求最大公约数、最小公倍数】详解

    题目:从键盘输入两个数字,并求出他们的最大公约数. 解题思路: 一. 当我们看到题目时,首先思考求什么是最大公约数,什么 是最小公倍数. 最大公约数:指两个或两个以上共有的约数中最大的那个.最小公倍数 ...

  8. php 对象转数组_PHP的垃圾回收机制-PHP高级面试题+详解

    八重樱:面试10家公司,收获9个offer,2020年PHP 面试问题​zhuanlan.zhihu.com ps:本篇内容包括精选面试题与知识篇. PHP面试题关于PHP的垃圾回收机制,PHP的垃圾 ...

  9. 《C语言杂记》C语言字符数组与字符指针(指向字符串的指针)详解

    C语言中没有特定的字符串类型,我们通常是将字符串放在一个字符数组中,字符数组用法很简单我们还是来你看个例子吧. #include <stdio.h> #include <string ...

最新文章

  1. 程序猿职业规划,未来该何去何从
  2. 备份软件 FreeFileSync 怎么用
  3. LA3027简单带权并查集
  4. vue按钮字体大小设置_vue-elementui之按钮
  5. 学习:ups电池放电时间是怎么计算的?
  6. 三极管和MOS管有什么不一样?用MOS管还是三极管?
  7. python合并csv文件_Python学习——pandas 合并csv文件
  8. AI应用开发基础傻瓜书系列目录
  9. mysql创建表的时候日期给个默认值_mysql 创建表时 日期字段默认值为当前时间...
  10. java aio socket_[Java]socket Aio demo
  11. @@Autowired依赖注入先后顺序
  12. java ipmi关闭服务器,Dell服务器的IPMI/iKVM使用方法(开机,关机,重启,重装系统)...
  13. BP(BackPropagation)神经网络算法详解
  14. word中插入题注 表1 图1
  15. WindowsXPSP2 DEP技术揭秘
  16. ubuntu Pathon 目录
  17. Using 1.7 requires compiling with Android 4.4 (KitKat); currently using API 10
  18. 哪个牌子的蓝牙耳机音质好?音质比较好的蓝牙耳机排名
  19. 小白有这六个Python学习网站,比那些收费几百几千的还要好用
  20. Fiddler 抓包夜神模拟器图文详解

热门文章

  1. S5PV210_流水灯
  2. 强大的Java前台后台开发工具
  3. 主机远程虚拟机linux,如何使用SSH来远程连接Linux虚拟主机?
  4. 模块“CHUSBDLL.DLL.dll“可能与您正在运行的Windows版本不兼容。检查该模块是否与regsvr32.exe的x86或x64版本兼容 【已解决】
  5. 杰理之4.0工具固件升级【篇】
  6. 十五、机器学习中的决策树和随机森林算法
  7. 关于移动互联网的新要求
  8. (个人杂记)第八章 按键输入实验
  9. 斑马条码打印机的手动设置方法
  10. 毛玻璃之前世今生之filter与backdrop-filter