[Programmers] Lv2. μˆ˜μ‹ μ΅œλŒ€ν™” | C++

2023. 6. 8. 22:08ㆍCoding Test/Programmers

πŸ”—λ¬Έμ œ λ³΄λŸ¬κ°€κΈ°
 

ν”„λ‘œκ·Έλž˜λ¨ΈμŠ€

μ½”λ“œ μ€‘μ‹¬μ˜ 개발자 μ±„μš©. μŠ€νƒ 기반의 ν¬μ§€μ…˜ 맀칭. ν”„λ‘œκ·Έλž˜λ¨ΈμŠ€μ˜ 개발자 λ§žμΆ€ν˜• ν”„λ‘œν•„μ„ λ“±λ‘ν•˜κ³ , λ‚˜μ™€ 기술 ꢁ합이 잘 λ§žλŠ” 기업듀을 맀칭 λ°›μœΌμ„Έμš”.

programmers.co.kr

 

πŸ‘¨‍πŸ’»ν’€μ΄ κ³Όμ •

 

자료ꡬ쑰 μ‹œκ°„μ— μ „μœ„ν‘œκΈ°μ‹(Prefix), μ€‘μœ„ν‘œκΈ°μ‹(Infix), ν›„μœ„ν‘œκΈ°μ‹(Postfix)에 λŒ€ν•΄ 배운 적이 μžˆμœΌλ‚˜, μ‹œκ°„μ΄ μ˜€λž˜λ˜μ–΄ 기얡이 잘 μ•ˆ λ‚˜λ”λΌκ΅¬μš”. κ·Έλž˜μ„œ λ‹€μ‹œ ν•œ 번 μ°Ύμ•„λ΄€μŠ΅λ‹ˆλ‹€.

 

μ»΄νŒŒμΌλŸ¬κ°€ μ—°μ‚°μž μš°μ„ μˆœμœ„μ— 따라 μ€‘μœ„ν‘œκΈ°μ‹μ„ ν›„μœ„ν‘œκΈ°μ‹μœΌλ‘œ λ³€ν™˜ν•œ 후에, 계산을 μ§„ν–‰ν•œλ‹€κ³  ν•˜λ”λΌκ΅¬μš”. μˆ²μ„ 보지 λͺ»ν•˜κ³  λ‚˜λ¬΄λ§Œ λ³Ό 수 μžˆλŠ” 컴퓨터 μž…μž₯에선 μˆ˜μ‹μ„ μ™Όμͺ½μ—μ„œ 였λ₯Έμͺ½μœΌλ‘œ μ°¨λ‘€λŒ€λ‘œ 읽어가며 κ³„μ‚°ν•˜λŠ” 게 νŽΈν•˜μ£ . 그에 λ°˜ν•΄, μ‚¬λžŒμ€ μˆ²μ„ λ³Ό 수 μžˆμŠ΅λ‹ˆλ‹€. 눈으둜 전체 μˆ˜μ‹μ„ ν•œ λ²ˆμ— λ³Ό 수 있기 λ•Œλ¬Έμ΄μ£ .

 

λ”°λΌμ„œ, μ€‘μœ„ν‘œκΈ°μ‹μ„ ν›„μœ„ν‘œκΈ°μ‹μœΌλ‘œ λ°”κΎΈλŠ” 과정을 진행해야 ν•©λ‹ˆλ‹€. 그리고, μ—°μ‚°μž μš°μ„ μˆœμœ„ μˆœμ—΄λ„ λ§Œλ“€μ–΄μ•Ό ν•˜μ£ .

μ €λŠ” λ‹€μŒκ³Ό 같은 μˆœμ„œλŒ€λ‘œ μ§„ν–‰ν–ˆμŠ΅λ‹ˆλ‹€.

 

 

1. 주어진 μˆ˜μ‹μ„ ν”Όμ—°μ‚°μž, μ—°μ‚°μž λ³„λ‘œ 토큰화

 

