πŸ’†πŸ»‍♂️ ν”Ό-μ—μŠ€/🐣 ν”„λ‘œκ·Έλž˜λ¨ΈμŠ€

[μŠ€μœ„ν”„νŠΈ μ•Œκ³ λ¦¬μ¦˜] ν”„λ‘œκ·Έλž˜λ¨ΈμŠ€: μˆ˜μ‹μ΅œλŒ€ν™”

κ°œλ°œν•˜λŠ” ν›ˆμ΄ 2021. 9. 1. 01:12

문제

https://programmers.co.kr/learn/courses/30/lessons/67257

 

μ½”λ”©ν…ŒμŠ€νŠΈ μ—°μŠ΅ - μˆ˜μ‹ μ΅œλŒ€ν™”

IT 벀처 νšŒμ‚¬λ₯Ό μš΄μ˜ν•˜κ³  μžˆλŠ” 라이언은 맀년 사내 해컀톀 λŒ€νšŒλ₯Ό κ°œμ΅œν•˜μ—¬ μš°μŠΉμžμ—κ²Œ μƒκΈˆμ„ μ§€κΈ‰ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€. 이번 λŒ€νšŒμ—μ„œλŠ” μš°μŠΉμžμ—κ²Œ μ§€κΈ‰λ˜λŠ” μƒκΈˆμ„ 이전 λŒ€νšŒμ™€λŠ” λ‹€λ₯΄κ²Œ λ‹€μŒκ³Ό

programmers.co.kr

문제 μ„€λͺ…

IT 벀처 νšŒμ‚¬λ₯Ό μš΄μ˜ν•˜κ³  μžˆλŠ” λΌμ΄μ–Έμ€ 맀년 사내 해컀톀 λŒ€νšŒλ₯Ό κ°œμ΅œν•˜μ—¬ μš°μŠΉμžμ—κ²Œ μƒκΈˆμ„ μ§€κΈ‰ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€.


이번 λŒ€νšŒμ—μ„œλŠ” μš°μŠΉμžμ—κ²Œ μ§€κΈ‰λ˜λŠ” μƒκΈˆμ„ 이전 λŒ€νšŒμ™€λŠ” λ‹€λ₯΄κ²Œ λ‹€μŒκ³Ό 같은 λ°©μ‹μœΌλ‘œ κ²°μ •ν•˜λ €κ³  ν•©λ‹ˆλ‹€.


해컀톀 λŒ€νšŒμ— μ°Έκ°€ν•˜λŠ” λͺ¨λ“  μ°Έκ°€μžλ“€μ—κ²ŒλŠ” μˆ«μžλ“€κ³Ό 3κ°€μ§€μ˜ μ—°μ‚°λ¬Έμž(+, -, *) 만으둜 이루어진 μ—°μ‚° μˆ˜μ‹μ΄ μ „λ‹¬λ˜λ©°, μ°Έκ°€μžμ˜ λ―Έμ…˜μ€ 전달받은 μˆ˜μ‹μ— ν¬ν•¨λœ μ—°μ‚°μžμ˜ μš°μ„ μˆœμœ„λ₯Ό 자유둭게 μž¬μ •μ˜ν•˜μ—¬ λ§Œλ“€ 수 μžˆλŠ” κ°€μž₯ 큰 숫자λ₯Ό μ œμΆœν•˜λŠ” κ²ƒμž…λ‹ˆλ‹€.


