火柴拼正方形

172 阅读1分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 21 天,点击查看活动详情

你将得到一个整数数组 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

思路

首先对火柴棍求和,得到边长 sideside ,若总长不能被 44 整除则返回 falsefalse。

1. 状态压缩:

最多有 1515 根火柴棍,考虑用一个整型 statestate 表示每根火柴棍是否被选择的状态,statestate 第 ii 位为 11 表示 matchsticks[i]matchsticks[i] 已选择。

2. 搜索策略:

dfs 函数的含义是:查询从当前状态出发,能否在每一步都满足条件的情况下,将所有火柴棍都选择。

具体而言,statestate 表示当前状态,sumsum 表示当前累加边长,其取值范围为 [0,side)[0,side)。每一步遍历挑选一个还未被选择的火柴 ii( statestate 相应位为 00 ),若满足条件 sum+matchsticks[i]<=sidesum+matchsticks[i]<=side, 说明可以选择,继续向下搜索。若搜索到终止状态 (1<<n)−1(1<<n)−1 ,提前返回。

3. 终止状态:

为所有火柴都能够被成功选择,此时返回 truetrue,因此设置 cache[(1<<n)−1]=1cache[(1<<n)−1]=1 。

代码

#define setBit(x, n) (x | (1 << n))
class Solution {
public:
    int side; // 边长
    vector<int8_t> cache;  
    bool makesquare(vector<int>& matchsticks) {
        // 求出边长
        int sum = accumulate(matchsticks.begin(), matchsticks.end(), 0);
        if(sum % 4) return false;
        side = sum / 4;
        // dfs
        int n = matchsticks.size();
        cache = vector<int8_t>((1 << n), -1);
        cache[(1 << n) - 1] = 1;
        return dfs(0, 0, matchsticks);        
    }

    // state - 当前状态,第 i 位为 1 表示 matchsticks[i] 已选择
    // sum - 表示当前累加边长
    bool dfs(int state, int sum, vector<int>& matchsticks){
        if(cache[state] != -1) return cache[state];
        int n = matchsticks.size();
        bool ans = 0;
        for(int i=0; i<n; ++i){
            if(getBit(state, i) == 0 && sum + matchsticks[i] <= side) { 
                int new_sum = ( sum + matchsticks[i] ) % side;
                if( dfs(setBit(state, i), new_sum, matchsticks) ) {
                    ans = 1;
                    break;
                };
            }
        }
        cache[state] = ans;
        return ans;
    }
};