μ˜ˆμ œμ—μ„œ 주어진 μž…λ ₯ "100-200*300-500+20"으둜 보자면, ["100", "-", "200", "*", "300", "-", "500", "+", "20"]으둜 각각 뢄리해야 ν•©λ‹ˆλ‹€. λ˜ν•œ, μˆ˜μ‹μ— λ“±μž₯ν•˜λŠ” μ—°μ‚°μžμ˜ μ’…λ₯˜κ°€ 무엇 무엇이 μžˆλŠ”μ§€λ„ μ•Œμ•„λ†”μ•Ό ν•˜μ£ . λ“±μž₯ν•˜λŠ” μ—°μ‚°μžκ°€ μ΅œλŒ€ 3개 뿐이라 3! = 6κ°€μ§€μ˜ μ—°μ‚°μž μš°μ„ μˆœμœ„ 경우의 μˆ˜λ°–μ— μ•ˆ λ‚˜μ˜€μ§€λ§Œ, μ €λŠ” κ·Έ λ§ˆμ €λ„ 쀄이고 μ‹Άμ—ˆμŠ΅λ‹ˆλ‹€.

 

set을 μ΄μš©ν•˜μ—¬ λ“±μž₯ν•˜λŠ” μ—°μ‚°μž μ’…λ₯˜ 수λ₯Ό 쀑볡없이 μ €μž₯해놨고, λΆ„λ¦¬λœ μˆ˜μ‹μ„ 가지고 μžˆλŠ” Expression 클래슀λ₯Ό λ§Œλ“€μ—ˆμŠ΅λ‹ˆλ‹€.

class Expression {
public:
    Expression(const string& expression) {
        string digitBuffer;

        for (const auto element : expression) {
            if (isdigit(element)) {
                digitBuffer.push_back(element);
                continue;
            }

            _operatorTypes.insert(element);
            _splitedExpression.push_back(digitBuffer);

            string _operator;
            _operator.push_back(element);

            _splitedExpression.push_back(_operator);
            digitBuffer.clear();
        }

        _splitedExpression.push_back(digitBuffer);
    }

public:
    vector<string> _splitedExpression;
    set<char> _operatorTypes;
};

 

 

2. μ—°μ‚°μž μš°μ„ μˆœμœ„ μˆœμ—΄ λ§Œλ“€κΈ°

 

λ“±μž₯ν•˜λŠ” μ—°μ‚°μž μ’…λ₯˜ μˆ˜κ°€ μ΅œλŒ€ 3개이기 λ•Œλ¬Έμ— μ΅œλŒ€ 6κ°€μ§€μ˜ 경우의 μˆ˜κ°€ μ‘΄μž¬ν•©λ‹ˆλ‹€. μˆœμ—΄μ„ μ‚¬μš©ν•˜κΈ° μœ„ν•΄ <algorithm> ν—€λ”μ˜ next_permutation()을 μ‚¬μš©ν–ˆλŠ”λ°, μ˜€λ¦„μ°¨μˆœμœΌλ‘œ μ •λ ¬λœ μ‹œν€€μŠ€ μ»¨ν…Œμ΄λ„ˆλ₯Ό λ„£μ–΄μ•Ό ν•¨μˆ˜κ°€ μ˜¬λ°”λ₯΄κ²Œ μž‘λ™ν•©λ‹ˆλ‹€.

 

ν•˜μ§€λ§Œ BST 기반인 set은 순회λ₯Ό μ˜€λ¦„μ°¨μˆœμœΌλ‘œ μ‹œμž‘ν•˜μ£ ! κ·Έλž˜μ„œ set을 μˆœνšŒν•˜λ©° string에 μ°¨λ‘€λŒ€λ‘œ λ‹΄μ•˜κ³ , next_permutation()의 κ²°κ³Όλ₯Ό μ°¨λ‘€λŒ€λ‘œ 결과에 λ‹΄μ•˜μŠ΅λ‹ˆλ‹€.

