Java递归解决子集求和问题

子集求和问题属于难以高效解决的计算问题中的一类,用于以信息保密为目标的应用中。

子集求和问题的定义为:给定一个整数集和目标值,确定是否可以找到这些整数的一个子集,使其总和等于指定的目标值。

比如给定集合{-2,1,3,8}和目标值7,那么问题的答案就是是,因为有子集{-2,1,8}加起来对于7。但是如果目标值是5,答案就为否。

所以我们很容易定义出递归函数原型:

boolean subsetSumExists(TreeSet set, int target);

分析简单情况——集合为空。除非目标值为0,递归结束,否则我们无法用空集中的元素产生目标值。

if (set.isEmpty()) {
   return target == 0;
} else {...//让问题规模变小的方案}


我们要让集合变小,朝着集合为空的目标迈进。就需要从集合中不断导出元素。导出的元素无非两种情况,1、在构成目标值的子集里,此时就要将target减去这个导出元素;2、不在子集里,就不用减,递归调用还是传target。要么包含要么排除,即包含/排除模式。

分析了这些,递归代码就好写了:

import java.util.TreeSet;

public class SubsetSum {

   public void run() {
      TreeSet set = createIntSet(-2, 1, 3, 8);
      System.out.println("set = " + toString(set));
      int min = minSum(set);
      int max = maxSum(set);
      for (int i = min; i <= max; i++) {
         System.out.println("subsetSumExists(set, " + i + ") = " +
                            subsetSumExists(set, i));
      }
   }

   private TreeSet createIntSet(int... args) {
      TreeSet set = new TreeSet();
      for (int n : args) {
         set.add(n);
      }
      return set;
   }

   private boolean subsetSumExists(TreeSet set, int target) {
      if (set.isEmpty()) {
         return target == 0;
      } else {
         int element = set.first();
         TreeSet rest = new TreeSet(set);
         rest.remove(element);
         return subsetSumExists(rest, target)
             || subsetSumExists(rest, target - element);
      }
   }

   private int minSum(TreeSet set) {
      int total = 0;
      for (int element : set) {
         if (element < 0) total += element;
      }
      return total;
   }

   private int maxSum(TreeSet set) {
      int total = 0;
      for (int element : set) {
         if (element > 0) total += element;
      }
      return total;
   }

/**
 * Returns the String representation of the set using the
 * conventional curly-brace representation.
 */

   private String toString(TreeSet set) {
      String str = "{";
      for (int element : set) {
         if (str.length() > 1) str += ",";
         str += " " + element;
      }
      return str + " }";
   }

/* Main program */

   public static void main(String[] args) {
      new SubsetSum().run();
   }

}


参考:《Programming Abstractions in Java》

你可能感兴趣的:(Java算法与抽象,递归,子集求和,Java,递归)