단, μ—°μ‚°μžμ˜ μš°μ„ μˆœμœ„λ₯Ό μƒˆλ‘œ μ •μ˜ν•  λ•Œ, 같은 μˆœμœ„μ˜ μ—°μ‚°μžλŠ” μ—†μ–΄μ•Ό ν•©λ‹ˆλ‹€. 즉, + > - > * λ˜λŠ” - > * > + λ“±κ³Ό 같이 μ—°μ‚°μž μš°μ„ μˆœμœ„λ₯Ό μ •μ˜ν•  수 μžˆμœΌλ‚˜ +,* > - λ˜λŠ” * > +,-처럼 2개 μ΄μƒμ˜ μ—°μ‚°μžκ°€ λ™μΌν•œ μˆœμœ„λ₯Ό 가지도둝 μ—°μ‚°μž μš°μ„ μˆœμœ„λ₯Ό μ •μ˜ν•  μˆ˜λŠ” μ—†μŠ΅λ‹ˆλ‹€. μˆ˜μ‹μ— ν¬ν•¨λœ μ—°μ‚°μžκ°€ 2개라면 μ •μ˜ν•  수 μžˆλŠ” μ—°μ‚°μž μš°μ„ μˆœμœ„ 쑰합은 2! = 2가지이며, μ—°μ‚°μžκ°€ 3개라면 3! = 6가지 쑰합이 κ°€λŠ₯ν•©λ‹ˆλ‹€.


λ§Œμ•½ κ³„μ‚°λœ κ²°κ³Όκ°€ 음수라면 ν•΄λ‹Ή 숫자의 μ ˆλŒ“κ°’μœΌλ‘œ λ³€ν™˜ν•˜μ—¬ μ œμΆœν•˜λ©° μ œμΆœν•œ μˆ«μžκ°€ κ°€μž₯ 큰 μ°Έκ°€μžλ₯Ό 우승자둜 μ„ μ •ν•˜λ©°, μš°μŠΉμžκ°€ μ œμΆœν•œ 숫자λ₯Ό μš°μŠΉμƒκΈˆμœΌλ‘œ μ§€κΈ‰ν•˜κ²Œ λ©λ‹ˆλ‹€.

 

예λ₯Ό λ“€μ–΄, μ°Έκ°€μž 쀑 λ„€μ˜€κ°€ μ•„λž˜μ™€ 같은 μˆ˜μ‹μ„ μ „λ‹¬λ°›μ•˜λ‹€κ³  κ°€μ •ν•©λ‹ˆλ‹€.

"100-200*300-500+20"

일반적으둜 μˆ˜ν•™ 및 μ „μ‚°ν•™μ—μ„œ μ•½μ†λœ μ—°μ‚°μž μš°μ„ μˆœμœ„μ— λ”°λ₯΄λ©΄ λ”ν•˜κΈ°μ™€ λΉΌκΈ°λŠ” μ„œλ‘œ λ™λ“±ν•˜λ©° κ³±ν•˜κΈ°λŠ” λ”ν•˜κΈ°, 빼기에 λΉ„ν•΄ μš°μ„ μˆœμœ„κ°€ λ†’μ•„ * > +,- λ‘œ μš°μ„ μˆœμœ„κ°€ μ •μ˜λ˜μ–΄ μžˆμŠ΅λ‹ˆλ‹€.


λŒ€νšŒ κ·œμΉ™μ— 따라 + > - > * λ˜λŠ” - > * > + λ“±κ³Ό 같이 μ—°μ‚°μž μš°μ„ μˆœμœ„λ₯Ό μ •μ˜ν•  수 μžˆμœΌλ‚˜ +,* > - λ˜λŠ” * > +,- μ²˜λŸΌ 2개 μ΄μƒμ˜ μ—°μ‚°μžκ°€ λ™μΌν•œ μˆœμœ„λ₯Ό 가지도둝 μ—°μ‚°μž μš°μ„ μˆœμœ„λ₯Ό μ •μ˜ν•  μˆ˜λŠ” μ—†μŠ΅λ‹ˆλ‹€.


μˆ˜μ‹μ— μ—°μ‚°μžκ°€ 3개 μ£Όμ–΄μ‘ŒμœΌλ―€λ‘œ κ°€λŠ₯ν•œ μ—°μ‚°μž μš°μ„ μˆœμœ„ 쑰합은 3! = 6가지이며, κ·Έ 쀑 + > - > * λ‘œ μ—°μ‚°μž μš°μ„ μˆœμœ„λ₯Ό μ •ν•œλ‹€λ©΄ 결괏값은 22,000원이 λ©λ‹ˆλ‹€.


