力扣高頻|算法面試題彙總(四):堆、棧與隊列

力扣高頻|算法面試題彙總(四):堆、棧與隊列

力扣鏈接
目錄:

  • 1.最小棧
  • 2.數組中的第K個最大元素
  • 3.數據流的中位數
  • 4.有序矩陣中第K小的元素
  • 5.前 K 個高頻元素
  • 6.滑動窗口最大值
  • 7.基本計算器 II
  • 8.扁平化嵌套列表迭代器
  • 9.逆波蘭表達式求值

1.最小棧

設計一個支持 push ,pop ,top 操作,並能在常數時間內檢索到最小元素的棧。
push(x) —— 將元素 x 推入棧中。
pop() —— 刪除棧頂的元素。
top() —— 獲取棧頂元素。
getMin() —— 檢索棧中的最小元素。
示例:
輸入:
[“MinStack”,“push”,“push”,“push”,“getMin”,“pop”,“top”,“getMin”]
[[],[-2],[0],[-3],[],[],[],[]]
輸出:
[null,null,null,null,-3,null,0,-2]
解釋:
MinStack minStack = new MinStack();
minStack.push(-2);
minStack.push(0);
minStack.push(-3);
minStack.getMin(); --> 返回 -3.
minStack.pop();
minStack.top(); --> 返回 0.
minStack.getMin(); --> 返回 -2.
提示:
pop、top 和 getMin 操作總是在 非空棧 上調用。

C++

class MinStack {
private:
    vector<int> nums;
public:
    /** initialize your data structure here. */
    MinStack() {

    }
    
    void push(int x) {

        nums.push_back(x);
    }
    
    void pop() {
        nums.pop_back();
    }
    
    int top() {
        return nums[nums.size() - 1];
    }
    
    int getMin() {
        int min = nums[0];
        for(auto num : nums){
            if(num < min)
                min = num;
        }
        return min;
    }
};

/**
 * Your MinStack object will be instantiated and called as such:
 * MinStack* obj = new MinStack();
 * obj->push(x);
 * obj->pop();
 * int param_3 = obj->top();
 * int param_4 = obj->getMin();
 */

Python

class MinStack:
    def __init__(self):
        """
        initialize your data structure here.
        """
        self.nums = []
    def push(self, x: int) -> None:
        self.nums.append(x)
    def pop(self) -> None:
        self.nums.pop()
    def top(self) -> int:
        return self.nums[len(self.nums) - 1]
    def getMin(self) -> int:
        min = self.nums[0]
        for num in self.nums:
            if num < min:
                min = num
        return min
# Your MinStack object will be instantiated and called as such:
# obj = MinStack()
# obj.push(x)
# obj.pop()
# param_3 = obj.top()
# param_4 = obj.getMin()

2.數組中的第K個最大元素

在未排序的數組中找到第 k 個最大的元素。請注意,你需要找的是數組排序後的第 k 個最大的元素,而不是第 k 個不同的元素。
示例 1:
輸入: [3,2,1,5,6,4] 和 k = 2
輸出: 5
示例 2:
輸入: [3,2,3,1,2,4,5,5,6] 和 k = 4
輸出: 4
說明:
你可以假設 k 總是有效的,且 1 ≤ k ≤ 數組的長度。

思路1:
排序後查找。
使用默認排序算法的複雜度:算法的時間複雜度爲 O(NlogN)O(Nlog N),空間複雜度爲 O(1)O(1)
C++

class Solution {
public:
    int findKthLargest(vector<int>& nums, int k) {
        sort(nums.begin(), nums.end());
        return nums[nums.size() - k];
    }
};

Python

class Solution:
    def findKthLargest(self, nums: List[int], k: int) -> int:
        nums = sorted(nums)
        return nums[len(nums) - k]

思路2:
參考官方思路,使用大頂堆,保留k個最大的數。
向大小爲 k 的堆中添加元素的時間複雜度爲O(logk)O(logk),我們將重複該操作 N 次,故總時間複雜度爲 {O}(N \log k)O(Nlogk)。
在 Python 的 heapq 庫中有一個 nlargest 方法,具有同樣的時間複雜度,能將代碼簡化到只有一行。
C++

