楼主: yangzhit
跳转到指定楼层
上一主题 下一主题
收起左侧

骨骼蠡口分类整理追加单调队列

 
🔗
 楼主| yangzhit 2020-7-13 05:51:05 | 只看该作者
全局:
LC739. Daily Temperatures (单调递减栈), 亚麻,思科,领英
739是一道G家年初老题
给出每天温度序列,想知道多少天可以等到更暖和的天气。
方法,建立一个温度递增栈。
   def dailyTemperatures(self, T: List[int]) -> List[int]:
        stack=[]
        map={}
        i = 0
        while i < len(T):
            #当新温度比栈顶高,则栈顶等到了更暖和天气
            while len(stack) and T[i]>T[stack[-1]]:
                map[stack.pop()]=i
            stack.append(i)
            i = i+1
        i = 0
        result = []
        while i < len(T):
            if i in map:
                result.append(map[i]-i)
           #没等到暖和的天气,地球就流浪了
            else:
                result.append(0)
            i = i +1
        return result
回复

使用道具 举报

🔗
beyondR 2020-7-13 06:19:20 | 只看该作者
全局:
谢谢楼主,希望楼主可以继续总结。在这里我补充一下三个hard题我自己的解法和解释,各位看官要是觉得好麻烦加个米,觉得不好麻烦补充更好的写法,谢谢。

84:从某个index出发,以他为中心的的最大矩形,是找到它右边和左边第一个高度小于它的矩形为左右边界,然后相减再乘以他本身的高度
        由此可以得出,这题本质是要找到从某个index出发它左边和右边第一个高度小于它的数,因此可以得出要使用递增栈

    input我们叫它array
    #初始化:array结尾放0
    array.append(0)
    # 初始化:栈里放-1
    stack = [-1]
    ans = 0

    for i in range(len(array)):
      # 当前index小于栈顶,说明已经不再是递增栈,我们需要pop
      while array[i] < array[stack[-1]]:
        # 依次pop出栈里大于i的元素
        height = array[stack.pop()]
        # 此时栈里元素的右边界已经确定,为i(因为i是右边第一个小于栈里元素的)
        # 因为递增,所以栈里元素的左边界就是它前面一个元素
        width = i - stack[-1] -1
        # 如果有必要的话,更新一下max
        ans = max(ans, height*width)
      # 因为我们已经pop出所有大于i的元素,现在加进去i依然可以保证是一个递增栈
      stack.append(i)
    return ans

评分

参与人数 1大米 +1 收起 理由
yangzhit + 1 给你点个赞!

查看全部评分

回复

使用道具 举报

🔗
wanli 2020-7-13 06:37:22 来自APP | 只看该作者
全局:
这才是值得加分的精华帖子
回复

使用道具 举报

🔗
beyondR 2020-7-13 06:41:59 | 只看该作者
全局:
本帖最后由 beyondR 于 2020-7-13 06:45 编辑

继续,42:   为什么先po上一题84,因为这两题很相似,我认为需要先理解84再理解42。
    和84相似,我们分析,从某个index出发,先要找到它右边和左边最高的矩形为左右边界,然后取两边更小的一个高度(木桶效应)-它本身的高度 即为被困雨水的高度
    由此可以得出,这题本质是要找到从某个index出发它右边和左边最高的矩形然后再找到两者相对更小的一个高度
    诚然,我们依旧可以用栈来做,但是这样我们需要一个On的空间
    因此,我们发现可以用双指针,再记录一下左边和右边的最大值的方法来做,这样我们的空间就优化到了01,达到最优解

    依然叫input array
    left, right = 0, len(array) - 1
    left_max, right_max = 0, 0
    ans = 0
    while left < right:
      # 我们每走一步,如果applicable,先要更新left和right max
      if array[left] > left_max:
        left_max = array[left]
      if array[right] > right_max:
        right_max = array[right]
      # 然后移动双指针中较小的那一个,并且计算水位高度
      if left_max < right_max:
        ans += left_max - array[left]
        left += 1
      else:
        ans += right_max - array[right]
        right -= 1
        
    return ans

评分

参与人数 1大米 +1 收起 理由
yangzhit + 1 给你点个赞!

查看全部评分

回复

使用道具 举报

🔗
 楼主| yangzhit 2020-7-13 06:54:58 | 只看该作者
全局:
LC503. Next Greater Element II, FB 亚麻
503是G家1年老题,亚麻1月老题,FB新题
给一个循环列表,找出每个元素,下一个比其大的数。
相比496,要多循环一遍,找出栈里剩下的NGN
    def nextGreaterElements(self, nums: List[int]) -> List[int]:
        stack = []
        result = [-1] *len(nums)
        p=0
        while p<2*len(nums):
            while len(stack) and nums[stack[-1]] < nums[p%len(nums)]:
                result[stack.pop()]=nums[p%len(nums)]
            #第2轮不入栈
            if p<len(nums):
                stack.append(p)
            p=p+1
        return result
回复

使用道具 举报