λ°˜λ©΄μ— * > + > - λ‘œ μ—°μ‚°μž μš°μ„ μˆœμœ„λ₯Ό μ •ν•œλ‹€λ©΄ μˆ˜μ‹μ˜ 결괏값은 -60,420 μ΄μ§€λ§Œ, κ·œμΉ™μ— 따라 우승 μ‹œ μƒκΈˆμ€ μ ˆλŒ“κ°’μΈ 60,420원이 λ©λ‹ˆλ‹€.

 

μ°Έκ°€μžμ—κ²Œ 주어진 μ—°μ‚° μˆ˜μ‹μ΄ λ‹΄κΈ΄ λ¬Έμžμ—΄ expression이 λ§€κ°œλ³€μˆ˜λ‘œ μ£Όμ–΄μ§ˆ λ•Œ, 우승 μ‹œ 받을 수 μžˆλŠ” κ°€μž₯ 큰 μƒκΈˆ κΈˆμ•‘μ„ return ν•˜λ„λ‘ solution ν•¨μˆ˜λ₯Ό μ™„μ„±ν•΄μ£Όμ„Έμš”.

 

[μ œν•œμ‚¬ν•­]

  • expression은 길이가 3 이상 100 μ΄ν•˜μΈ λ¬Έμžμ—΄μž…λ‹ˆλ‹€.
  • expression은 곡백문자, κ΄„ν˜Έλ¬Έμž 없이 μ˜€λ‘œμ§€ μˆ«μžμ™€ 3κ°€μ§€μ˜ μ—°μ‚°μž(+, -, *) 만으둜 이루어진 μ˜¬λ°”λ₯Έ μ€‘μœ„ν‘œκΈ°λ²•(μ—°μ‚°μ˜ 두 λŒ€μƒ 사이에 μ—°μ‚°κΈ°ν˜Έλ₯Ό μ‚¬μš©ν•˜λŠ” 방식)으둜 ν‘œν˜„λœ μ—°μ‚°μ‹μž…λ‹ˆλ‹€. 잘λͺ»λœ 연산식은 μž…λ ₯으둜 주어지지 μ•ŠμŠ΅λ‹ˆλ‹€.
    • 즉, "402+-561*"처럼 잘λͺ»λœ μˆ˜μ‹μ€ μ˜¬λ°”λ₯Έ μ€‘μœ„ν‘œκΈ°λ²•μ΄ μ•„λ‹ˆλ―€λ‘œ 주어지지 μ•ŠμŠ΅λ‹ˆλ‹€.
  • expression의 ν”Όμ—°μ‚°μž(operand)λŠ” 0 이상 999 μ΄ν•˜μ˜ μˆ«μžμž…λ‹ˆλ‹€.
    • 즉, "100-2145*458+12"처럼 999λ₯Ό μ΄ˆκ³Όν•˜λŠ” ν”Όμ—°μ‚°μžκ°€ ν¬ν•¨λœ μˆ˜μ‹μ€ μž…λ ₯으둜 주어지지 μ•ŠμŠ΅λ‹ˆλ‹€.
    • "-56+100"처럼 ν”Όμ—°μ‚°μžκ°€ 음수인 μˆ˜μ‹λ„ μž…λ ₯으둜 주어지지 μ•ŠμŠ΅λ‹ˆλ‹€.
  • expression은 적어도 1개 μ΄μƒμ˜ μ—°μ‚°μžλ₯Ό ν¬ν•¨ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€.
  • μ—°μ‚°μž μš°μ„ μˆœμœ„λ₯Ό μ–΄λ–»κ²Œ μ μš©ν•˜λ”λΌλ„, expression의 쀑간 계산값과 μ΅œμ’… 결괏값은 μ ˆλŒ“κ°’μ΄ 263 - 1 μ΄ν•˜κ°€ λ˜λ„λ‘ μž…λ ₯이 μ£Όμ–΄μ§‘λ‹ˆλ‹€.
  • 같은 μ—°μ‚°μžλΌλ¦¬λŠ” μ•žμ— μžˆλŠ” κ²ƒμ˜ μš°μ„ μˆœμœ„κ°€ 더 λ†’μŠ΅λ‹ˆλ‹€.

