算法训练营04-map,set,dequeue,stack

预习题目
有效的模板字符串
最小栈

实战题目
最大矩形面积
滑动窗口

课后作业
用 add first 或 add last 这套新的 API 改写 Deque 的代码
分析 Queue 和 Priority Queue 的源码
设计环形队列
雨水

总结

1. 问题的抽象转化

把问题简单抽象化
比如求雨水的,简化逻辑为装满的情况下每个柱子距离水平面的距离,进而求出每个柱子对水的容纳,直接从最终状态进行分解,然后通过解决子问题来解决整个问题
求最大矩形面积,简化为以每个柱子作为矩形的最低高度,进行状态搜索,这个是枚举所有的状态,找到最优的状态
问题简化为可以枚举的状态,那么计算机就能够对这些状态进行单个处理,进而得到结果

算法的一个思想就是在解空间进行搜索,所以,对于复杂的问题可以尝试进行解空间的划分,然后进行搜索,得到最优,也就是枚举
但是矩形这道题还有一种是枚举两个边界,找中间最小的柱子,这种枚举方式可能也不容易处理,这个也是在解空间进行搜索,都是问题的解决方案

有时候有的问题可能很快的抽象为简单的问题,但是有点问题逻辑比较复杂,更难抽象为独立的简单的问题,所以处理的方式也不太一样,有些问题,初始的时候想不到解决方法也很正常,因为你连最基本的暴力方法都没有解决的头绪,所以处理起来也更加复杂化。所以还是要多看多练习,逐步提升对同类问题的抽象转化能力。

矩形和雨水问题是很好的思想转化的题目,可以多学习和体会。

2. 边界问题的转化

写代码的时候,惯性思维,在处理第一个元素的时候想当然的就用了特殊处理的case,就像下面的

   for i in range(length) :
            if i == 0 :
                left_boundry[0] = -1
                stack.append(i)
                continue 

这个显然就是线性思维导致的特殊case思维,特殊case的存在会让代码的可读性降低,而且写起来越写越复杂,换个思维,我们可以先按照普通的其他case的处理方式来写这段代码,看看是否可以兼容特殊case的处理,或者仅仅是加一些判断来作为特殊case的处理,像下面的第二版中,直接糅合进来了

   for i in range(length) :
            while stack and heights[stack[-1]] >= heights[i] :
                stack.pop()
            if stack :
                left_boundry[i] = stack[-1]
            else :
                left_boundry[i] = -1
            stack.append(i)
1.第一版



写了一个左右合并的,但是写的很不好,感觉是没有抓住要点,代码写的很复杂
 def largestRectangleArea(self, heights: List[int]) -> int:
        length = len(heights) 
        max_area = 0 
        stack = []
        left_boundry = [-1]*length
        right_boundry = [0]*length
        for i in range(length) :
            if i == 0 :
                left_boundry[0] = -1
                stack.append(i)
                continue 
            if heights[i] < heights[stack[-1]] :
                while len(stack) > 0 and heights[i] < heights[stack[-1]] :
                    right_boundry[stack[-1]] = i-1
                    stack.pop()
                if len(stack) == 0 :
                    left_boundry[i] = -1
                elif heights[i] == heights[stack[-1]] :
                    left_boundry[i] = left_boundry[stack[-1]]
                else :
                    left_boundry[i] = stack[-1]
                stack.append(i)
            elif heights[i] == heights[stack[-1]] :
                left_boundry[i] = left_boundry[stack[-1]]
                stack.append(i)
            else :
                left_boundry[i] = stack[-1]
                stack.append(i)
        if  len(stack) > 0 :
            right = stack[-1]
            while len(stack) > 0 :
                right_boundry[stack[-1]] = right
                stack.pop()
        for i in range(length) :
            cur = (right_boundry[i]-left_boundry[i]) * heights[i]
            max_area = max(max_area,cur)  
        # print(left_boundry)
        # print(right_boundry)
        return max_area
            
