Different Ways to Add Parentheses

Different Ways to Add Parentheses

문제 내용

숫자와 +,-,* 3개의 Operation으로 구성된 문장이 있다.

임의로 () <- 괄호를 만든다고 했을 때 나올 수 있는 모든 답을 구하시오.

중복 허용.

 

접근 방법

언듯 쉬워보이는 문제였는데, 

  • 1 <= expression.length <= 20

이 제한 사항을 확인했을 때, 쉬운 방법으로 해결이 안된다는 것을 알았어야 했다.

즉 Operation은 최대 9개가 넘어 가지 않는다.

1+1+1+1+1+1+1+1+1+11

제한사항이 작다는 것을 봤을 때 NP문제라는 것을 알지 못했던 부분이 아쉽다.

아무튼 결국 전 검색이 필요하다.

그럼 모든 경우의 수를 확인하는 방법은 어떻게 해야할까?

괄호를 크게 잡았을 경우를 생각해 보자.

(1)+(1+1+1+1+1+1+1+1+11)

(1+1)+(1+1+1+1+1+1+1+11)

....

(1+1+1+1+1+1+1+1+1)+(11)

특정 Operation을 가운데 두고 양쪽의 결과를 처리하는 방식으로 생각 할 수있다.

이렇게 분리를 하면 가로안의 값은 다시 동일한 방식으로 계산이 가능하다.

(1+1+1+1+1+1+1+1+1)

((1)+(1+1+1+1+1+1+1+1))

.....

((1+1+1+1+1+1+1+1)+(1))

다시 한번더 괄호를 만들어 낼 수 있다.

(1+1+1+1+1+1+1+1)

((1)+(1+1+1+1+1+1+1))

....

((1+1+1+1+1+1+1)+(1))

이런 방식으로 괄호를 칠 수 있는 모든 경우의 수를 만들어 낼 수 있게 된다.

  • Operation을 만나면 해당 Operation을 중심으로 양쪽을 나누어서 양쪽에서 올수 있는 모든 경우의 수를 합산한다.

그럼 코드로 해당 내용을 만들어 보자.

var diffWaysToCompute = function(expression) {
    
    let ans = new Array();
    
    for(let i = 0; i < expression.length; i++){
        let char = expression.charAt(i);
        
        if(char.indexOf('+-*')){
            let leftArr = diffWaysToCompute(expression.substring(0,i));
            let rightArr = diffWaysToCompute(expression.substring(i+1,expression.length));
            
            for(let l = 0; l < leftArr.length; l++){
                for(let r = 0; r < rightArr.length; r++){
                    if(char === '+'){
                        ans.push(leftArr[l] + rightArr[r]);
                    }
                    if(char === '-'){
                        ans.push(leftArr[l] - rightArr[r]);
                    }
                    if(char === '*'){
                        ans.push(leftArr[l] * rightArr[r]);
                    }
                }
            }
        }
    }
    
    if(ans.length === 0) ans.push(parseInt(expression));
    
    return ans;
    
};

위의 코드는 Time Complexity를 계산해 보면

Operation 숫자만큼 한번 계산하고,

다음 Operation에서 Operation 횟수 - 1회 만큼 다시 한번더 Search한다. 그리고 다음 dfs에서 한번더 -1회 만큼 Search한다. 해당 expression에 Operation이 없을 때까지 진행 한다.

즉 Operation 1회에 $ N^2 $ 만큼 깊이로 들어가고 for로 전체 순회를 한번더 하니까 

$$ O(N^3) $$

이 된다.

이 부분을 최적화 하기 위해서 DP를 사용해 보자.

Expression에서 나올 수 있는 결과값의 Set은 항상 고정 될 수 있음으로

한번 사용된 Expression을 Cache처리 하도록 하자.

예를 들자면

1 *2+3 은

$ (1 *2) +3 = 5 $ or $ 1 * (2+3) = 6 $ 두 개 인것은 불변이다.

이것을 Map에 저장해서 재활용 할 수 있게 만들자.

var diffWaysToCompute = function(expression, dp = new Map()) {
    if(dp.has(expression)) return dp.get(expression);
    
    let ans = new Array();
    
    for(let i = 0; i < expression.length; i++){
        let char = expression.charAt(i);
        
        if(char.indexOf('+-*')){
            let leftArr = diffWaysToCompute(expression.substring(0,i),dp);
            let rightArr = diffWaysToCompute(expression.substring(i+1,expression.length),dp);
            
            for(let l = 0; l < leftArr.length; l++){
                for(let r = 0; r < rightArr.length; r++){
                    if(char === '+'){
                        ans.push(leftArr[l] + rightArr[r]);
                    }
                    if(char === '-'){
                        ans.push(leftArr[l] - rightArr[r]);
                    }
                    if(char === '*'){
                        ans.push(leftArr[l] * rightArr[r]);
                    }
                }
            }
        }
    }
    
    if(ans.length === 0) ans.push(parseInt(expression));
    
    dp.set(expression, ans);
    
    return ans;
    
};

 

이렇게 하면 Operation만큼 1회 검색 후 양쪽 한번씩 검색하고 저장이 된 부분은 즉각 결과를 내놓음으로

$$ O(N^2) $$ 으로 충분하게 된다.

미디엄 문제인데... 전순환 문제는 꼭 hard를 푸는 느낌이다. 

아 혹시나 해서 위의 Time Complexity는 대략적인 것이고 정확한것은 하기 link의 

https://people.math.sc.edu/howard/Classes/554b/catalan.pdf

https://www.geeksforgeeks.org/program-nth-catalan-number/

내용을 확인해야 할 것 같은데 너무 복잡해서 Pass...

728x90
반응형

'Problem Solving' 카테고리의 다른 글

Data Stream as Disjoint Intervals  (0) 2021.08.10
Hamming Distance  (0) 2021.08.09
Confirmation Rate  (0) 2021.08.02
2진수 최 좌측 1자리 찾기  (0) 2021.08.02
Super Egg Drop  (0) 2021.07.30