Leetcode刷题(12) 单调栈的应用

Leetcode刷题(12) 单调栈的应用

具体方法参考: labudadong的特殊数据结构:单调栈

该笔记是在做LeetCode的时候使用python的重写版本

496. 下一个更大元素 I

class Solution(object):
    # 暴力法
    def nextGreaterElement(self, nums1, nums2):
        """
        :type nums1: List[int]
        :type nums2: List[int]
        :rtype: List[int]
        """
        hashmap = dict()
        n2 = len(nums2)
        # 经典的二维数组的遍历
        for i in range(n2 - 1):
            for j in range(i + 1, n2):
                if nums2[j] > nums2[i]:
                    hashmap[nums2[i]] = nums2[j]
                    # 找到了最近的一个最大的数之后就跳出内循环,避免被后面的数给覆盖掉
                    break
        res = []
        for num in nums1:
            res.append(hashmap.get(num, -1))

        return res

                   
# Next Greater Number 一般使用单调栈来解答
class Solution(object):
    def nextGreaterElement(self, nums1, nums2):
        """
        :type nums1: List[int]
        :type nums2: List[int]
        :rtype: List[int]
        """
        # 记录答案: Number --> Next Greater Number
        ans = dict()
        # 创建列表作为单调栈, 从栈底到栈顶元素递减
        stack = list()
        # 元素倒着加入栈中
        n = len(nums2)
        for i in range(n - 1, -1, -1):  
            # 先判断栈是否为空,不空的话再比较栈顶元素和当前遍历到的元素的大小
            while (len(stack) > 0 and nums2[i] >= stack[-1]):
                # 比当前元素小的栈内元素直接出站
                stack.pop()
            ans[nums2[i]] = stack[-1] if len(stack) > 0 else -1
            # 当前遍历到的元素入栈接受下一次的大小判定
            stack.append(nums2[i])
        
        # 取得输出结果
        res = list()
        for nums1_i in nums1:
            res.append(ans[nums1_i])
        return res



503. 下一个更大元素 II

采用伪循环的方式构造循环

class Solution(object):
    def nextGreaterElements(self, nums):
        """
        :type nums: List[int]
        :rtype: List[int]
        """
        # 给原来的数组再在后面接上一截[1, 2, 1]-->[1, 2, 1, 1, 2, 1]
        # 可以用循环数组来节省空间
        stack = list()
        n = len(nums)
        ans = [-1] * n
        # 假装有2 * n个元素来遍历,
        # 相比第一道题, 把i替换成 i % n 就行
        for i in range(n * 2 - 1, -1, -1):
            # 如果stack非空,将当前元素和栈顶元素比较
            while (len(stack) > 0 and nums[i % n] >= stack[-1]):
                stack.pop()
            # 如果栈顶不是空的就说明当前元素前还有比它大的元素,得到答案,否则得到-1
            ans[i % n] = stack[-1] if len(stack) > 0 else -1
            # 加入栈中,接受下一轮审判
            stack.append(nums[i % n])
        return ans

84. 柱状图中最大的矩形

参考Leetcode题解

暴力法

from typing import List


class Solution:
    def largestRectangleArea(self, heights: List[int]) -> int:
        size = len(heights)
        res = 0

        for i in range(size):
            left = i
            cur_height = heights[i]
            while left > 0 and heights[left - 1] >= cur_height:
                left -= 1

            right = i
            while right < size - 1 and heights[right + 1] >= cur_height:
                right += 1

            max_width = right - left + 1
            res = max(res, max_width * cur_height)
        return res

单调栈

from typing import List
class Solution:
    def largestRectangleArea(self, heights: List[int]) -> int:
        size = len(heights)
        res = 0
        stack = []
        for i in range(size):
            # 先顺序遍历height, 当前遍历的到的高度比栈顶的小, 栈顶元素出栈并处理这个栈顶元素
            while len(stack) > 0 and heights[i] < heights[stack[-1]]:
                cur_height = heights[stack.pop()]
                # 反序搜索栈顶元素和cur_height高度一样的
                while len(stack) > 0 and cur_height == heights[stack[-1]]:
                    stack.pop()

                if len(stack) > 0:
                    # 宽度上不包括stack[-1], 所以要-1
                    cur_width = i - stack[-1] - 1
                else:
                    # 都是
                    cur_width = i

                res = max(res, cur_height * cur_width)
            
            # (处理完最后) 当前遍历的到的高度比栈顶的大的时候, 当前高度的下标进栈
            stack.append(i)
        
        # 再反向遍历一波就是答案了, 此时的栈是 从栈顶--> 是从大到小的单调栈
        while len(stack) > 0 is not None:
            cur_height = heights[stack.pop()]
            if len(stack) > 0:
                cur_width = size - stack[-1] - 1
            else:
                cur_width = size
            res = max(res, cur_height * cur_width)

        return res

这是华为2021.08.26 pm. 7:00笔试的第二题的题解, 和上面的这题基本一样,我一开始想用单调栈,但是想不起来了....,所以最后用的暴力求解。

import sys
# 将宽大于1的箱子分为两个高度相同的子箱子
# 然后采用左右指针从中间向两边移动
def main():
    sys.stdin = open('input.txt', 'r')
    lines = sys.stdin.readlines()
    n = len(lines)
    index = 0
    while index < n:
        try:
            line = lines[index].strip().split('],')
            x = (line[0] + ']').split(',')
            y = line[1].split(',')
            x[0] = x[0][1]
            x[-1] = x[-1][0]
            x = list(map(int, x))
            flag = 0
            for j in x:
                if j <= 0:
                    flag = 1
            if flag == 1:
                print(0)
                continue


            y[0] = y[0][1]
            y[-1] = y[-1][0]
            y = list(map(int, y))
            num = len(y)

            height = []
            for i in range(num):
                if x[i] == 1:
                    height.append(y[i])
                elif i > 1:
                    height = height + [y[i]] * x[i]

            hn = len(height)
            maxA = 0
            for i, h in enumerate(height):
                left = i
                right = i
                thisheight = h
                while left > 0 and thisheight <= height[left - 1]:
                    left -= 1
                while right < hn - 1 and thisheight <= height[right + 1]:
                    right += 1
                maxA = max(maxA, (right - left + 1) * thisheight)

            print(maxA)
            index += 1

        except:
            break


if __name__ == "__main__":
    main()

316. 去除重复字母

class Solution(object):
    def removeDuplicateLetters(self, s):
        """
        :type s: str
        :rtype: str
        """
        instack = dict()
        count = dict()
        ans = []

        for c in s:
            count[c] = count.get(c, 0) + 1 
        for c in count:
            instack[c] = False

        for c in s:
            count[c] -= 1
            # 如果在里面的话就不用了, 跳过
            if instack[c] == True:
                continue

            while len(ans) > 0 and ans[-1] > c:
                # 后面还有这个将要出栈的c才将其出栈, 不然后面就遇不到了,就不是去重了
                if count[ans[-1]] > 0:
                    instack[ans.pop()] = False
                # 注意这个循环的终止条件, 不加的话会死循环(因为这个分支不会导致出栈, 会一直满足循环的条件)
                elif (count[ans[-1]] == 0):
                    break
            # 更新ans和instack
            ans.append(c)
            instack[c] = True
        
        return ''.join(ans)

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值