Jerry's Blog

Recording what I learned everyday

View on GitHub


8 November 2020

LeetCode(473) -- Matchsticks to Square

by Jerry Zhang

Problem

给了一些火柴棍的长度,判断它们能否拼成一个正方形。

Solution

public class P473_MatchstickstoSquare {

    public HashMap<Pair<Integer, Integer>, Boolean> memo = new HashMap<>();

    public int[] nums;

    public int side;

    public boolean recurse(Integer mask, Integer sidesDone) {
        int total = 0;
        int L = this.nums.length;

        Pair<Integer, Integer> memoKey = new Pair<>(mask, sidesDone);
        for (int i = L - 1; i >= 0; i--) {
            if ((mask & (1 << i)) == 0) {
                total += this.nums[L - 1 - i];
            }
        }
        if (total > 0 && total % this.side == 0) {
            sidesDone++;
        }
        if (sidesDone == 3) {
            return true;
        }
        if (this.memo.containsKey(memoKey)) {
            return this.memo.get((memoKey));
        }
        boolean ans = false;
        int c = total / this.side;
        int rem = this.side * (c + 1) - total;
        for (int i = L - 1; i >= 0; i--) {
            if (this.nums[L - 1 - i] <= rem && (mask & (1 << i)) > 0) {
                if (recurse(mask ^ (1 << i), sidesDone)) {
                    ans = true;
                    break;
                }
            }
        }
        this.memo.put(memoKey, ans);
        return ans;
    }

    public boolean makesquare(int[] nums) {
        if (nums == null || nums.length == 0) {
            return false;
        }
        int L = nums.length;
        int perimeter = 0;
        for (int num : nums) {
            perimeter += num;
        }
        if (perimeter % 4 != 0) {
            return false;
        }
        this.nums = nums;
        this.side = perimeter / 4;
        return this.recurse((1 << L) - 1, 0);
    }
}

61%

The Best Solution

class Solution {
     public boolean makesquare(int[] nums) {
        if (nums == null || nums.length < 4)
            return false;
        int sum = 0;
        for (int n : nums)
            sum += n;
        if (sum % 4 != 0)
            return false;
        Arrays.sort(nums);
        boolean[] used = new boolean[nums.length];
        return canMakeSquare(nums, nums.length - 1, 0, sum / 4, 0, used);
    }

    // side: there are 4 side of a square to be filled
    private boolean canMakeSquare(int[] nums, int idx, int sum, int targetSum, int side, boolean[] used) {
        // if there is only 1 side left, since all the rest reaches target, the last one reaches targetSum for sure
        if (side == 3)
            return true;

        if (sum == targetSum)
            return canMakeSquare(nums, nums.length - 1, 0, targetSum, side + 1, used);
        else if (sum > targetSum)
            return false;
        else 
        {
            for (int i = idx; i >= 0; --i)
            {
                if (used[i])
                    continue;
                used[i] = true;
                if (canMakeSquare(nums, i - 1, sum + nums[i], targetSum, side, used))
                    return true;
                used[i] = false;
                // dedup
                while (i > 0 && nums[i] == nums[i -1])
                    i--;
            }
            return false;
        }
    }
}
tags: LeetCode