vector<map<char, int>> GetOperatorsPermutation(set<char> operators) {
    string strOpreators;
    vector<map<char, int>> results;

    for (const auto _operator : operators)
        strOpreators.push_back(_operator);

    do {
        map<char, int> priority;

        for (int i = 0; i < strOpreators.length(); i++)
            priority[strOpreators[i]] = i;

        results.push_back(priority);
    } while (next_permutation(strOpreators.begin(), strOpreators.end()));

    return results;
}

 

 

3. μ€‘μœ„ν‘œκΈ°μ‹μ„ ν›„μœ„ν‘œκΈ°μ‹μœΌλ‘œ λ³€ν™˜ν•˜κΈ°

 

이제 주어진 μ—°μ‚°μž μš°μ„ μˆœμœ„μ™€ 토큰화 된 μ€‘μœ„ν‘œκΈ°μ‹λ“€μ„ λ°”νƒ•μœΌλ‘œ ν›„μœ„ν‘œκΈ°μ‹μ„ λ§Œλ“€λ©΄ λ©λ‹ˆλ‹€. μ΅œμ’… κ²°κ³Όλ₯Ό 담을 vector<string> postFix와 μ—°μ‚°μžλ₯Ό λ‹΄μ•„ λ‘˜ stack<char> operatorsκ°€ ν•„μš”ν•©λ‹ˆλ‹€. ν›„μœ„ν‘œκΈ°μ‹μ„ λ§Œλ“œλŠ” μ•Œκ³ λ¦¬μ¦˜μ€ λ‹€μŒκ³Ό κ°™μ•˜μŠ΅λ‹ˆλ‹€. (πŸ”—μ°Έκ³  λΈ”λ‘œκ·Έ)

 

  1. μˆ«μžλŠ” κ·ΈλŒ€λ‘œ postFix에 μΆ”κ°€
  2. λ§Œμ•½ μŠ€νƒμ΄ λΉ„μ–΄μžˆλ‹€λ©΄ μ—°μ‚°μžλ₯Ό κ·Έλƒ₯ μŠ€νƒμ— λ„£λŠ”λ‹€.
  3. (μŠ€νƒμ˜ top에 μžˆλŠ” μ—°μ‚°μžμ˜ μš°μ„ μˆœμœ„ < ν˜„μž¬ μ—°μ‚°μžμ˜ μš°μ„ μˆœμœ„) 이면 ν˜„μž¬ μ—°μ‚°μžλ₯Ό κ·Έλƒ₯ μŠ€νƒμ— λ„£λŠ”λ‹€.
  4. (μŠ€νƒμ˜ top에 μžˆλŠ” μ—°μ‚°μžμ˜ μš°μ„ μˆœμœ„ >= ν˜„μž¬ μ—°μ‚°μžμ˜ μš°μ„ μˆœμœ„) 이면 2번 ν˜Ήμ€ 3번 상황이 될 λ•ŒκΉŒμ§€ pop ν•˜μ—¬ postFix에 μΆ”κ°€ν•œλ‹€. λ‹€ 끝났닀면 ν˜„μž¬ μ—°μ‚°μžλ₯Ό μŠ€νƒμ— λ„£λŠ”λ‹€.
  5. λͺ¨λ“  μˆ˜μ‹μ„ λ‹€ μ‚¬μš©ν–ˆλ‹€λ©΄, μŠ€νƒμ΄ 빌 λ•ŒκΉŒμ§€ popν•˜μ—¬ postFix에 μΆ”κ°€ν•œλ‹€.