풀이

이 문제λ₯Ό ν•΄κ²°ν•˜κΈ° μœ„ν•΄μ„œ 두 개의 μ†Œλ¬Έμ œλ₯Ό μ •μ˜ν•΄μ•Όν•©λ‹ˆλ‹€.

 

1. μ—°μ‚°μž μš°μ„ μˆœμœ„μ˜ 쑰합을 λ§Œλ“œλŠ” 문제

2. μ—°μ‚°μž μš°μ„ μˆœμœ„λŒ€λ‘œ 식을 κ³„μ‚°ν•˜λŠ” 문제

 

λ”°λΌμ„œ μ‘°ν•©κ³Ό μ™„μ „νƒμƒ‰μœΌλ‘œ ν’€ 수 μžˆλŠ” λ¬Έμ œμ˜€μŠ΅λ‹ˆλ‹€.

μ‘°ν•© μ°ΎκΈ°

λ¨Όμ €, μ—°μ‚°μžμ˜ μš°μ„ μˆœμœ„λŠ” λ°±νŠΈλž˜ν‚Ήμ„ 톡해 쑰합을 μƒμ„±ν•΄μ£Όμ—ˆμŠ΅λ‹ˆλ‹€. "+", "-", "*" 둜 λ§Œλ“€ 수 μžˆλŠ” μ€‘λ³΅μ—†λŠ” 쑰합을 λ§Œλ“€λ©΄ 총 6개의 쑰합을 μ–»κ²Œ λ©λ‹ˆλ‹€. 

func makeComb (operators: [String], priorityOp: [String], combinations: [[String]]) -> [[String]] {
    var combinations = combinations
    var priorityOp = priorityOp
    
    if priorityOp.count == operators.count {
        combinations.append(priorityOp)
        return combinations
    }
    
    for i in 0..<operators.count {
        if priorityOp.contains(operators[i]) { continue }
        priorityOp.append(operators[i])
        combinations = makeComb(operators: operators, priorityOp: priorityOp, combinations: combinations)
        priorityOp.removeLast()
    }
    return combinations
}

μš°μ„ μˆœμœ„λŒ€λ‘œ κ³„μ‚°ν•˜κΈ° 

식을 λ°°μ—΄λ‘œ λ‚˜λˆ„κΈ°

μš°μ„  μˆœμœ„λŒ€λ‘œ 계산을 ν•˜κΈ° μœ„ν•΄μ„œ λ¬Έμžμ—΄μ—μ„œ μ—°μ‚°μžμ™€ ν”Όμ—°μ‚°μžλ₯Ό 각각 λ‚˜λˆ„μ–΄μ€„ ν•„μš”κ°€ μžˆμ—ˆμŠ΅λ‹ˆλ‹€. 이λ₯Ό μœ„ν•΄ expression λ¬Έμžμ—΄μ„ λΆ€λΆ„ λ¬Έμžμ—΄λ‘œ λ‚˜λˆ μ„œ 배열에 μ €μž₯ν•˜λŠ” ν•¨μˆ˜λ₯Ό λ§Œλ“€κΈ°λ‘œ ν•˜κ³  λ‹€μŒκ³Ό 같은 μ•Œκ³ λ¦¬μ¦˜μœΌλ‘œ ν•¨μˆ˜λ₯Ό κ΅¬μ„±ν•˜μ˜€μŠ΅λ‹ˆλ‹€.

  1. expression λ¬Έμžμ—΄μ„ "+", "-", "*" 문자λ₯Ό κΈ°μ€€μœΌλ‘œ λ‚˜λˆ μ„œ λ°°μ—΄λ‘œ λ§Œλ“ λ‹€. 예) "100*10-2+1" -> ["100", "10", "2", "1"]
  2. expression λ¬Έμžμ—΄μ—μ„œ μ—°μ‚°μž λ¬Έμžλ“€μ˜ μˆœμ„œλ₯Ό κ΅¬ν•œλ‹€. 예) ["*", "-", "+"]
  3. 숫자만 있던 배열에 연산듀을 λΌμ›Œλ„£λŠ”λ‹€. 예) ["100", "*", "10", "-", "2", "+", "1"]