class Solution {
public:
    int findKthLargest(vector<int>& nums, int k) {
        priority_queue<int,vector<int>,greater<int>> q;
        for(auto it:nums){
            q.push(it);
            if(q.size()>k) q.pop();
        }
        return q.top();
    }
};

Python

class Solution:
    def findKthLargest(self, nums, k):
        """
        :type nums: List[int]
        :type k: int
        :rtype: int
        """
        return heapq.nlargest(k, nums)[-1]

3.數據流的中位數

中位數是有序列表中間的數。如果列表長度是偶數,中位數則是中間兩個數的平均值。
例如,
[2,3,4] 的中位數是 3
[2,3] 的中位數是 (2 + 3) / 2 = 2.5
設計一個支持以下兩種操作的數據結構:
void addNum(int num) - 從數據流中添加一個整數到數據結構中。
double findMedian() - 返回目前所有元素的中位數。
示例:
addNum(1)
addNum(2)
findMedian() -> 1.5
addNum(3)
findMedian() -> 2
進階:
如果數據流中所有整數都在 0 到 100 範圍內,你將如何優化你的算法?
如果數據流中 99% 的整數都在 0 到 100 範圍內,你將如何優化你的算法?

思路1:
暴力法,每次獲取中位數時就進行排序獲取,超時
思路2:
使用最大堆和最小堆,參考劍指offer:數據流中的中位數
C++

class MedianFinder {
private:
    // 最大堆
    vector<int> maxheap;
    // 最小堆
    vector<int> minheap;
public:
    /** initialize your data structure here. */
    MedianFinder() {
        
    }
    void addNum(int num) {
       int size = maxheap.size() + minheap.size();
        // 如果當前數目是偶數個,默認把num放進最小堆
        if((size & 1) == 0){
            int temp = num;
            //如果最大堆不爲空,且輸入的數字小於最大堆的最大值
            if(!maxheap.empty() && num < maxheap[0]){
                // 把最大的數字拿出來
                temp = maxheap[0];
                // 再把數字放進最大堆
                maxheap[0] = num;
                // 重新生成最大堆
                make_heap(maxheap.begin(), maxheap.end());
            }
            // 把元素放進最小堆
            minheap.push_back(temp);
            // 重新生成最小堆
            push_heap(minheap.begin(), minheap.end(), greater<int>());
        }else{// 如果當前數目是奇數個,默認把num放進最大堆
            int temp = num;
            // 如果最小堆不爲空,且輸入的數字大於最小堆的最小值
            if(!minheap.empty() && num > minheap[0]){
                temp = minheap[0]; // 把最小的數字拿出來
                minheap[0] = num; // 把輸入的數字放進最小堆
                make_heap(minheap.begin(), minheap.end(), greater<int>());
            }
            // 把元素放進最大堆
            maxheap.push_back(temp);
            // 重新生成最大堆
            push_heap(maxheap.begin(), maxheap.end());
        }
    }
    
    double findMedian() {
        int size = maxheap.size() + minheap.size();
        double res;
        if(size & 1){
            res = minheap[0];
        }else{
            res = (maxheap[0] + minheap[0])*0.5;
        }
        return res;
    }
};

很迷,在最後一個測試用例超時了,所以參考官方實現。

class MedianFinder {
    priority_queue<int> maxheap;                              // 最大堆 降序
    priority_queue<int, vector<int>, greater<int>> minheap;   // 最小堆 升序

public:
    // Adds a number into the data structure.
    void addNum(int num)
    {
        maxheap.push(num);                                    // 把數字添加到最大堆中

        minheap.push(maxheap.top());                          // 把最大堆的最大值放進最小堆中
        maxheap.pop();                                        // 彈出最大堆最大值
        // 如果最大堆的元素個數小於最小堆的個數
        if (maxheap.size() < minheap.size()) {                // maintain size property
            maxheap.push(minheap.top());                      // 把最小堆的最小值放進最大堆
            minheap.pop();                                    // 彈出最小堆最小值
        }
    }
    // Returns the median of current data stream
    double findMedian()
    {   // 默認最大堆的元素個數大於最小堆元素個數 
        return maxheap.size() > minheap.size() ? (double) maxheap.top() : (maxheap.top() + minheap.top()) * 0.5;
    }
};

Python