vector<string> ConvertInfixToPostFix(const vector<string>& splitedInfixExpression, const map<char, int>& operatorPriority) {
    vector<string> postFix;
    stack<char> operators;

    for (auto element : splitedInfixExpression) {
        if (isdigit(element[0])) {
            postFix.push_back(element);
            continue;
        }

        if (operators.empty()) {
            operators.push(element[0]);
            continue;
        }

        int currentOpratorPriority = operatorPriority.find(element[0])->second;
        int stackTopOperatorPriority = operatorPriority.find(operators.top())->second;

        if (stackTopOperatorPriority < currentOpratorPriority) {
            operators.push(element[0]);
        }

        else {
            while (true) {
                if (operators.empty())
                    break;

                char targetOperator = operators.top();
                int priority = operatorPriority.find(targetOperator)->second;

                if (priority < currentOpratorPriority)
                    break;

                string strOperator;
                strOperator.push_back(targetOperator);
                postFix.push_back(strOperator);
                operators.pop();
            }

            operators.push(element[0]);
        }
    }

    while (!operators.empty()) {
        char targetOperator = operators.top();
        operators.pop();

        string strOperator;
        strOperator.push_back(targetOperator);
        postFix.push_back(strOperator);
    }

    return postFix;
}

 

 

4. ν›„μœ„ν‘œκΈ°μ‹μ„ κ³„μ‚°ν•˜μ—¬ 이전 계산 결괏값보닀 큰 지 λΉ„κ΅ν•œλ‹€.

 

이제 ν›„μœ„ν‘œκΈ°μ‹μ„ μˆœνšŒν•˜λ©° 계산을 ν•˜λ©΄ λ©λ‹ˆλ‹€. κ³„μ‚°ν•˜λŠ” 과정은 어렡지 μ•Šμ•˜μŠ΅λ‹ˆλ‹€. μ—¬κΈ°μ„œλ„ μˆ«μžμ™€ μ—°μ‚°μžλ₯Ό λ‹΄μ•„ λ‘˜ stack<string>이 ν•„μš”ν•©λ‹ˆλ‹€. 계산 과정은 λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€.

 

  1. μˆ«μžλŠ” μŠ€νƒμ— κ·Έλƒ₯ μΆ”κ°€ν•œλ‹€.
  2. μ—°μ‚°μžκ°€ λ‚˜μ˜€λ©΄ 숫자 2개λ₯Ό pop ν•΄μ„œ κ³„μ‚°ν•œλ‹€.
  3. μ΄λ•Œ λ¨Όμ € pop λ˜λŠ” μˆ«μžκ°€ 두 번째 κ°’, λ‚˜μ€‘μ— popλ˜λŠ” μˆ«μžκ°€ 첫 번째 κ°’μœΌλ‘œ ν•˜μ—¬ 계산해야 ν•œλ‹€. κ³„μ‚°ν•œ 값은 λ‹€μ‹œ μŠ€νƒμ— λ„£λŠ”λ‹€.

 

μœ„ 과정을 ν›„μœ„ν‘œκΈ°μ‹μ΄ 끝날 λ•ŒκΉŒμ§€ μ§„ν–‰ν•˜λ©΄, μŠ€νƒμ— μ΅œμ’… 계산값이 μ €μž₯λ˜μ–΄ μžˆμŠ΅λ‹ˆλ‹€.

long long Calculate(const vector<string>& postFixExpression) {
    stack<string> myStack;

    for (const auto element : postFixExpression) {
        if (isdigit(element[0])) {
            myStack.push(element);
            continue;
        }

        long long num2 = stoll(myStack.top());
        myStack.pop();

        long long num1 = stoll(myStack.top());
        myStack.pop();

        long long result = 0;
        switch (element[0]) {

            case '+':
                result = num1 + num2;
                break;

            case '-':
                result = num1 - num2;
                break;

            case '*':
                result = num1 * num2;
                break;
        }

        myStack.push(to_string(result));
    }

    return abs(stoll(myStack.top()));
}

 

 

✏️ μ†ŒμŠ€ μ½”λ“œ 및 κ²°κ³Ό

#include <set>
#include <map>
#include <stack>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;