🔗
beyondR 2020-7-13 07:25:34 | 只看该作者
全局:
最后:862 (这题写了好多,累了,orz)

    def shortestSubarray(A, K):
        # 首先分析,要找一个contiguous subarray of A with sum at least K,等于要在它的prefix sum array里找到最近的两个点使其相减大于等于k
        # 也就是说对于任何一个数y,要找以它为结尾的sublist大于k,也就是要找离他最近的一个数x使其满足,y-x >= k
        # 有了这个分析以后,得到一个重要的观察,假如有 i1 < i2 而 prefix[x2] <= prefix[i1],那我们永远不会取到i1,原因是如果对一个index满足prefix[index] - prefix[i1] >= k,那肯定也满足prefix[index] - prefix[i2] >= k,而i2比i1大,意味着i2开头的subarray比i1开头的短。
        # 因此可以得出,我们可以维护一个单调递增队列
        # 另一个重要的观察是,如果对一个index我们取了i1作为subarray的开头,那比它大的index必然不会再取i1,因为以第一个index结尾的subarray一定比以比它大的index结尾的subarray短。所以一旦用过一次,即可以pop i1出队列。
        
        
        prefix, ans = [0], len(A) + 1
        for num in A:
            prefix.append(prefix[-1] + num)
        
        
        q = collections.deque()
        for i, num in enumerate(prefix):
            # 如果prefix sum开始递减,为维护递增队列我们pop(对应观察一)
            while q and num < prefix[q[-1]]:
                q.pop()
            # 对应观察二
            while q and num - prefix[q[0]] >= K:
                ans = min(ans, i - q.popleft())
            q.append(i)
            
        return ans if ans < len(A) + 1 else -1

评分

参与人数 1大米 +1 收起 理由
yangzhit + 1 很有用的信息!

查看全部评分

回复

使用道具 举报

🔗
__jind 2020-7-13 07:40:50 | 只看该作者
全局:
yangzhit 发表于 2020-7-12 16:55
谢谢,不确定。如果有相应解法或链接,麻烦贴出来
  1. class Solution:
  2.     def numSubmat(self, mat) -> int:
  3.         '''
  4.             1 0 1
  5.             1 1 0
  6.             1 1 0

  7.               ↓ use prefix sum by column

  8.             1 0 1
  9.             2 1 0
  10.             3 2 0

  11.         calculate the prefix sum, like:
  12.         
  13.                 h: [2 2 4 3 1]
  14.             index:  0 1 2 3 4
  15.         
  16.         
  17.         stack = [(-1, 0)]
  18.         stack.append (i, h[i]) when it is increasing.
  19.         Once you find h[3] = 3 which is not increasing,
  20.             you pop items from stack (i, h[i]),
  21.             until the item on the top of the stack has a lower height
  22.         
  23.         this property means that:
  24.             
  25.             
  26.         # of rectangles created by the popped column =
  27.             [cur(i) - popped(i)]
  28.             * [popped(i) - stack[-1][0]]   
  29.             # 左边包含 popped column 的 能组成正方形的长度 * 右边... (左边和右边,包含 popped column 的 所有组合)
  30.             * h[popped(i)]
  31.             
  32.         '''
  33.         for row in mat:
  34.             row.append(0)  
  35.         
  36.         col = len(mat[0])
  37.         res = 0
  38.         h = [0 for _ in range(col)]
  39.         
  40.         for row in mat:
  41.             stack = [(-1, 0)]
  42.             
  43.             for i in range(col):
  44.                
  45.                 h[i] = h[i] + 1 if row[i] == 1 else 0 # calculate the height  
  46.                
  47.                 while stack and len(stack) > 1 and h[stack[-1][0]] > h[i]: #  and len(stack) > 1 是因为有可能 h[stack[-1][0]] 是 h[-1] 就错了
  48.                     popped_i, popped_h = stack.pop()
  49.                     res += (i - popped_i) * (popped_i - stack[-1][0]) * popped_h
  50.                
  51.                 stack.append((i, h[i]))
  52.             
  53.         return res         
  54.         
  55.         
  56.         
  57.         
  58.     def numSubmat___(self, mat) -> int:
  59.         '''
  60.             1 0 1
  61.             1 1 0
  62.             1 1 0

  63.               ↓ use prefix sum by column

  64.             1 0 1
  65.             2 1 0
  66.             3 2 0

  67.         calculate the prefix sum, like:
  68.         
  69.                 h: [2 2 4 3 1]
  70.             index:  0 1 2 3 4
  71.             
  72.         # of rectangles created by the cur column =
  73.             (the index of the cur column - the index of the previous column with lower height)
  74.             * the height of cur column
  75.             + the submatries owing to the previous column with lower height
  76.         
  77.         we store the # of rectangle with the index, like: (index, # of rectangle of the cur column)
  78.             
  79.         Once you find h[3] = 3 which is not increasing,
  80.             you pop items from stack (i, previous rectangle),
  81.             until the item on the top of the stack has a lower height
  82.             


  83.         '''
  84.         col = len(mat[0])
  85.         res = 0
  86.         h = [0 for _ in range(col)]
  87.         
  88.         for row in mat:
  89.             stack = [(-1, 0)]
  90.             
  91.             for i in range(col):
  92.                
  93.                 h[i] = h[i] + 1 if row[i] == 1 else 0 # calculate the height  
  94.                
  95.                 while stack and len(stack) > 1 and h[stack[-1][0]] > h[i]:
  96.                     stack.pop()
  97.                
  98.                 # the rectangles created by cur column
  99.                 width = i - stack[-1][0]
  100.                 plus = stack[-1][1]
  101.                 cur = width*h[i] + plus
  102.                
  103.                 stack.append((i, cur))
  104.                 res += cur
  105.             print(h)
  106.         return res