class MedianFinder:
    def __init__(self):
        """
        initialize your data structure here.
        """
        self.minheap = [] # 最小堆
        self.maxheap = [] # 最大堆   
    def addNum(self, num: int) -> None:
        # 默認把元素添加到最大堆
        heapq.heappush(self.maxheap, (-num, num)) # python默認最小堆,模擬最大堆
        # 把最大堆最大值元素給最小堆
        heapq.heappush(self.minheap, self.maxheap[0][1])
        # 彈出最大堆的最大值
        heapq.heappop(self.maxheap)
        # 如果最大堆的元素個數少於最小堆數量,把最小堆的最小值給最大堆
        if len(self.maxheap) < len(self.minheap):
            heapq.heappush(self.maxheap, (-self.minheap[0], self.minheap[0]))
            heapq.heappop(self.minheap)
            
    def findMedian(self) -> float:
        size = len(self.minheap) + len(self.maxheap)
        # 如果是奇數
        if size & 1:
            return self.maxheap[0][1]
        else:
            return (self.maxheap[0][1] + self.minheap[0])*0.5

4.有序矩陣中第K小的元素

給定一個 n x n 矩陣,其中每行和每列元素均按升序排序,找到矩陣中第k小的元素。
請注意,它是排序後的第 k 小元素,而不是第 k 個不同的元素。
示例:
matrix = [
[ 1, 5, 9],
[10, 11, 13],
[12, 13, 15]
],
k = 8,
返回 13。
提示:
你可以假設 k 的值永遠是有效的, 1 ≤ k ≤ n2 。

思路1:
使用堆排序,時間複雜度爲O(n2log(k))O(n^2log(k)),空間複雜度爲O(k)O(k)用最大堆保存最小的k個數,堆頂就是第k小的數。由於矩陣大小是有順序的,還可以有優化空間:如果該行元素大於堆頂,則可以直接中斷該循環,因爲不可能還存在比堆頂還小的元素,進入下一個循環。
C++

class Solution {
public:
    int kthSmallest(vector<vector<int>>& matrix, int k) {
        // 創建大頂堆,保存最小的k個元素
        priority_queue<int> maxheap; 
        for(int col = 0; col < matrix[0].size(); ++col)
            for(int row = 0; row < matrix.size(); ++row){
                if(maxheap.size() < k ){
                    // 放進元素
                    maxheap.push(matrix[row][col]);
                }else if(maxheap.top() > matrix[row][col]){// 如果矩陣元素小於最大堆的最大值
                    // 彈出最大值
                    maxheap.pop();
                    maxheap.push(matrix[row][col]); 
                }else{// 矩陣每行是從小到大,則右邊的元素不可能還小於最大堆最大值
                    break;
                }
            }
        return maxheap.top();        
    }
};

Python

class Solution:
    def kthSmallest(self, matrix: List[List[int]], k: int) -> int:
        # 最大堆
        maxheap = [] # 最大堆  
        for row in range(len(matrix)):
            for col in range(len(matrix[0])):
                if len(maxheap) < k:
                    heapq.heappush(maxheap, (-matrix[row][col], matrix[row][col])) # python默認最小堆,模擬最大堆
                elif maxheap[0][1] > matrix[row][col]:
                    # 彈出最大堆的最大值
                    heapq.heappop(maxheap)
                    # 添加元素
                    heapq.heappush(maxheap, (-matrix[row][col], matrix[row][col]))
                else:
                    break
        return maxheap[0][1]

思路2
二分法。參考思路如下:
首先第k大數一定落在[l, r]中,其中l = matrix[0][0], r = matrix[row - 1][col - 1].
我們二分值域[l, r]區間,mid = (l + r) >> 1, 對於mid,檢查矩陣中有多少元素小於等於mid,記個數爲cnt,那麼有:

  • 1、如果cnt < k, 那麼[l, mid]中包含矩陣元素個數一定小於k,那麼第k小元素一定不在[l, mid]中,必定在[mid +1, r]中,所以更新l = mid + 1.
  • 2、否則cnt >= k,那麼[l, mid]中包含矩陣元素個數就大於等於k,即第k小元素一定在[l,mid]區間中,更新r = mid;

算法時間複雜度爲O(nlog(m))O(n * log(m)), 其中n = max(row, col),代表矩陣行數和列數的最大值, m代表二分區間的長度,即矩陣最大值和最小值的差。
C++

