题目:你将得到一个整数数组 matchsticks ,其中 matchsticks[i] 是第 i 个火柴棒的长度。你要用 所有的火柴棍 拼成一个正方形。你 不能折断 任何一根火柴棒,但你可以把它们连在一起,而且每根火柴棒必须 使用一次 。
如果你能使这个正方形,则返回 true ,否则返回 false
测试1
输入: matchsticks = [1,1,2,2,2]
输出: true
解释: 能拼成一个边长为2的正方形,每边两根火柴。
测试2
输入: matchsticks = [3,3,3,3,4]
输出: false
解释: 不能用所有火柴拼成一个正方形。
思路:dfs暴力穷举
本题就是判断能否将一个数组拆分成四等分
生活中一个家中可能配有多个垃圾桶,但是我们都懒的倒垃圾,基本都是所有垃圾桶满了再一起倒掉。有的时候先放满一个桶后再放下一个桶,如果当前垃圾桶放不下这么大的一个垃圾,那么我们就会放在空桶里。所以,dfs的基本思路就是,放四个垃圾桶,依次放垃圾,如果一个桶快满了导致下一个垃圾放不下,那么就换下一个桶,如果放到最后没法放了,回溯取出上一个垃圾,放在下一个桶。
关于先放大垃圾还是小垃圾的问题。这个太过明显了,生活经验也告诉我们,大的垃圾要先放,而且放在底下,所以需要将数组按降序排列,以减少回溯次数。
代码如下:
class Solution {
//定义桶
int[] bucket;
//定义边长
int side;
public boolean makesquare(int[] matchsticks){
//初始化桶
bucket = new int[4];
//初始化边长
int sum = 0;
for (int i = 0; i < matchsticks.length; i++) {
sum += matchsticks[i];
}
if (sum % 4 != 0){
return false;
}
side = sum / 4;
//排序
matchsticks = sort(matchsticks);
return dfs(matchsticks,0);
}
public boolean dfs(int[] matchsticks,int index){
//如果遍历完了,那么结束递归
if (index == matchsticks.length){
return true;
}
//循环放垃圾
for (int i = 0; i < 4; i++) {
//如果满了,那就放下一个桶
if (bucket[i] + matchsticks[index] > side){
continue;
}else {
bucket[i] += matchsticks[index];
//递归
if (dfs(matchsticks,index + 1)){
return true;
}
bucket[i] -= matchsticks[index];
}
}
return false;
}
//冒泡排序,降序排列
public int[] sort(int[] nums){
for (int i = 0; i < nums.length; i++) {
for (int j = 0; j < nums.length - i - 1; j++) {
if (nums[j] < nums[j+1]){
int temp = nums[j];
nums[j] = nums[j+1];
nums[j+1] = temp;
}
}
}
return nums;
}
}