Java递归解决子集求和问题

本文探讨了子集求和问题这一复杂计算问题,并通过递归算法实现了解决方案。文章详细介绍了如何判断一个整数集是否存在子集,使得其总和等于给定的目标值。

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

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

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

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

boolean subsetSumExists(TreeSet<int> 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<Integer> 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<Integer> createIntSet(int... args) {
      TreeSet<Integer> set = new TreeSet<Integer>();
      for (int n : args) {
         set.add(n);
      }
      return set;
   }

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

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

   private int maxSum(TreeSet<Integer> 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<Integer> 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》
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值