Array sum is K - DP

求出一个数组arr中有没有那几个数加起来等于S,有,返回true 没有返回false。

分析:

eg:arr={2,4,6,3}  S=10;

动态规划可以这么理解:1、很多个重叠子问题 2、选或者不选的问题

对于数组中的每一个数,比如例子中的3,如果选择,则需要3之前的数可以组成S-3=7

按下标i表示:

                    如果选:f(i,S)=f(i-1,S-arr[i]);

                    如果不选:f(i)=f(i-1,S)

再考虑问题的出口:当数组只有一个元素,此时返回arr[0]==S;

当S=0,即f(i,S)中S为0,说明在i的后面的数组中已经有加起来等于S的数,则返回true,

如果arr[i]>S ,则直接计算f(i-1,S)即可。

动态规划可以用递归的方式完成,但复杂度为O(2^n),因为它是由大到小的推,比如要算f(i),要算f(i-1),而动态规划是从小到大,先计算f(i),再计算f(i+1),把每次的结果存储下来,最后复杂度变为O(n)。

下面是代码实现:rec_subSet是递归实现,dp_subSet是动态规划实现。

package test;


public class Main {
	
	public static boolean rec_subSet(int[] arr,int i,int S){
		if(S==0)
			return true;
		if(i==0)
			return arr[i]==S;
		if(arr[i]>S){
			return rec_subSet(arr,i-1, S);
		}
		return rec_subSet(arr, i-1, S-arr[i])||rec_subSet(arr, i-1, S);
	}
	
	public static void dp_subSet(int[] arr,int S) {
boolean[][] subSet = new boolean[arr.length][S+1];
    	
    	for(int i = 0; i <= arr.length-1; i++){
    		subSet[i][0] = true;
    	}
    	
    	for(int i = 0; i <= S; i++){
    		subSet[0][i] = false;
    		if(i==arr[0])
    			subSet[0][arr[0]] = true;
    	}
    	
    	for(int i = 1; i <= arr.length-1;i++){
    		for(int s = 1;s<=S;s++){
    			if(arr[i]>s)
    				subSet[i][s] = subSet[i-1][s];
    			else {
					subSet[i][s] = (subSet[i-1][s-arr[i]]) || (subSet[i-1][s]);
				}
    		}
    	}
    	System.out.println(subSet[5][S]);
	}
    public static void main(String[] args) {
    	
    	int[] arr = {3,34,4,12,5,2};
    	int S = 9;
    	dp_subSet(arr, S);
    	System.out.println(rec_subSet(arr,arr.length-1,S));
    }
     
}


猜你喜欢

转载自blog.csdn.net/cuiyaocool/article/details/79742084
今日推荐