1、递归实现(参考:https://blog.csdn.net/hit_lk/article/details/53967627)

  1. public class Test {
  2.  
  3. @org.junit.Test
  4. public void test() {
  5. System.out.println("方案数:" + getAllSchemeNum(new int[]{ 5, 5, 5, 2, 3 }, 15));
  6. } // out : 方案数:4
  7.  
  8. /**
  9. * 从数组中选择和为sum的任意个数的组合数
  10. */
  11. public static int getAllSchemeNum(int[] arr, int sum) {
  12. int count = 0;
  13. // 将 选择一个数的组合数、选择两个数的组合数、...选择n个数的组合数 相加
  14. for (int numToSelect = 1; numToSelect <= arr.length; numToSelect++) {
  15. count += getSchemeNumByNumToSelect(arr, numToSelect, sum, 0);
  16. }
  17. return count;
  18. }
  19.  
  20. /**
  21. * 求【从数组的[arr[index], arr[length-1]]片段中获取和为sumToSelect的numToSelect个数】的方案数
  22. * @param arr 数组
  23. * @param numToSelect 还需要选择的数的个数
  24. * @param sumToSelect 还需要选择数之和
  25. * @param index 可选的范围的左边界
  26. * @return
  27. */
  28. public static int getSchemeNumByNumToSelect(int[] arr, int numToSelect, int sumToSelect, int index) {
  29. int count = 0;
  30. // 递归出口,如果数全部选择完成,则只需判定sumToSelect是否为零,如果为零,符合条件,返回1,否则返回0
  31. if (numToSelect == 0) {
  32. return sumToSelect == 0 ? 1 : 0;
  33. }
  34. /*
  35. * 将问题按选择的第一个数的不同做分解,第一个数可选的范围为[index, arr.length - numToSelect],
  36. * 所以就分解成了(arr.length - numToSelect - index + 1)个子问题。可为什么可选下标的右边界是
  37. * (arr.length - numToSelect)呢?是因为如果第一个数的下标是(arr.length - numToSelect + 1),
  38. * 那么后面只剩(numToSelect - 2)个位置,是不够放下剩余的(numToSelect - 1)个值的。
  39. */
  40. for (int i = index; i <= arr.length - numToSelect; i++) {
  41. if (arr[i] <= sumToSelect) {
  42. /*
  43. * 选择了第一个数arr[i],还需要在剩余数组片段中选择和为(sumToSelect-arr[i])
  44. * 的(numToSelect-1)个数。
  45. * >> 需要递归
  46. */
  47. count += getSchemeNumByNumToSelect(arr, numToSelect - 1, sumToSelect - arr[i], i + 1);
  48. }
  49. }
  50. return count;
  51. }
  52. }

2、动态规划dp[][]

  1. @Test
  2. public void test1() {
  3. // 指定输入 >>
  4. int[] arr = { 5, 5, 10, 2, 3 };
  5. int sum = 15;
  6. // ================================================
  7.  
  8. // 初始化dp二维数组 【dp[i][j]表示用前i个数组成和为j的方案个数】
  9. int rows = arr.length + 1;
  10. int cols = sum + 1;
  11. int[][] dp = new int[rows][cols];
  12. // 初始化dp的第一列,用前i个数组成和为0的方案都只有1种,就是什么都不取;
  13. for (int i = 0; i < rows; i++) {
  14. dp[i][0] = 1;
  15. }
  16. // 初始化dp的第一行,用0个元素不能组成1~sum
  17. for (int j = 1; j <= sum; j++) {
  18. dp[0][j] = 0;
  19. }
  20.  
  21. System.out.println("-- 处理前dp:");
  22. for (int i = 0; i < rows; i++) {
  23. System.out.println((i > 0 ? arr[i - 1] : "附加0") + "\t" + Arrays.toString(dp[i]));
  24. }
  25. System.out.println();
  26.  
  27. // 一行行的计算dp中每个元素的值
  28. //System.out.println("附加0 \t"+Arrays.toString(dp[0]));
  29. for (int i = 1; i < rows; i++) {
  30. for (int j = 1; j <= sum; j++) {
  31. /*
  32. * 用前i个数来组成和为j的组合,所有成功的组合可分下面两种情况:
  33. * 1、 组合中不包含第i个数 ,即只用前i-1个数来组成和为j的组合。
  34. * 2、组合中包含第i个数,这要求第i个数不能比和大(前i-1个数要组成和为:j-第i个数)。
  35. */
  36. dp[i][j] = dp[i - 1][j];
  37. if (arr[i-1] <= j) { // 第i个数为arr[i-1]
  38. dp[i][j] += dp[i - 1][j - arr[i-1]];
  39. }
  40. }
  41. //System.out.println(arr[i-1]+"\t"+Arrays.toString(dp[i]));
  42. }
  43.  
  44. System.out.println("-- 处理后dp:");
  45. for (int i = 0; i < rows; i++) {
  46. System.out.println((i > 0 ? arr[i - 1] : "附加0") + "\t" + Arrays.toString(dp[i]));
  47. }
  48. System.out.println("答案:" + dp[rows-1][sum]);
  49. }
  50. /* out:
  51. -- 处理前dp:
  52. 附加0 [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
  53. 5 [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
  54. 5 [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
  55. 10 [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
  56. 2 [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
  57. 3 [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
  58.  
  59. -- 处理后dp:
  60. 附加0 [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
  61. 5 [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
  62. 5 [1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0]
  63. 10 [1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 2]
  64. 2 [1, 0, 1, 0, 0, 2, 0, 2, 0, 0, 2, 0, 2, 0, 0, 2]
  65. 3 [1, 0, 1, 1, 0, 3, 0, 2, 2, 0, 4, 0, 2, 2, 0, 4]
  66. 答案:4
  67. */

【算法习题】正整数数组中和为sum的任意个数的组合数的更多相关文章

  1. 【算法习题】数组中任意2个(3个)数的和为sum的组合

    题1.给定一个int数组,一个数sum,求数组中和为sum的任意2个数的组合 @Test public void test_find2() { int[] arr = { -1, 0, 2, 3, 4 ...

  2. (回溯法)数组中和为S的N个数

    Given a list of numbers, find the number of tuples of size N that add to S. for example in the list ...

  3. Two sum(给定一个无重复数组和目标值,查找数组中和为目标值的两个数,并输出其下标)

    示例: nums = [1,2,5,7] target = [6] return [0,2] Python解决方案1: def twoSum(nums, target): ""&q ...

  4. 18. 4Sum -- 找到数组中和为target的4个数

    Given an array S of n integers, are there elements a, b, c, and d in S such that a + b + c + d = tar ...

  5. 给定一个整数数组和一个目标值,找出数组中和为目标值的两个数 例如给定nums = [2,7,11,15],target = 9

    python解决方案 nums = [1,2,3,4,5,6] #假如这是给定的数组 target = 9 #假如这是给定的目标值 num_list = [] #用来装结果的容器 def run(nu ...

  6. 1001 数组中和等于K的数对 1002 数塔取数问题 1003 阶乘后面0的数量 1004 n^n的末位数字 1009 数字1的数量

    1001 数组中和等于K的数对 基准时间限制:1 秒 空间限制:131072 KB 分值: 5 难度:1级算法题 给出一个整数K和一个无序数组A,A的元素为N个互不相同的整数,找出数组A中所有和等于K ...

  7. c++刷题(12/100)无序数组中和为定值的最长子数组

    题目一: 最短无序连续子数组 给定一个整数数组,你需要寻找一个连续的子数组,如果对这个子数组进行升序排序,那么整个数组都会变为升序排序. 你找到的子数组应是最短的,请输出它的长度. 示例 1: 输入: ...

  8. [经典算法题]寻找数组中第K大的数的方法总结

    [经典算法题]寻找数组中第K大的数的方法总结 责任编辑:admin 日期:2012-11-26   字体:[大 中 小] 打印复制链接我要评论   今天看算法分析是,看到一个这样的问题,就是在一堆数据 ...

  9. 【bzoj3289】Mato的文件管理 离散化+莫队算法+树状数组

    原文地址:http://www.cnblogs.com/GXZlegend/p/6805224.html 题目描述 Mato同学从各路神犇以各种方式(你们懂的)收集了许多资料,这些资料一共有n份,每份 ...

随机推荐

  1. python学习笔记——(二)循环

    ·密文输入引入getpass库使用getpass.getpass("password:")tips:该功能在PyCharm中不好使,只能在命令行用 ·python强制缩进,省略了大 ...

  2. Microsoft宣布为Power BI提供AI模型构建器,关键驱动程序分析和Azure机器学习集成

    微软的Power BI现在是一种正在大量结合人工智能(AI)的商业分析服务,它使用户无需编码经验或深厚的技术专长就能够创建报告,仪表板等.近日西雅图公司宣布推出几款新的AI功能,包括图像识别和文本分析 ...

  3. SQL数据库中查询中加N'' 前缀是什么意思

    It's declaring the string as nvarchar data type, rather than varchar You may have seen Transact-SQL ...

  4. WEBBASE篇: 第十一篇, JavaScript知识6

    JavaScript 知识6 一, String 对象 1,分隔字符串, 函数: split(seperator) 作用: 将字符串,通过seperator 拆分成一个数组: eg: var msg= ...

  5. 【EMV L2】EMV终端数据

    Account TypeAcquirer IdentifierAdditional Terminal CapabilitiesAmount, Authorised (Binary)Amount, Au ...

  6. c++函数总结

    1.strcpy(char *str1, char *str2) 作用:把str2的字符复制到str1,函数是C风格的函数. 注意事项:strcpy会从源地址一直往后拷贝,直到遇到'\0'为止,所以如 ...

  7. Vector的用法

    vector容器是笔试时最经常用到的容器,它实际是一个类模板,它所具有一些成员函数我们必须熟练使用,这样才会加快编程速度. 首先加头文件并定义: #include<vector> vect ...

  8. python学习5---实现凸包

    1.暴力法 def g(A,B,P): """ 判断点PA矢量在AB矢量的顺时针还是逆时针方向, 若在逆时针方向则返回1,同向返回0,在顺时针方向返回-1 :param ...

  9. 小括号转义 '\\s'

    select split("2405F5 (base 16) Integrated Device Technology (Malaysia) Sdn. Bhd.","\\ ...

  10. IT名词概括与简单了解

    云计算概念 云架构 我看过两本云计算,<云计算><云计算架构技术与实践> 云计算是一个很广的概念,简单的说将互联网中的计算机资源按需分配,提高闲置资源的利用率,需要多少你就购买 ...