473. 火柴拼正方形

63 阅读2分钟

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

题目描述

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

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

示例

image.png

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

提示

  • 1 <= matchsticks.length <= 15
  • 1 <= matchsticks[i] <= 10^8

回溯

要将整数数组中所有的火柴拼接成一个正方形,那么我们需要统计出所有火柴的总长度,且要保证正方形的四条边相等,由于火柴的长度不一,且不能将火柴折断,那么我们需要进行多次排列,计算出最终能否顺利拼成正方形。

正方形有四条边,那么同一根火柴,我们需要让它在四条边上都比较过,判断放在哪边最适合,这样的场景,可以使用回溯算法来进行实现。

class Solution {
    public boolean makesquare(int[] matchsticks) {
        // 得到火柴的总长度
        int totalLen = Arrays.stream(matchsticks).sum();
        
        // 如果不能平均分成4份,直接返回
        if (totalLen % 4 != 0) {
            return false;
        }
        
        // 排序
        Arrays.sort(matchsticks);
        
        // 回溯
        int[] edges = new int[4];
        return dfs(matchsticks.length - 1, matchsticks, edges, totalLen / 4);
    }

    public boolean dfs(int index, int[] matchsticks, int[] edges, int len) {
        // 所有火柴均已使用,返回结果
        if (index == -1) {
            return true;
        }
        
        // 遍历四边
        for (int i = 0; i < edges.length; i++) {
            // 给当前的边加上火柴的长度
            edges[i] += matchsticks[index];
            
            // 条件判断是否符合长度并且已经使用完所有火柴
            if (edges[i] <= len && dfs(index - 1, matchsticks, edges, len)) {
                return true;
            }
            
            // 回溯
            edges[i] -= matchsticks[index];
        }
        return false;
    }
}