class Solution {
public:
    int kthSmallest(vector<vector<int>>& matrix, int k) {
        int rows = matrix.size();
        int cols = matrix[0].size();
        // 使用二分法
        int low = matrix[0][0];
        int high = matrix[rows - 1][cols - 1];
        while(low < high){
            int mid = low + (high - low)/2;
            int count = findCount(matrix, mid);
            // 如果比mid小的數字小於k, 說明第k小的數字大於當前mid
            if(count < k)
                low = mid + 1;
            else
                high = mid;      
        }
        return low;  
    }
    int findCount(vector<vector<int>>& matrix, int mid){
        // 利用矩陣特性從左小角開始查找
        int count = 0;
        int rows = matrix.size();
        int cols = matrix[0].size();
        int row = rows-1;
        int col = 0;
        while( row >= 0 && col <= cols - 1){
            if(matrix[row][col] > mid){
                // 先減行數
                --row;
            }else{// 跳過這一列
                count += row+1;
                // 移動
                ++col;
            }
        }
        return count;   
    }
};

Python

class Solution:
    def kthSmallest(self, matrix: List[List[int]], k: int) -> int:
        # 二分法
        low = matrix[0][0]
        rows = len(matrix)
        cols = len(matrix[0])
        high = matrix[rows - 1][cols - 1]
        while low < high:
            mid = low + (high - low)/2
            count = self.findCount(matrix , mid)
            if count < k:
                low = mid + 1
            else:
                high = mid
        return int(low)
    def findCount(self, matrix , mid):
            rows = len(matrix)
            cols = len(matrix[0])
            col = 0
            row = rows - 1
            count = 0
            while row >= 0 and col <= cols - 1:
                if matrix[row][col] > mid:
                    row -= 1
                else:
                    count += row + 1
                    col += 1
            return count               

5.前 K 個高頻元素

給定一個非空的整數數組,返回其中出現頻率前 k 高的元素。
示例 1:
輸入: nums = [1,1,1,2,2,3], k = 2
輸出: [1,2]
示例 2:
輸入: nums = [1], k = 1
輸出: [1]
提示:
你可以假設給定的 k 總是合理的,且 1 ≤ k ≤ 數組中不相同的元素的個數。
你的算法的時間複雜度必須優於 O(n log n) , n 是數組的大小。
題目數據保證答案唯一,換句話說,數組中前 k 個高頻元素的集合是唯一的。
你可以按任意順序返回答案。

思路:
首先使用哈希表記錄每個數字出現的頻率,解這使用最小堆進行存儲數字出現的頻率,用來保存前k個高頻元素出現的頻率。
C++

class Solution {
public:
    vector<int> topKFrequent(vector<int>& nums, int k) {
        // 用哈希表存儲每個id出現的次數
        unordered_map<int, int> idCount;
        for(auto num : nums){
            if(idCount.find(num) == idCount.end())
                idCount[num] = 1;
            else
                ++idCount[num];         
        }
        // 使用最小堆來保存出現頻率最高的k個元素
        vector<int> minheap;
        
        for(auto x : idCount){
            minheap.push_back(x.second);
            // 當已建堆的容器範圍內有新的元素插入末尾後,應當調用push_heap將該元素插入堆中。
            push_heap(minheap.begin(), minheap.end(), greater<int>());
            if(minheap.size() > k){
                // 將堆頂(所給範圍的最前面)元素移動到所給範圍的最後,並且將新的最小值置於所給範圍的最前面
                pop_heap(minheap.begin(), minheap.end(), greater<int>());
                // 彈出最小堆最小的那個元素
                minheap.pop_back();
            }
        }
        vector<int> ans;
        for(auto x : idCount){
            // 在最小堆中招對應的id,以及保證結果不存在這個數字,以免重複記錄
            if(find(minheap.begin(), minheap.end(), x.second) != minheap.end() && find(ans.begin(), ans.end(), x.first) == ans.end()){
                ans.push_back(x.first);
            }
        }
        return ans;
    }
};

Python:

class Solution:
    def topKFrequent(self, nums: List[int], k: int) -> List[int]:
        idHash = dict()
        for num in nums:
            if not num in idHash:
                idHash[num] = 1
            else:
                idHash[num] += 1
        # 建立最小堆 
        minheap = []
        for key in idHash:
            
            heapq.heappush(minheap, (idHash[key], key))
            if len(minheap) > k:
                # 彈出
                heapq.heappop(minheap)
                # 變最小堆
                # heapq.heapify(minheap)
                
        ans = []
        for value, key in minheap:
            ans.append(key)
        
        return ans

6.滑動窗口最大值

給定一個數組 nums,有一個大小爲 k 的滑動窗口從數組的最左側移動到數組的最右側。你只可以看到在滑動窗口內的 k 個數字。滑動窗口每次只向右移動一位。
返回滑動窗口中的最大值。
進階:
你能在線性時間複雜度內解決此題嗎?
示例:
輸入: nums = [1,3,-1,-3,5,3,6,7], 和 k = 3
輸出: [3,3,5,5,6,7]
解釋:
滑動窗口的位置 最大值
[1 3 -1] -3 5 3 6 7 3
1 [3 -1 -3] 5 3 6 7 3
1 3 [-1 -3 5] 3 6 7 5
1 3 -1 [-3 5 3] 6 7 5
1 3 -1 -3 [5 3 6] 7 6
1 3 -1 -3 5 [3 6 7] 7
提示:
1 <= nums.length <= 10^5
-10^4 <= nums[i] <= 10^4
1 <= k <= nums.length

這題劍指offer做過,具體思路見劍指offer|解析和答案(C++/Python) (五)上:滑動窗口最大值
C++

class Solution {
public:
    vector<int> maxSlidingWindow(vector<int>& nums, int k) {
        vector<int> maxvalue;
        // 新建隊列進行保存最大值的索引
        deque<int> index;
        for(int i = 0; i < k; ++i){
            // 確保索引的值是保留的最大值
            while(!index.empty() && nums[i]>= nums[index.back()])
                index.pop_back();
            // 添加索引
            index.push_back(i);
        }
        for(int i = k; i < nums.size(); ++i){
            // 添加最大值
            maxvalue.push_back(nums[index.front()]);
            // 確保索引的值是保留的最大值
            while(!index.empty() && nums[i]>= nums[index.back()])
                index.pop_back();
            // 如果最大值溢出滑動框
            if(!index.empty() && index.front() <= (i - k))
                index.pop_front();
            index.push_back(i);
        }
        // 加入最後一個值
        maxvalue.push_back(nums[index.front()]);
        return maxvalue;
    }
};

Python

class Solution:
    def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
        maxValue = list()
        if len(nums) > 0 and k > 0:
            index = []
            for i in range(k):
                while len(index) > 0 and nums[i] >= nums[index[-1]]:
                    index.pop()
                index.append(i)
                
            for i in range(k, len(nums)):
                maxValue.append(nums[index[0]])
                while len(index) > 0 and nums[i] >= nums[index[-1]]:
                    index.pop()
                if len(index) > 0 and index[0] <= (i-k):
                    index.pop(0)
                index.append(i)
            maxValue.append(nums[index[0]])
        return maxValue

7.基本計算器 II

實現一個基本的計算器來計算一個簡單的字符串表達式的值。
字符串表達式僅包含非負整數,+, - ,,/ 四種運算符和空格 。 整數除法僅保留整數部分。
示例 1:
輸入: "3+2
2"
輸出: 7
示例 2:
輸入: " 3/2 "
輸出: 1
示例 3:
輸入: " 3+5 / 2 "
輸出: 5
說明:
你可以假設所給定的表達式都是有效的。
請不要使用內置的庫函數 eval。

思路:
參考使用棧的方式來保存計算結果。利用棧的方式解決運算優先級的問題 當爲加減時放入棧中 當爲乘除時講棧頂元素與最近獲得一個數進行運算,同時把棧頂元素彈出,放進計算之後的元素。最後把棧的所有元素加起來即可。
C++