μ΄λ ‡κ²Œ ν•˜λ©΄ 전체 식을 μ—°μ‚°μžμ™€ ν”Όμ—°μ‚°μžλ‘œ λ‚˜λˆ μ„œ 배열에 λ‹΄κ²Œ λ©λ‹ˆλ‹€. μœ„ μ•Œκ³ λ¦¬μ¦˜μ„ κ΅¬ν˜„ν•˜λ©΄ λ‹€μŒκ³Ό 같이 κ΅¬ν˜„ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

func separateExpression(expression: String) -> [String] {
    var operators = expression.filter({ ["+", "-", "*"].contains($0) }).map({ symbol in String(symbol) })
    var numbers = expression.components(separatedBy: ["+", "-", "*"])
    
    var i = 1
    while !operators.isEmpty {
        numbers.insert(operators.removeFirst(), at: i)
        i += 2
    }
    
    return numbers
}

μ—°μ‚°μž 문자λ₯Ό μ‹€μ œ μ—°μ‚°μžλ‘œ λ°”κΎΈκΈ°

μŠ€μœ„ν”„νŠΈμ—μ„œ μ—°μ‚¬μžλ“€μ€ ν•¨μˆ˜μ΄κ³  ν•¨μˆ˜λŠ” λ°˜ν™˜κ°’μœΌλ‘œ μ‚¬μš©λ  수 μžˆκΈ°λ•Œλ¬Έμ—, 각 λ¬Έμžμ— λŒ€ν•œ μ—°μ‚°μžλ₯Ό λ°˜ν™˜ν•˜λŠ” ν•¨μˆ˜λ₯Ό ꡬ성할 수 μžˆμŠ΅λ‹ˆλ‹€.

func stringToOperator(op: String) -> ((Int, Int)->Int) {
    switch op {
    case "+":
        return (+)
    case "-":
        return (-)
    default:
        return (*)
    }
}

μŠ€νƒμœΌλ‘œ μš°μ„ μˆœμœ„μ— 맞게 κ³„μ‚°ν•˜κΈ°