1.第二版
这次学习了一下,分开了两个,感觉逻辑上简单了,很多,有时候惯性的思维总是在写第一个的时候就想着要不要特殊处理,可以想一下,通过增加一个调价
    def largestRectangleArea(self, heights: List[int]) -> int:
        length = len(heights) 
        max_area = 0 
        stack = []
        left_boundry = [-1]*length
        right_boundry = [0]*length
        for i in range(length) :
            while stack and heights[stack[-1]] >= heights[i] :
                stack.pop()
            if stack :
                left_boundry[i] = stack[-1]
            else :
                left_boundry[i] = -1
            stack.append(i)
        stack = []
        for j in reversed(range(length)) :
            while stack and heights[stack[-1]] >= heights[j] :
                stack.pop()
            if stack :
                right_boundry[j] = stack[-1]-1
            else :
                right_boundry[j] = length-1
            stack.append(j)
        for k in range(length) :
            cur = (right_boundry[k]-left_boundry[k])*heights[k]
            max_area = max(max_area,cur)
        return max_area


collections-deque

from collections import deque


append(x)
Add x to the right side of the deque.

appendleft(x)
Add x to the left side of the deque.

clear()
Remove all elements from the deque leaving it with length 0.

count(x)
Count the number of deque elements equal to x.

New in version 2.7.

extend(iterable)
Extend the right side of the deque by appending elements from the iterable argument.

extendleft(iterable)
Extend the left side of the deque by appending elements from iterable. Note, the series of left appends results in reversing the order of elements in the iterable argument.

pop()
Remove and return an element from the right side of the deque. If no elements are present, raises an IndexError.

popleft()
Remove and return an element from the left side of the deque. If no elements are present, raises an IndexError.

remove(value)
Remove the first occurrence of value. If not found, raises a ValueError.

New in version 2.5.

reverse()
Reverse the elements of the deque in-place and then return None.

New in version 2.7.

rotate(n=1)
Rotate the deque n steps to the right. If n is negative, rotate to the left.

In addition to the above, deques support iteration, pickling, len(d), reversed(d), copy.copy(d), copy.deepcopy(d), membership testing with the in operator, and subscript references such as d[-1]. Indexed access is O(1) at both ends but slows to O(n) in the middle. For fast random access, use lists instead.

样例

 使用双端队列,结合后面的大的可以覆盖前面的小的模式,这个问题一下就迎刃而解了,真是神奇啊
 加油
 from collections import deque
 class Solution:
     def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
         ## 双端队列模式
         n = len(nums)
         dq = deque()
         for i in range(k) :
             while dq and nums[dq[-1]] <= nums[i] :
                 dq.pop()
             dq.append(i)
         res = []
         res.append(nums[dq[0]])
         for j in range(k,n) :
             if (j - dq[0]) >= k :
                 dq.popleft()
             while dq and nums[dq[-1]] <= nums[j] :
                 dq.pop()
             dq.append(j)
             res.append(nums[dq[0]])
         return res 

heapq

heapq.heappush(heap, item)
Push the value item onto the heap, maintaining the heap invariant.

heapq.heappop(heap)
Pop and return the smallest item from the heap, maintaining the heap invariant. If the heap is empty, IndexError is raised. To access the smallest item without popping it, use heap[0].

heapq.heappushpop(heap, item)
Push item on the heap, then pop and return the smallest item from the heap. The combined action runs more efficiently than heappush() followed by a separate call to heappop().

New in version 2.6.

heapq.heapify(x)
Transform list x into a heap, in-place, in linear time.

heapq.heapreplace(heap, item)

样例
class Solution:
    def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
        ## 堆的应用
        n = len(nums)
        res = []
        heap = [(-nums[i],i) for i in range(k)]
        heapq.heapify(heap)
        res.append(-heap[0][0])
        for i in range(k,n):
            heapq.heappush(heap,(-nums[i],i))
            while (i - heap[0][1]) >= k :
                heapq.heappop(heap)
            res.append(-heap[0][0])
        
        return res 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值