class Solution {
public:
    int calculate(string s) {
        long result = 0;
        long num = 0;
        // 初始上一個運算符爲加法 上個數字爲0
        char op = '+';
        char c;
        // 用棧來保存結果
        vector<int> stack;
        for(int i = 0; i < s.length(); ++i){
            c = s[i];
            if(c >='0'){
                // 計算數字
                num = num * 10 + c- '0';
            }
            // 當遇到符號時,或者是到了字符串末尾
            if(c < '0' && c != ' '|| i == s.length() -1){
                // 此時op是上一次遇到的符號
                if(op == '+') stack.push_back(num);
                if(op == '-') stack.push_back(-num);
                if(op == '*' || op =='/'){
                    int temp = (op == '*')? stack.back() * num : stack.back()/num;
                    // 彈出上一個值
                    stack.pop_back();
                    // 重新放進計算的結果
                    stack.push_back(temp);       
                }
                // 獲取當前op符號
                op = s[i];
                num = 0;
            }
        }
        while(!stack.empty()){
            result += stack.back();
            stack.pop_back();
        }
        return result;       
    }
};

Python

class Solution:
    def calculate(self, s: str) -> int:
        stack = []
        num = 0
        res = 0
        op = '+'
        ops = ['+', '-', '*', '/']
        for i in range(len(s)):
            # s[i] != ' ' 很重要
            if not s[i] in ops and  s[i] != ' ':
                num = num*10 + int(s[i]) 
            if s[i] in ops and s[i] != ' ' or i == len(s) - 1:
                if op == '+':
                    stack.append(num)
                if op == '-':
                    stack.append(-num)
                if op == '*' :
                    temp = stack[-1]*num 
                    stack.pop()
                    stack.append(int(temp))
                if op == '/':
                    temp = stack[-1]/num 
                    stack.pop()
                    stack.append(int(temp))                            
                num = 0
                op = s[i]
        for num in stack:
            res += num
            
        return res

8.扁平化嵌套列表迭代器

扁平化嵌套列表迭代器
給你一個嵌套的整型列表。請你設計一個迭代器,使其能夠遍歷這個整型列表中的所有整數。
列表中的每一項或者爲一個整數,或者是另一個列表。其中列表的元素也可能是整數或是其他列表。
示例 1:
輸入: [[1,1],2,[1,1]]
輸出: [1,1,2,1,1]
解釋: 通過重複調用 next 直到 hasNext 返回 false,next 返回的元素的順序應該是: [1,1,2,1,1]。
示例 2:
輸入: [1,[4,[6]]]
輸出: [1,4,6]
解釋: 通過重複調用 next 直到 hasNext 返回 false,next 返回的元素的順序應該是: [1,4,6]。

這題沒怎麼看明白,先放一下。
C++

class NestedIterator {
private:
    stack<NestedInteger> s;
public:
    NestedIterator(vector<NestedInteger> &nestedList) {
        // 添加元素
        for(int i = nestedList.size() - 1; i >= 0; --i)
            s.push(nestedList[i]);
    }
    
    int next() {
        NestedInteger temp = s.top(); // 獲取棧頂元素
        s.pop(); // 彈出棧頂
        return temp.getInteger();
    }
    
    bool hasNext() {
        while(!s.empty()){
            NestedInteger temp = s.top();
            if(temp.isInteger())
                return true;
            s.pop();
            for(int i = temp.getList().size() - 1; i >= 0; --i)
                s.push(temp.getList()[i]);
        }
        return false;
    }
};

還有其他思路:C++ 綜合各路大佬的答案
Python:
來自:棧+迭代,5行代碼簡單易理解

class NestedIterator:
    def __init__(self, nestedList: [NestedInteger]):
        # 對於nestedList中的內容,我們需要從左往右遍歷,
        # 但堆棧pop是從右端開始,所以我們壓棧的時候需要將nestedList反轉再壓棧
        self.stack = nestedList[::-1]

    def next(self) -> int:
        # hasNext 函數中已經保證棧頂是integer,所以直接返回pop結果
        return self.stack.pop(-1).getInteger()

    def hasNext(self) -> bool: 
        # 對棧頂進行‘剝皮’,如果棧頂是List,把List反轉再依次壓棧,
        # 然後再看棧頂,依次循環直到棧頂爲Integer。
        # 同時可以處理空的List,類似[[[]],[]]這種test case           
        while len(self.stack) > 0 and self.stack[-1].isInteger() is False:
            self.stack += self.stack.pop().getList()[::-1]
        return len(self.stack) > 0

9.逆波蘭表達式求值

