본문 바로가기

코딩테스트/LeetCode

[LeetCode] Matchsticks To Square

문제링크

 

Matchsticks to Square - LeetCode

Level up your coding skills and quickly land a job. This is the best place to expand your knowledge and get prepared for your next interview.

leetcode.com

 

matchstick이 담긴 배열 matchsticks가 주어질때 모든 matchstick을 사용하여 하나의 정사각형을 만드는 문제

조건1. stick은 부술수 없고 연결할 수 있다.
조건2. 각각의 stick은 한번만 사용할 수 있다. 

접근방법

우선 정사각형이 될 수 있는 조건을 판별해야한다.
perimeter : 모든 성냥깨비 길이의 합
sideLen : perimeter / 4 (한변의 길이)
const perimeter = matchsticks.reduce((acc, cur) => acc += cur);
const sideLen = perimeter / 4;

matchsticks.sort((a, b) => b - a);

if(!Number.isInteger(sideLen) || matchsticks.length < 4 || matchsticks[0] > sideLen) return false;​

한변의 길이가 정수가 아니거나, 성냥깨비의 개수가 3개 이하이거나, 가장 긴 성냥깨비가 한변의 길이보다 긴 경우
정사각형이 될 수 없다.


이제 모든 성냥깨비를 통해 정사각형이 될 수 있는지 (4개의 sideLen을 만들 수 있는지)를 구해야한다.

bfs방식으로 가까운 성냥부터 탐색하여 진행하였다.
sideArr : 정사각형 4변을 의미 (모든 변의 길이가 sideLen이 되어야함)
const sideArr = new Array(4).fill(0);

const dfs = (stickIdx, sideLen) => {
    if(stickIdx === matchsticks.length) return true;
    for(let i = 0; i < 4; i++){
        if(sideArr[i] + matchsticks[stickIdx] > sideLen) continue;

        sideArr[i] += matchsticks[stickIdx];

        if(dfs(stickIdx + 1, sideLen)) return true;

        sideArr[i] -= matchsticks[stickIdx];
    }

    return false;
}​

함수는 첫번째 성냥부터 탐색하며 조건에 맞는 sideArr[i]에 성냥을 넣는 방식으로 진행한다.

예)
matchsticks = [10,7,7,7,2,2,2,1,1,1] (내림차순 정렬)
sideArr = [0,0,0,0]
sideLen = 10;

sideArr[i] + matchsticks[stickIdx]  > 10 인 경우 sideArr[i+1]에 matchsticks[stickIdx]를 더하며 진행
dfs(0, sideLen) 실행시 => sideArr[10, 0, 0, 0]
재귀를 통해 dfs(1, sideLen) 실행시 => sideArr[10, 7, 0, 0]
재귀를 통해 dfs(2, sideLen) 실행시 => sideArr[10, 7, 7, 0]
재귀를 통해 dfs(3, sideLen) 실행시 => sideArr[10, 7, 7, 7]
재귀를 통해 dfs(4, sideLen) 실행시 => sideArr[10, 9, 7, 7]
...
재귀를 통해 dfs(9, sideLen) 실행시 => sideArr[10, 10, 10, 10]
stickIdx === matchsticks.length가 되었으므로 true를 반환한다.

이는 제일 간단한 경우를 설명한 것으로 만약 false가 호출되어 sideArr[i] -= matchsticks[stickIdx];가 실행되면 설명하기 매우 복잡해진다.

 

/**
 * @param {number[]} matchsticks
 * @return {boolean}
 */
var makesquare = function(matchsticks) {
    const perimeter = matchsticks.reduce((acc, cur) => acc += cur);
    const sideLen = perimeter / 4;
    const sideArr = new Array(4).fill(0);
    
    matchsticks.sort((a, b) => b - a);
    
    if(!Number.isInteger(sideLen) || matchsticks.length < 4 || matchsticks[0] > sideLen) return false;
    
    const dfs = (stickIdx, sideLen) => {
        if(stickIdx === matchsticks.length) return true;
        for(let i = 0; i < 4; i++){
            if(sideArr[i] + matchsticks[stickIdx] > sideLen) continue;
            
            sideArr[i] += matchsticks[stickIdx];
            
            if(dfs(stickIdx + 1, sideLen)) return true;
            
            sideArr[i] -= matchsticks[stickIdx];
        }
        
        return false;
    }
    
    return dfs(0, sideLen)
};

'코딩테스트 > LeetCode' 카테고리의 다른 글

[LeetCode] Pascals Triangle  (0) 2022.07.19
[LeetCode] Single Number II  (0) 2022.07.15
[LeetCode] Combination Sum  (0) 2022.07.11
[LeetCode] Min Cost Climbing Stairs  (0) 2022.07.10
[LeetCode] Single Number  (0) 2022.07.09