前端菜鳥的每週一道演算法題(一) - 逆波蘭表示式求值

極客James發表於2019-09-01

閱讀時間預估:8分鐘

什麼是逆波蘭?

來自百度百科的解釋:

逆波蘭表示式又叫做字尾表示式。在通常的表示式中,二元運算子總是置於與之相關的兩個運算物件之間,這種表示法也稱為中綴表示。波蘭邏輯學家J.Lukasiewicz於1929年提出了另一種表示表示式的方法,按此方法,每一運算子都置於其運算物件之後,故稱為字尾表示。

大白話解釋:

給你一組數字,從左向右遍歷,如果遇到+-*/那麼就逆序拿出運算子左邊的2個數字進行運算,運算完之後繼續放裡面,繼續遍歷迴圈,直到結束,前提是要遵守最基本的四則運算。

例如
輸入:["2","1","+",3,"/"]
逆波蘭值為:
(2+1)/3 = 1

輸入:["4","13","5","/","+"]
逆波蘭值為:
4+(13/5) = 6

輸入:["10", "6", "9", "3", "+", "-11", "*", "/", "*", "17", "+", "5", "+"]
逆波蘭值為:
((10 * (6 / ((9 + 3) * -11))) + 17) + 5
= ((10 * (6 / (12 * -11))) + 17) + 5
= ((10 * (6 / -132)) + 17) + 5
= ((10 * 0) + 17) + 5
= (0 + 17) + 5
= 17 + 5
= 22
複製程式碼

下面通過畫圖的方式來分析求逆波蘭值的過程

前端菜鳥的每週一道演算法題(一) - 逆波蘭表示式求值
通過上面的圖,我們可以很清晰的看出其規律,其實就是壓棧,出棧,壓棧,出棧的過程,那麼在JS中陣列的pushpop就可以實現。

程式碼實現過程:

方案一:

var evalRPN = function (tokens) {
    // 定義一個陣列棧
    let stack = [];
    for (let item of tokens) {
        switch (item) {
            case '+':
                let a1 = stack.pop();
                let b1 = stack.pop();
                stack.push(b1 + a1);
                break;
            case '-':
                let a2 = stack.pop();
                let b2 = stack.pop();
                stack.push(b2 - a2);
                break;
            case '*':
                let a3 = stack.pop();
                let b3 = stack.pop();
                stack.push(b3 * a3);
                break;
            case '/':
                let a4 = stack.pop();
                let b4 = stack.pop();
                stack.push(parseInt(b4 / a4));
                break;
            default:
                stack.push(parseInt(item));
        }
    }
    return parseInt(stack.pop());
}
複製程式碼

精簡程式碼封裝一:

<script>
var evalRPN = function (tokens) {
    // 運算規則
    var caculate = function (right, left, operator) {
        switch (operator) {
            case '+':
                return Number(left) + Number(right);
            case '-':
                return Number(left) - Number(right);
            case '*':
                return Number(left) * Number(right);
            default:
                return parseInt(left / right);
        }
    }
    // 判斷是否是 + - * /
    function isOperator(str) {
        return ["+", "-", "*", "/"].includes(str);
    }
    // 定義一個棧用來存放資料
    let stack = [];
    for (item of tokens) {
        // 遍歷傳過來的tokens並通過三目運算來計算值
        isOperator(item) ? stack.push(caculate(stack.pop(), stack.pop(), item)) : stack.push(parseInt(
            item));
    }
    return stack.pop();
}

var data = ["2", "1", "+", "3", "*"];
console.log(evalRPN(data)); 

正確答案:9
</script>
複製程式碼

最終程式碼:

var evalRPN = function (tokens) {
    // 定義一個陣列棧
    let stack = [];
    for (let item of tokens) {
        switch (item) {
            case '+':1 = ;
                stack.push(stack.pop() + stack.pop());
                break;
            case '-':
                stack.push(-stack.pop() + stack.pop());
                break;
            case '*':
                stack.push(stack.pop() * stack.pop());
                break;
            case '/':
                let right = stack.pop();
                stack.push(parseInt(stack.pop() / right));
                break;
            default:
                stack.push(parseInt(item));
        }
    }
    return parseInt(stack.pop());
}
var data = ["2", "1", "+", "3", "*"];
console.log(evalRPN(data));
// 輸出答案為:9
</script>
複製程式碼

小夥伴們可以複製以上程式碼到LeetCode 逆波蘭表示式求值進行驗證,如果您有更好的實現方案,也歡迎留言一起交流和討論。

希望我的分享對你能有幫助,如何對你有所啟發,以程式設計師最高禮遇點贊?評論加轉發的方式來鼓勵我,你的肯定是我前進的最大動力!

如果你想獲取前端整期學習視訊和資料掃一掃下面的二維碼,回覆學習即可免費領取,也希望在前端進階的路上,我們一起成長,一起進步!

前端菜鳥的每週一道演算法題(一) - 逆波蘭表示式求值

相關文章