根據逆波蘭表示法,求表達式的值。
有效的運算符包括 +, -, , / 。每個運算對象可以是整數,也可以是另一個逆波蘭表達式。
說明:
整數除法只保留整數部分。
給定逆波蘭表達式總是有效的。換句話說,表達式總會得出有效數值且不存在除數爲 0 的情況。
示例 1:
輸入: [“2”, “1”, “+”, “3”, "
"]
輸出: 9
解釋: ((2 + 1) * 3) = 9
示例 2:
輸入: [“4”, “13”, “5”, “/”, “+”]
輸出: 6
解釋: (4 + (13 / 5)) = 6

思路:
這個在《大話數據結構上》看到過。使用數據結構。規則:從左到右遍歷表達式的每個數字和符號,遇到是數字就進棧,遇到是符號,就將處於棧頂的兩個數字彈出,進行運算,運算結果進錢, 直到最終獲得結果。
舉例後綴表達式:931 - 3*+102 / +,以下圖片來自《大話數據結構上》:
在這裏插入圖片描述在這裏插入圖片描述在這裏插入圖片描述在這裏插入圖片描述在這裏插入圖片描述
C++

class Solution {
public:
    int evalRPN(vector<string>& tokens) {
        // 用棧來存儲數字
        vector<int> nums;
        for(int i = 0; i < tokens.size(); ++i){
            if(tokens[i] != "+" && tokens[i] != "-" && tokens[i] != "*" && tokens[i] != "/"){
                nums.push_back(stoi(tokens[i]));
            }else if(tokens[i] == "+"){
                int add1 = nums.back();
                nums.pop_back();
                int add2 = nums.back();
                nums.pop_back();
                add2 = add2 + add1;
                nums.push_back(add2);
            }else if(tokens[i] == "-"){
                int sub1 = nums.back();
                nums.pop_back();
                int sub2 = nums.back();
                nums.pop_back();
                sub2 = sub2 - sub1;
                nums.push_back(sub2);
            }else if(tokens[i] == "*"){
                int mul1 = nums.back();
                nums.pop_back();
                int mul2 = nums.back();
                nums.pop_back();    
                mul2 = mul2 * mul1;
                nums.push_back(mul2);
            }else if(tokens[i] == "/"){
                int div1 = nums.back();
                nums.pop_back();
                int div2 = nums.back();
                nums.pop_back();
                div2 = div2 / div1;
                nums.push_back(div2);
            }       
        }
    return nums[0];
    }
};

還有範例,很優美:

class Solution {
public:
    int evalRPN(vector<string>& tokens) {
        if(tokens.size()==0) return 0;
        stack<int> s;
        int temp=0;
        for(int i=0;i<tokens.size();i++){
            if(tokens[i][0]<='9'&&tokens[i][0]>='0'||(tokens[i].size()>1&&tokens[i][0]=='-')){
                s.push(atoi(tokens[i].c_str()));
            }else{
                int a=s.top();
                s.pop();
                int b=s.top();
                s.pop();
                if(tokens[i][0]=='+') temp=a+b;
                if(tokens[i][0]=='-') temp=b-a;
                if(tokens[i][0]=='*') temp=a*b;
                if(tokens[i][0]=='/') temp=b/a;
                s.push(temp);
            }
        }
        return s.top();
    }
};

Python:

class Solution:
    def evalRPN(self, tokens: List[str]) -> int:            
        nums = []
        ops = ["+", "-", "*", "/"]
        for i in range(len(tokens)):
            if not tokens[i] in ops:
                nums.append(int(tokens[i]))
            elif tokens[i] == "+":
                add1, add2 = nums[-2], nums[-1]
                nums.pop()
                nums.pop()
                add1 = add1 + add2
                nums.append(int(add1))
            elif tokens[i] == "-":
                sub1, sub2 = nums[-2], nums[-1]
                nums.pop()
                nums.pop()
                sub1 = sub1 - sub2
                nums.append(int(sub1))
            elif tokens[i] == "*":
                mul1, mul2 = nums[-2], nums[-1]
                nums.pop()
                nums.pop()
                mul1 = mul1 * mul2
                nums.append(int(mul1))
            elif tokens[i] == "/":
                div1, div2 = nums[-2], nums[-1]
                nums.pop()
                nums.pop()
                div1 = div1 / div2
                nums.append(int(div1))
        return nums[0]
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章