이제 1λ‹¨κ³„μ—μ„œ κ΅¬ν•œ μ‘°ν•©κ³Ό λ§Œλ“€μ–΄μ§„ 식 배열을 μ΄μš©ν•΄μ„œ μš°μ„ μˆœμœ„λŒ€λ‘œ 계산을 μˆ˜ν–‰ν•΄μ£Όμ–΄μ•Ό ν•©λ‹ˆλ‹€. μŠ€νƒμ„ μ‚¬μš©ν•΄μ„œ ν˜„μž¬ μš°μ„ μˆœμœ„κ°€ κ°€μž₯ 높은 μ—°μ‚°μžλΆ€ν„° μ‚¬μš©ν•˜λ©΄ μ‹μ˜ κ²°κ³Όλ₯Ό 얻을 수 μžˆμŠ΅λ‹ˆλ‹€. μ•Œκ³ λ¦¬μ¦˜μ€ λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€.

  1. 빈 μŠ€νƒμ„ λ§Œλ“ λ‹€.
  2. μ—°μ‚°μž μš°μ„ μˆœμœ„ 배열을 μ°Έμ‘°ν•΄μ„œ ν˜„μž¬ μš°μ„ μˆœμœ„κ°€ κ°€μž₯ 높은 μ—°μ‚°μžλ₯Ό μ„€μ •ν•œλ‹€.
  3. ν˜„μž¬ μ‹μ—μ„œ κ°€μž₯ μ•ž 문자λ₯Ό popν•œλ‹€.
  4. κΊΌλ‚Έ λ¬Έμžκ°€ 숫자라면 μŠ€νƒμ— λ„£λŠ”λ‹€.
  5. μŠ€νƒμ— 값이 λ“€μ–΄μžˆκ³ , κΊΌλ‚Έ λ¬Έμžκ°€ μ—°μ‚°μžμΌ λ•Œ,
    1. ν˜„μž¬ μš°μ„ μˆœμœ„κ°€ κ°€μž₯ 높은 μ—°μ‚°μžμ™€ μΌμΉ˜ν•œλ‹€λ©΄ :
      1. μŠ€νƒμ˜ λ§ˆμ§€λ§‰ popν•΄μ„œ lhs둜 λ§Œλ“ λ‹€.
      2. μ‹μ—μ„œ 문자 ν•˜λ‚˜λ₯Ό 더 pop ν•΄μ„œ rhs둜 λ§Œλ“ λ‹€. 잘λͺ»λœ 연산식은 주어지지 μ•ŠκΈ° λ•Œλ¬Έμ— 항상 μˆ«μžκ°€ λ‚˜μ˜΅λ‹ˆλ‹€.
      3. lhs와 rhs에 λŒ€ν•΄ κΊΌλ‚Έ μ—°μ‚°μžλ‘œ 연산을 μˆ˜ν–‰ν•΄μ„œ μ—°μ‚° κ²°κ³Όλ₯Ό λ‹€μ‹œ μŠ€νƒμ— λ„£λŠ”λ‹€.
    2. ν˜„μž¬ μš°μ„ μˆœμœ„κ°€ κ°€μž₯ 높은 μ—°μ‚°μžκ°€ μ•„λ‹ˆλΌλ©΄
      1. μŠ€νƒμ— κ·ΈλŒ€λ‘œ λ„£λŠ”λ‹€.
  6. μŠ€νƒμ— μ €μž₯된 값은 μš°μ„ μˆœμœ„κ°€ κ°€μž₯ 높은 μ—°μ‚°μžλ₯Ό κ³„μ‚°ν•œ 식이기 λ•Œλ¬Έμ— μŠ€νƒμ— μžˆλŠ” 식을 ν˜„μž¬ μ‹μœΌλ‘œ μΉ˜ν™˜ν•œλ‹€. 
  7. 가지고 μžˆλŠ” μ—°μ‚°μžλ₯Ό μš°μ„ μˆœμœ„λŒ€λ‘œ λ‹€ μ‚¬μš©ν•  λ•ŒκΉŒμ§€ 1 ~ 6번 과정을 λ°˜λ³΅ν•œλ‹€.

μœ„ μž‘μ—…μ„ κ΅¬ν•œ λͺ¨λ“  μ—°μ‚°μž 쑰합에 λŒ€ν•΄μ„œ μˆ˜ν–‰ν•˜κ³ , 각 μ‘°ν•©μ˜ 연산이 끝날 λ•Œλ§ˆλ‹€ μ ˆλŒ€κ°’μœΌλ‘œ μ΅œλŒ€κ°’μ„ μ—…λ°μ΄νŠΈν•˜λ©΄ 닡을 찾을 수 μžˆμŠ΅λ‹ˆλ‹€.

 

for combination in operatorCombinations {
        var currentExpression = separatedExpression
        var result = 0
        for op in combination {
            var stack: [String] = []
            while !currentExpression.isEmpty {
                var next = currentExpression.removeFirst()
                if !stack.isEmpty && op == next {
                    let lhs = Int(stack.removeLast())!
                    let rhs = Int(currentExpression.removeFirst())!
                    next = String(stringToOperator(op: op)(lhs, rhs))
                }
                stack.append(next)
            }
            currentExpression = stack
            result = Int(currentExpression.last!)!
        }
        answer = max(answer, abs(result))
    }

μ½”λ“œ