讲解

504 篇文章 0 订阅
43 篇文章 0 订阅

转自出处:http://supercharles888.blog.51cto.com/609344/1345561


其实这道题就是 :   在一个数组中找出和为10的所有组合的问题



题目:

假设有一个大水池,其容积为poolSize,还有n个彼此大小不同的水桶,分别是B1,B2,B3,B4,B5..Bn,放在一个数组中 。请给出水桶的所有组合,使得他们的容积之和刚好可以灌满整个水池poolSize


分析:

因为很久没弄算法了,这题目搞了我近2个小时,其实思路还是蛮简单的, 就是回溯。首先,先升序排列水桶,然后移除水桶容积直接超过水池容积的(这种水桶显然不可能成为解的集合) 。排序后,选出最大的水桶,如果最大的水桶容积刚好等于水池容积,那么返回。如果最大的水桶容积也没有水池大,那么必定是若干小水桶的组合来满足大水池的要求,假设满足要求的水桶集合为C.这时候,我们从排序了的水桶中选出最大的水桶,这样分2种情况:


假设目前最大的水桶Bmax是C的一部分,那么最终的C必定为Bmax  加上水桶集合中除去Bmax的某个组合来满足C-Bmax的结果集,这是一个递归

假设目前最大的水桶Bmax不是C的一部分,那么最终的C必定为水桶集合中除去Bmax的某个组合来满足C的结果集,这也是一个递归。


所以最后实现代码为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
package  com.charles.algo;
import  java.util.ArrayList;
import  java.util.Arrays;
import  java.util.List;
/**
  *
  * 百度面试题:
  * 假设有一个大水池,其容积为poolSize,还有n个彼此大小不同的水桶,分别是B1,B2,B3,B4,B5..Bn,放在一个数组中
  * 请给出水桶的所有组合,使得他们的容积之和刚好可以灌满整个水池poolSize
  *
  * @author charles.wang
  *
  */
public  class  BucketAndPool {
     // 放置可能的解
     private  static  List<Integer> list =  new  ArrayList<Integer>();
     /**
      * 这是一个wrapper方法,用于做一些参数排序处理,和排除所有绝对不可能作为候选列表的桶,以免减少运行时间开销
      *
      * @param poolSize
      *            池的大小
      * @param buckets
      *            所有候选桶的数组
      */
     public  static  void  fillPoolWithBuckets( int  poolSize,  int [] buckets) {
         // 局部变量,作为真正参与运算的buckets
         int [] actualBuckets = buckets;
         // 首先,吧所有的水桶按照升序排序,这样方便我们找到最大的桶
         Arrays.sort(actualBuckets);
         // 判断如果某个buckets的大小超过了池子,那么从这个bucket开始,比它大的buckets都不考虑
         // 于是缩减原来的buckets数组为新的buckets数组,并且只有不超过poolSize的buckets会列在其中
         for  ( int  i =  0 ; i < buckets.length; i++) {
             if  (buckets[i] > poolSize) {
                 actualBuckets = Arrays.copyOf(actualBuckets, i);
                 break ;
             }
         }
         // 递归的调用方法来输出结果
         findSolution(poolSize, actualBuckets);
     }
     /**
      * 递归方法,用当前的可选已经排过序的桶的列表来填充一个池子poolSize
      *
      * @param poolSize
      * @param sortedBuckets
      */
     private  static  void  findSolution( int  poolSize,  int [] sortedBuckets) {
         // 递归的出口,是当前没有可用的桶或者需要凑容积的池子尺寸已经为0了
         if  ((sortedBuckets.length ==  0 ) || (poolSize <=  0 ))
             return ;
         // 输出结果
         //输出结果的条件是当前最大桶(已经排序过)直接满足条件,那么当前最大桶就作为可用解的一个值
         //比如用桶{1,2,3}去凑水池容积为3, 那么一旦找到3,那么就直接输出3
         //而解访问两部分,一个是已有的在计算子匹配之前的已经选出的桶的列表,在list列表中存着呢
         //另一个是找到的当前的解,所以依次输出已选桶的列表(来自list)和当前桶
         if  (poolSize == sortedBuckets[sortedBuckets.length -  1 ]) {
             for  ( int  i =  0 ; i < list.size(); i++) {
                 System.out.print(list.get(i) +  "," );
             }
             System.out.println(poolSize);
         }
                                                   
         //如果最大桶无法直接满足池子的容量,那么就必须用若干小桶来凑池子的容量,为此,先选出小桶中最大的那个。
                                                   
         // 最大的水桶
         int  largestBucket = sortedBuckets[sortedBuckets.length -  1 ];
         //现在解决方案分2部分:
         //(1)放入可用桶桶列表中最大的这个到可用列表中,并且这个桶是有解的,
         //   则用桶列表剔除最大桶的子桶列表来凑 剩余池子容量-最大桶容量,这是个递归调用
         //(2)放入最大桶进去之后,是无解的,那么从可用列表中剔除这个最大桶
         //   并且用桶列表剔除最大桶的子桶列表来凑 剩余池子容量,这是也个递归调用
                                                   
         //放入最大的水桶到可用列表,递归解决其他的水桶来凑 池容量-最大桶容量
         list.add(largestBucket);
         findSolution(poolSize - largestBucket,
                 Arrays.copyOf(sortedBuckets, sortedBuckets.length -  1 ));
         //不放入最大的水桶,递归的解决其他的水桶来凑 池容量
         list.remove(list.size() -  1 );
         findSolution(poolSize,
                 Arrays.copyOf(sortedBuckets, sortedBuckets.length -  1 ));
     }
     public  static  void  main(String[] args) {
         int  poolSize =  31 ;
         int [] buckets = {  6 8 7 12 17 28 23 1 3 16  };
                                                   
         fillPoolWithBuckets(poolSize, buckets);
     }
}



我们假设有若干小水桶,6L,8L,7L,12L,28L,23L,1L,3L,16L,我们要凑出31L的水池, 那么运行这个程序之后,结果如下:

103639281.png


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值