class Expression {
public:
    Expression(const string& expression) {
        string digitBuffer;

        for (const auto element : expression) {
            if (isdigit(element)) {
                digitBuffer.push_back(element);
                continue;
            }

            _operatorTypes.insert(element);
            _splitedExpression.push_back(digitBuffer);

            string _operator;
            _operator.push_back(element);

            _splitedExpression.push_back(_operator);
            digitBuffer.clear();
        }

        _splitedExpression.push_back(digitBuffer);
    }

public:
    vector<string> _splitedExpression;
    set<char> _operatorTypes;
};


vector<map<char, int>> GetOperatorsPermutation(set<char> operators) {
    string strOpreators;
    vector<map<char, int>> results;

    for (const auto _operator : operators)
        strOpreators.push_back(_operator);


    do {
        map<char, int> priority;

        for (int i = 0; i < strOpreators.length(); i++)
            priority[strOpreators[i]] = i;

        results.push_back(priority);
    } while (next_permutation(strOpreators.begin(), strOpreators.end()));

    return results;
}


vector<string> ConvertInfixToPostFix(const vector<string>& splitedInfixExpression, const map<char, int>& operatorPriority) {
    vector<string> postFix;
    stack<char> operators;

    for (auto element : splitedInfixExpression) {
        if (isdigit(element[0])) {
            postFix.push_back(element);
            continue;
        }

        if (operators.empty()) {
            operators.push(element[0]);
            continue;
        }

        int currentOpratorPriority = operatorPriority.find(element[0])->second;
        int stackTopOperatorPriority = operatorPriority.find(operators.top())->second;

        if (stackTopOperatorPriority < currentOpratorPriority) {
            operators.push(element[0]);
        }

        else {
            while (true) {
                if (operators.empty())
                    break;

                char targetOperator = operators.top();
                int priority = operatorPriority.find(targetOperator)->second;

                if (priority < currentOpratorPriority)
                    break;

                string strOperator;
                strOperator.push_back(targetOperator);
                postFix.push_back(strOperator);
                operators.pop();
            }

            operators.push(element[0]);
        }
    }

    while (!operators.empty()) {
        char targetOperator = operators.top();
        operators.pop();

        string strOperator;
        strOperator.push_back(targetOperator);
        postFix.push_back(strOperator);
    }

    return postFix;
}


long long Calculate(const vector<string>& postFixExpression) {

    stack<string> myStack;

    for (const auto element : postFixExpression) {
        if (isdigit(element[0])) {
            myStack.push(element);
            continue;
        }

        long long num2 = stoll(myStack.top());
        myStack.pop();

        long long num1 = stoll(myStack.top());
        myStack.pop();

        long long result = 0;
        switch (element[0]) {

            case '+':
                result = num1 + num2;
                break;

            case '-':
                result = num1 - num2;
                break;

            case '*':
                result = num1 * num2;
                break;
        }

        myStack.push(to_string(result));
    }


    return abs(stoll(myStack.top()));
}

long long solution(string expression) {
    Expression myExpression(expression);
    vector<map<char, int>> operatorPriorities = GetOperatorsPermutation(myExpression._operatorTypes);
    long long answer = 0;

    for (const auto priority : operatorPriorities) {
        vector<string> postFix = ConvertInfixToPostFix(myExpression._splitedExpression, priority);
        long long result = Calculate(postFix);

        if (answer < result)
            answer = result;
    }

    return answer;
}

 

 

 

κΈ°λŠ₯λ³„λ‘œ ν•¨μˆ˜λ₯Ό μ΅œλŒ€ν•œ λΉΌλ €κ³  λ…Έλ ₯ 쀑인데, μ½”λ“œ 길이가 였히렀 더 κΈΈμ–΄μ§€λŠ” λŠλ‚Œμ€ λ­˜κΉŒμš”...

 

 

728x90
λ°˜μ‘ν˜•