复制代码

评分

参与人数 1大米 +1 收起 理由
yangzhit + 1 赞一个!

查看全部评分

回复

使用道具 举报

🔗
 楼主| yangzhit 2020-7-14 09:12:16 | 只看该作者
全局:
beyondR 发表于 2020-7-13 07:25
最后:862 (这题写了好多,累了,orz)

    def shortestSubarray(A, K):

感谢题解和详细的注释,我根据这个思路写了自己的代码。

    def shortestSubarray(self, A: List[int], K: int) -> int:
        sum = [0]
        for a in A:
            sum.append(sum[-1]+a)
        result = len(sum)
        stack=[]
        for i in range(len(sum)):
            while stack and sum[i]<=sum[stack[-1]]:
                stack.pop()
            while stack and sum[i]-sum[stack[0]]>=K:
                result = min(result, i-stack.pop(0))
            stack.append(i)  
        if result == len(sum):
            return -1
        return result

跟一个实例分析
A=[84,-37,32,40,95]
K=167
Sum   区间   栈
0                  [0]
84      [0,0]   [0,84]
47      [0,1]   [0,47]     如果某个sum-84符合>167,sum-47肯定符合,而-47更优。第一个while
79      [0,2]   [0,47,79]  如果sum-47符合>167,sum-79不一定。79-47不>=167
119    [0,3]   [0,47,79,119]  
214    [0,4]   [0,47,79,119],214 如果sum1-0符合,则sum2/3/4-0不是最优解。所以0可以删除,第二个while
回复

使用道具 举报

🔗
 楼主| yangzhit 2020-7-14 18:31:04 | 只看该作者
全局:
42. Trapping Rain Water
根据下面这个帖子,写了一个Python版本
https://www.cnblogs.com/grandyang/p/4402392.html
跟前面几题不一样的是,用到栈里两个数,一个作为左边的高,一个作为底。
栈是一个递减栈,这样才能形成一个坑。算坑里的水,是一个个底往上算。
    def trap(self, height: List[int]) -> int:
        s=[]
        r=0
        for i in range(len(height)):
            while s and height[i]>height[s[-1]]:
                t = s.pop()
                if s:
                    r = r + (min(height[i], height[s[-1]]) - height[t]) * (i-s[-1]-1)
            s.append(i)
        return r

min(height[i], height[s[-1]]) - height[t] 两边高取小,再把前面算过的底去掉
i-s[-1]-1 两边的距离减一,紧挨着盛不了水

本帖子中包含更多资源

您需要 登录 才可以下载或查看附件。没有帐号?注册账号

x
回复

使用道具 举报

🔗
 楼主| yangzhit 2020-7-14 18:47:19 | 只看该作者
全局:
84. Largest Rectangle in Histogram
这道题,根据下面帖子写了Python版
https://www.cnblogs.com/love-yh/p/7182920.html
主要是分两种情况,1. 如果栈不空,部分算面积 2. 如果栈空,全长算面积
    def largestRectangleArea(self, heights: List[int]) -> int:
        max = 0
        stack = []
        heights.append(-1)
        for i in range(0, len(heights)):
            while stack and heights[i] < heights[stack[-1]]:
                last = stack.pop()
                if stack and heights[last] * (i-stack[-1]-1)>max:
                    max = heights[last] * (i-stack[-1]-1) #部分
                elif stack ==0 and heights[last] * i>max:
                    max = heights[last] * i #全长                  
            stack.append(i)
        return max

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册账号
隐私提醒:
  • ☑ 禁止发布广告,拉群,贴个人联系方式:找人请去🔗同学同事飞友,拉群请去🔗拉群结伴,广告请去🔗跳蚤市场,和 🔗租房广告|找室友
  • ☑ 论坛内容在发帖 30 分钟内可以编辑,过后则不能删帖。为防止被骚扰甚至人肉,不要公开留微信等联系方式,如有需求请以论坛私信方式发送。
  • ☑ 干货版块可免费使用 🔗超级匿名:面经(美国面经、中国面经、数科面经、PM面经),抖包袱(美国、中国)和录取汇报、定位选校版
  • ☑ 查阅全站 🔗各种匿名方法

本版积分规则

>
快速回复 返回顶部 返回列表