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

 public class Test {

     @org.junit.Test
public void test() {
System.out.println("方案数:" + getAllSchemeNum(new int[]{ 5, 5, 5, 2, 3 }, 15));
} // out : 方案数:4 /**
* 从数组中选择和为sum的任意个数的组合数
*/
public static int getAllSchemeNum(int[] arr, int sum) {
int count = 0;
// 将 选择一个数的组合数、选择两个数的组合数、...选择n个数的组合数 相加
for (int numToSelect = 1; numToSelect <= arr.length; numToSelect++) {
count += getSchemeNumByNumToSelect(arr, numToSelect, sum, 0);
}
return count;
} /**
* 求【从数组的[arr[index], arr[length-1]]片段中获取和为sumToSelect的numToSelect个数】的方案数
* @param arr 数组
* @param numToSelect 还需要选择的数的个数
* @param sumToSelect 还需要选择数之和
* @param index 可选的范围的左边界
* @return
*/
public static int getSchemeNumByNumToSelect(int[] arr, int numToSelect, int sumToSelect, int index) {
int count = 0;
// 递归出口,如果数全部选择完成,则只需判定sumToSelect是否为零,如果为零,符合条件,返回1,否则返回0
if (numToSelect == 0) {
return sumToSelect == 0 ? 1 : 0;
}
/*
* 将问题按选择的第一个数的不同做分解,第一个数可选的范围为[index, arr.length - numToSelect],
* 所以就分解成了(arr.length - numToSelect - index + 1)个子问题。可为什么可选下标的右边界是
* (arr.length - numToSelect)呢?是因为如果第一个数的下标是(arr.length - numToSelect + 1),
* 那么后面只剩(numToSelect - 2)个位置,是不够放下剩余的(numToSelect - 1)个值的。
*/
for (int i = index; i <= arr.length - numToSelect; i++) {
if (arr[i] <= sumToSelect) {
/*
* 选择了第一个数arr[i],还需要在剩余数组片段中选择和为(sumToSelect-arr[i])
* 的(numToSelect-1)个数。
* >> 需要递归
*/
count += getSchemeNumByNumToSelect(arr, numToSelect - 1, sumToSelect - arr[i], i + 1);
}
}
return count;
}
}

2、动态规划dp[][]

 @Test
public void test1() {
// 指定输入 >>
int[] arr = { 5, 5, 10, 2, 3 };
int sum = 15;
// ================================================ // 初始化dp二维数组 【dp[i][j]表示用前i个数组成和为j的方案个数】
int rows = arr.length + 1;
int cols = sum + 1;
int[][] dp = new int[rows][cols];
// 初始化dp的第一列,用前i个数组成和为0的方案都只有1种,就是什么都不取;
for (int i = 0; i < rows; i++) {
dp[i][0] = 1;
}
// 初始化dp的第一行,用0个元素不能组成1~sum
for (int j = 1; j <= sum; j++) {
dp[0][j] = 0;
} System.out.println("-- 处理前dp:");
for (int i = 0; i < rows; i++) {
System.out.println((i > 0 ? arr[i - 1] : "附加0") + "\t" + Arrays.toString(dp[i]));
}
System.out.println(); // 一行行的计算dp中每个元素的值
//System.out.println("附加0 \t"+Arrays.toString(dp[0]));
for (int i = 1; i < rows; i++) {
for (int j = 1; j <= sum; j++) {
/*
* 用前i个数来组成和为j的组合,所有成功的组合可分下面两种情况:
* 1、 组合中不包含第i个数 ,即只用前i-1个数来组成和为j的组合。
* 2、组合中包含第i个数,这要求第i个数不能比和大(前i-1个数要组成和为:j-第i个数)。
*/
dp[i][j] = dp[i - 1][j];
if (arr[i-1] <= j) { // 第i个数为arr[i-1]
dp[i][j] += dp[i - 1][j - arr[i-1]];
}
}
//System.out.println(arr[i-1]+"\t"+Arrays.toString(dp[i]));
} System.out.println("-- 处理后dp:");
for (int i = 0; i < rows; i++) {
System.out.println((i > 0 ? arr[i - 1] : "附加0") + "\t" + Arrays.toString(dp[i]));
}
System.out.println("答案:" + dp[rows-1][sum]);
}
/* out:
-- 处理前dp:
附加0 [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
5 [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
5 [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
10 [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
2 [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
3 [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] -- 处理后dp:
附加0 [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
5 [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
5 [1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0]
10 [1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 2]
2 [1, 0, 1, 0, 0, 2, 0, 2, 0, 0, 2, 0, 2, 0, 0, 2]
3 [1, 0, 1, 1, 0, 3, 0, 2, 2, 0, 4, 0, 2, 2, 0, 4]
答案:4
*/

【算法习题】正整数数组中和为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. MySQL数据库“十宗罪”【十大经典错误案例】

    原文作者:张甦 来源:http://blog.51cto.com/sumongodb 今天就给大家列举 MySQL 数据库中,最经典的十大错误案例,并附有处理问题的解决思路和方法,希望能给刚入行,或数 ...

  2. C# Ini、Json、Xml 封装类

    1.Ini是什么?(我对它的理解,用于存储用户配置信息的文件,该文件放在用户电脑...) INI文件是一个无固定标准格式的配置文件.它以简单的文字与简单的结构组成,常常使用在Windows操作系统,或 ...

  3. DatePickerAndroid用法

    一.代码/** * Sample React Native App * https://github.com/facebook/react-native */ 'use strict'; import ...

  4. Ubuntu 将其他盘挂载到/home的子目录下

    Ubuntu 14.04 将其他盘挂载到/home的子目录下当安装完Ubuntu系统,由于当时没有注意,分配的分区空间太小.经过一段时间安装了各式各样的软件后,常常会遇到/home目录下空间不够的情况 ...

  5. 2018最新Python视频教程

    基础+就业Python视频教程需要的加我q:1139721002备注来意

  6. crunch--字典生成工具

    Crunch是一种创建密码字典工具,按照指定的规则生成密码字典,可以灵活的制定自己的字典文件.使用Crunch工具生成的密码可以输出到屏幕,保存到文件.或另一个程序.crunch程序在2004年及以前 ...

  7. python从零开始 -- 第0篇之Hello World!

    为什么选择python以及版本选择 学习资料 学习方法和路径 1. 为什么选择python以及版本选择: Python  好玩,强大,更多关于关于为什么选择Python,在  编程小白的第一本 Pyt ...

  8. 初用jdbc来运行事务

    dao层 public Connection getConnection() throws Exception { Class.forName(driver); if (con == null || ...

  9. vue 安装

    安装cnpm npm install -g cnpm --registry=https://registry.npm.taobao.org 安装 vue.js cnpm install -g vue- ...

  10. SQL中Union和Union All

    工作中,看到大佬写的一段SQL,查询了五个表中的数据,最后求某个收入的总和,其中使用了Union All,因此在这里记录一下我从中学到的东西 先上语法 Union:   [ Select语句1 ] U ...