力扣高频|算法面试题汇总(四):堆、栈与队列

力扣高频|算法面试题汇总(一):开始之前
力扣高频|算法面试题汇总(二):字符串
力扣高频|算法面试题汇总(三):数组
力扣高频|算法面试题汇总(四):堆、栈与队列
力扣高频|算法面试题汇总(五):链表
力扣高频|算法面试题汇总(六):哈希与映射
力扣高频|算法面试题汇总(七):树
力扣高频|算法面试题汇总(八):排序与检索
力扣高频|算法面试题汇总(九):动态规划
力扣高频|算法面试题汇总(十):图论
力扣高频|算法面试题汇总(十一):数学&位运算

力扣高频|算法面试题汇总(四):堆、栈与队列

力扣链接
目录:

  • 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 ( N l o g N ) O(Nlog N) O(NlogN),空间复杂度为 O ( 1 ) 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 ( l o g 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 ( n 2 l o g ( k ) ) O(n^2log(k)) O(n2log(k)),空间复杂度为 O ( 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 ( n ∗ l o g ( m ) ) O(n * log(m)) O(nlog(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]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值