先贴代码:
import java.util.*;
public class Solution {
public int getFirstUnFormedNum(int[] arr) {
Arrays.sort(arr); //排序数组
int min = arr[0]; //获取最小值
int max = 0; //获取最大值
for (int k : arr) {
max += k;
}
//创建布尔类型数组,存储[min,max]区间的每个值能否被组成
boolean[] result = new boolean[max + 1];
result[0] = true;
for(int t : arr){
for(int i = max;i >= t;i--){
result[i] = result[i - t] || result[i];
}
}
//遍历result数组,找到第一个结果为false的数,表示不能被组成,即为最小不可组成和
for(int j = min;j < result.length;j++){
if(!result[j]){
return j;
}
}
//循环结束没有输出,说明数组内所有的数都能被组成,那么就返回max+1
return max+1;
}
}
解题思路:
在本题中,max为最大的子集和,min为最小的子集和,要求求出在min到max的区间内找到最小的不可组成和。一个数为最小不可组成和表示这个数不能被数组里的任意子集相加得到。
就以数组 arr {3,2,5}为例,min是2,max是10,要求在2到10之间找到数组的最小不可组成和。如果没有,则最小不可组成和为max+1,即为11。
因为在数组中,10是一定可组成的,所以将10 - 3得到的8,也是可组成的,同理得出8 - 3得到的5 也是可组成的。那么我们可以创建出一个布尔类型的数组 result,用来存储[min , max]区间内的每个数是否是“可组成的”。
令i 表示[mi,max]区间内的每个数,t 表示数组 arr 里的每个元素,i 从max开始,往前递减,因为result[ i ]是可组成的,记为true,那么result[ i - t]也是可组成的,同样也记为true,
result[i - t - t]也是可组成的,记为true;依次遍历往前,就可以将每个可组成的数记为true,不可组成还是false。
最后遍历result 数组,遇到false直接返回,如果数组遍历完还没返回,那么说明所有的数都是可组成的,那么就返回max+1。