프로그래머스 - [Level 2] [카카오 인턴] 수식 최대화(JAVASCRIPT)

3 minute read

프로그래머스 [카카오 인턴] 수식 최대화 [KAKAO]

카테고리 : 문자열

풀이과정은 다음과 같다.

1) 문자열 파싱

연산자와 숫자를 분리해 배열을 만든다.

operator: ['+','-','*']
number : ['100','200','300']

2) 수식 우선순위를 결정

백트래킹을 활용해 수식의 우선순위를 결정한다.
연산자가 3개이기에 직접 연산자 배열을 만들어도  것같다.

3) 수식 계산

우선순위 순대로 수식을 계산한다.
계산이 완료  number 배열의 원소와 operator 연산자는 삭제해준다.

배열이 다음과 같다고 하자.

['+','*','-']
[500,100,200,300]

우선순위 연산자가 '+' 일때, 연산  배열 상태는 다음과 같다.
   
['*','-']
[600,200,300]

주의할점은 연산자 배열을 기준으로 for문을  ,
연산을 했다면 for문의 (증감 변수 -1) 해줘야만
모든 연산이 완료된다.


소스 코드

function solution(expression) {
    let answer = 0;
    const check=[];
    const number=[];
    const operation=[];
    
    function parse(exp){
        let str="";
        for(let i=0;i<exp.length;i++){
            if(exp[i]!=='*' && exp[i]!=='-' && exp[i]!=='+'){
                str+=exp[i];
            }else{
                number.push(str);
                if(i!==0 && exp[i-1]>=0 && exp[i-1]<=9) operation.push(exp[i]);
                str="";
            }
            if(i===exp.length-1) number.push(str);
        }
        
        for(let i=0;i<number.length;i++){
         if(number[i]===""){
             number.splice(i,1);
             number[i]=-number[i];
         }   
        }
    }
    
    
    function calc(oper,num1,num2){
        if(oper==='+') return num1*1+num2*1;
        if(oper==='-') return num1*1-num2*1;
        if(oper==='*') return (num1*1)*(num2*1);
    }
    
    function numToOper(num){
        if(num==='0') return '+';
        if(num==='1') return '-';
        if(num==='2') return '*';
    }
    
    
    function deepCopy(a,b){
        for(let i=0;i<b.length;i++) a[i]=b[i];
    }
    
    
    function go(str){
        let num=[];
        let oper=[];
        
        deepCopy(num,number);
        deepCopy(oper,operation);
        
        for(let i=0;i<3;i++){
            let nowOper=numToOper(str[i]);
            for(let j=0;j<oper.length;j++){
                if(oper[j]===nowOper){
                    let result=calc(oper[j],num[j],num[j+1]);
                    num[j]=result;
                    oper.splice(j,1);
                    num.splice(j+1,1);
                    j--;
                }   
            }
        }
        return Math.abs(num[0]);
    }
    
    function command(cnt,order){
        if(cnt===3){
            answer=Math.max(answer,go(order));
            return;
        }
        
        for(let i=0;i<3;i++){
             if(check[i]) continue;
             check[i]=1;
             command(cnt+1,order+i);
             check[i]=0;
        }
    }
    
    parse(expression);
    command(0,"");
    
    return answer;
}


다른 사람의 코드

내 코드와 다른점
1) 연산자 배열을 직접 만들었다.
2) slplit 정규표현식을 활용해 expression 배열을 파싱했다.
3) deepCopy => slice()로 가능
const solution = (expression) => {
  const arr = [
    ["+", "-", "*"],
    ["+", "*", "-"],
    ["-", "+", "*"],
    ["-", "*", "+"],
    ["*", "+", "-"],
    ["*", "-", "+"],
  ];

  //1. 수식을 숫자(num)과 기호(sign)으로 나눈다.
  let num = expression.split(/[^0-9]/);
  num = num.map((it) => {
    return parseInt(it);
  });
  const sign = [];
  for (let i = 0; i < expression.length; i++) {
    if (
      expression[i] === "*" ||
      expression[i] === "+" ||
      expression[i] === "-"
    ) {
      sign.push(expression[i]);
    }
  }

  let maxNum = 0;
  for (let i = 0; i < arr.length; i++) {
    //2. 배열과 수식을 복사한다.
    const copyNum = num.slice();
    const copySign = sign.slice();
    for (let j = 0; j < arr[i].length; j++) {
      for (let k = 0; k < copySign.length; k++) {
        if (copySign[k] === arr[i][j]) {
          if (copySign[k] === "*") {
            copyNum[k] *= copyNum[k + 1];
            copyNum.splice(k + 1, 1);
            copySign.splice(k, 1);
            k--;
          } else if (copySign[k] === "+") {
            copyNum[k] += copyNum[k + 1];
            copyNum.splice(k + 1, 1);
            copySign.splice(k, 1);
            k--;
          } else {
            copyNum[k] -= copyNum[k + 1];
            copyNum.splice(k + 1, 1);
            copySign.splice(k, 1);
            k--;
          }
        }
      }
    }
    //3. 계산후에 최댓값과 비교하여 최댓값을 찾는다.
    if (Math.abs(copyNum[0]) >= maxNum) {
      maxNum = Math.abs(copyNum[0]);
    }
  }
  return maxNum;
};


다른 사람의 코드 - 2

const solution = (expression) => {
  const numbers = expression.split(/[^0-9]/).map(v => Number(v));
   /*
    ^x : x로 시작하는 문자.
    expression : 	"-100*-200"
   	result => numbers = 	[ 0, 100, 0, 200 ]
   */
  const operators = expression.split(/[0-9]/).filter(v => v);
	/*
	  result => operators = [ '-', '*-' ]
	*/
  const formula = getFormula(numbers, operators);
  const cases = [
    ['*', '+', '-'], ['*', '-', '+'], ['+', '*', '-'],
    ['+', '-', '*'], ['-', '+', '*'], ['-', '*', '+'],
  ];

  /*
  	...cases => 2차원 배열의 원소인 1차원 배열을 기준으로 탐색하기 위함.
  */
  return Math.max(...cases.map(operators => {
    let result = formula.slice();
    operators.forEach(operator => {
      result = computeByTargetOperator(result, operator);
    });

    return Math.abs(...result);
  }));
};

const getFormula = (numbers, operators) => {
  const formula = [];

  numbers.forEach((number, i) => {
    formula.push(number);

    if (operators[i]) {
      formula.push(operators[i]);
    }
  });

  return formula;
}

const computeByTargetOperator = (formula, targetOperator) => {
  const computation = {
    '+': (a, b) => a + b,
    '-': (a, b) => a - b,
    '*': (a, b) => a * b,
  }

  const stack = [];
  for (let i = 0; i < formula.length; i += 1) {
    const target = formula[i];
    if (target === targetOperator) {
      const previousValue = stack.pop();
      const nextValue = formula[i + 1];

      const result = computation[targetOperator](previousValue, nextValue);

      stack.push(result);
      i += 1;
      continue;
    }

    stack.push(target);
  }

  return stack;  
};

Leave a comment