火柴拼正方形

193 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第7天,点击查看活动详情

一、题目

LeetCode 火柴拼正方形

你将得到一个整数数组 matchsticks ,其中 matchsticks[i] 是第 i 个火柴棒的长度。你要用 所有的火柴棍 拼成一个正方形。你 不能折断 任何一根火柴棒,但你可以把它们连在一起,而且每根火柴棒必须 使用一次 。

如果你能使这个正方形,则返回 true ,否则返回 false 。

示例 1:

输入: matchsticks = [1,1,2,2,2]
输出: true
解释: 能拼成一个边长为2的正方形,每边两根火柴。

示例 2:

输入: matchsticks = [3,3,3,3,4]
输出: false
解释: 不能用所有火柴拼成一个正方形。

提示:

1 <= matchsticks.length <= 15
1 <= matchsticks[i] <= 108

二、题解

给定一个整数的数组,数组元素值表示一根火柴的长度,要求判断能否使用所有的火柴拼接成一个正方形,并且不能折断火柴,每根火柴必须使用一次。

方法一 要使用火柴拼接完成一个正方形,那就需要拼接得到四条长度相等的火柴,那么数组元素的总长度就必须为4的倍数,同时需要使用这些元素任意的组合拼接来达到四条相等的边长。首先判断如果火柴都没有4根那就完全没法组成正方形了, 然后算出火柴总长度totalLen,如果不满足可以平均分配四条边的就没法组成正方形。然后我们需要记录4条边的长度,然后将火柴长度放置到边长上,并且保持刚好组合为边长的长度,当所以火柴都放置了,并且边长也都可以组合成正方形就是符合的,为了方便枚举,先给火柴长度排序,当然需要从大到小来排序的。然后就行dfs递归搜索,递归需要index记录某一根火柴,枚举其能否放入边长中来组合,同样的需要记录正方形的四条边长,这里就用square数组的四个元素来记录,然后遍历没一根火柴,尝试放入边长中拼接正方形。

三、代码

方法一 Java代码

class Solution {
    int[] ms;
    int sideLen;
    public boolean makesquare(int[] matchsticks) {
        if (matchsticks.length < 4) {
            return false;
        }
        int totalLen = Arrays.stream(matchsticks).sum();
        if (totalLen % 4 != 0) {
            return false;
        }
        Arrays.sort(matchsticks);
        for (int i = 0, j = matchsticks.length - 1; i < j; i++, j--) {
            int temp = matchsticks[i];
            matchsticks[i] = matchsticks[j];
            matchsticks[j] = temp;
        }
        ms = matchsticks;
        sideLen = totalLen / 4;
        int[] square = new int[4];
        return dfs(0, square);
    }

    public boolean dfs(int index, int[] square) {
        if (index == ms.length) {
            return true;
        }
        for (int i = 0; i < square.length; i++) {
            square[i] += ms[index];
            if (square[i] <= sideLen && dfs(index + 1, square)) {
                return true;
            }
            square[i] -= ms[index];
        }
        return false;
    }
}

时间复杂度:O(4^n),枚举每根火柴应该放置的边。

空间复杂度:O(n),递归使用的栈空间。