还记得童话《卖火柴的小女孩》吗?现在,你知道小女孩有多少根火柴,请找出一种能使用所有火柴拼成一个正方形的方法。不能折断火柴,可以把火柴连接起来,并且每根火柴都要用到。
输入为小女孩拥有火柴的数目,每根火柴用其长度表示。输出即为是否能用所有的火柴拼成正方形。
示例 1:
输入: [1,1,2,2,2]
输出: true
解释: 能拼成一个边长为2的正方形,每边两根火柴。
示例 2:
输入: [3,3,3,3,4]
输出: false
解释: 不能用所有火柴拼成一个正方形。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/matchsticks-to-square
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
private static boolean generate(int[] nums) {
if(nums.length < 4)
return false;
int tempSum = 0;
for(int i=0; i<nums.length; i++) {
tempSum += nums[i];
}
if(tempSum%4 != 0)
return false;
int target = tempSum/4;
List<Integer> okSubset = new ArrayList<>();
List<Integer> okHalf = new ArrayList<>();
int all = 1<<nums.length;
for(int i=1; i<all; i++) {
int sum = 0;
int val = 0;
for(int j=0; j<nums.length; j++) {
if((val = (i&(1<<j))) > 0) {
sum += nums[j];
}
}
//生成所有符合 target 的集合
if(sum == target) {
okSubset.add(i);
}
}
for(Integer i: okSubset)
System.out.println(i);
//{1, 1, 2, 4, 3, 2, 2, 1}
//选取两边:每个集合包含的边不同,如 {1,1,2}=7(2的0次方,2的一次方...) {4}=8,位与为0
for(int i=0; i<okSubset.size(); i++) {
for(int j=i+1; j<okSubset.size(); j++) {
if((okSubset.get(i)&okSubset.get(j)) == 0) {
okHalf.add((okSubset.get(i)|okSubset.get(j)));
}
}
}
//选取四边
for(int i=0; i<okHalf.size(); i++) {
for(int j=i+1; j<okHalf.size(); j++) {
if((okHalf.get(i)&okHalf.get(j)) == 0) {
return true;
}
}
}
return false;
}
//数组降序 i数组的位置,target = sum/4,buckets 4个装数据的桶
private static boolean generate(int i, int[] nums, int target, int[] buckets) {
if(i >= nums.length) {
return buckets[0] == target && buckets[1] == target
&& buckets[2] == target && buckets[3] == target;
}
for(int j=0; j<4; j++) {
if(buckets[j]+nums[i] > target) {
continue;
}
buckets[j] += nums[i];
if(generate(i+1, nums, target, buckets)) {
return true;
}
buckets[j] -= nums[i];
}
return false;
}
}