leetcode 单调栈及其他

单调栈

通常是一维数组,要寻找任一个元素的右边或者左边第一个比自己大或者小的元素的位置,可以考虑用单调栈。

1.单调栈里存放的元素是什么?

单调栈里只需要存放元素的下标i就可以了,如果需要使用对应的元素,直接T[i]就可以获取。

2.单调栈里元素是递增呢? 还是递减呢?

从栈头到栈底的顺序,使用递增循序。因为只有递增的时候,加入一个元素i,才知道栈顶元素在数组中右面第一个比栈顶元素大的元素是i

739. 每日温度

三种情况:T[i]小于栈顶,等于栈顶,大于栈顶

class Solution(object):
    def dailyTemperatures(self, temperatures):
        answer=[0]*len(temperatures)
        stack=[0]
        for i in range(1,len(temperatures)):
            if temperatures[i]<=temperatures[stack[-1]]:
                stack.append(i)
            else:
                while stack and temperatures[i]>temperatures[stack[-1]]:
                    answer[stack[-1]]=i-stack[-1]
                    stack.pop()
                stack.append(i)
        return answer

496. 下一个更大元素 I

没有重复元素,我们就可以用map来做映射了。根据数值快速找到下标,还可以判断nums2[i]是否在nums1中出现过。

class Solution(object):
    def nextGreaterElement(self, nums1, nums2):
        res=[-1]*len(nums1)
        stack=[0]
        for i in range(1,len(nums2)):
            if nums2[i]<=nums2[stack[-1]]:
                stack.append(i)
            else:
                while stack and nums2[i]>nums2[stack[-1]]:
                    if nums2[stack[-1]] in nums1:
                        ind=nums1.index(nums2[stack[-1]])
                        res[ind]=nums2[i]
                    stack.pop()
                stack.append(i)
        return res

503. 下一个更大元素 II

在遍历的过程中模拟走了两遍nums

class Solution(object):
    def nextGreaterElements(self, nums):
        res=[-1]*len(nums)
        stack=[0]
        for i in range(len(nums)*2):
            while stack and nums[i%len(nums)]>nums[stack[-1]]:
                res[stack[-1]]=nums[i%len(nums)]
                stack.pop()
            stack.append(i%len(nums))
        return res

42. 接雨水

取栈顶元素,将栈顶元素弹出,这个就是凹槽的底部,也就是中间位置,下标记为mid,对应的高度为height[mid]。

此时的栈顶元素st.top(),就是凹槽的左边位置,下标为st.top(),对应的高度为height[st.top()]。

当前遍历的元素i,就是凹槽右边的位置,下标为i,对应的高度为height[i]。

class Solution(object):
    def trap(self, height):
        sum_=0
        stack=[0]
        for i in range(1,len(height)):
            if height[i]<=height[stack[-1]]:
                stack.append(i)
            else:
                while stack and height[i]>height[stack[-1]]:
                    mid=stack[-1]
                    stack.pop()
                    if stack:
                        h=min(height[stack[-1]],height[i])-height[mid]
                        w=i-stack[-1]-1
                        sum_+=h*w
                stack.append(i)
        return sum_

84. 柱状图中最大的矩形

本题是要找每个柱子左右两边第一个小于该柱子的柱子,所以从栈头(元素从栈头弹出)到栈底的顺序应该是从大到小的顺序

找每个柱子左右侧的第一个高度值小于该柱子的柱子
单调栈:栈顶到栈底:从大到小(每插入一个新的小数值时,都要弹出先前的大数值)
栈顶,栈顶的下一个元素,即将入栈的元素:这三个元素组成了最大面积的高度和宽度

class Solution(object):
    def largestRectangleArea(self, heights):
        heights.insert(0,0)
        heights.append(0)
        stack=[0]
        res=0
        for i in range(1,len(heights)):
            if heights[i]>=heights[stack[-1]]:
                stack.append(i)
            else:
                while stack and heights[i]<heights[stack[-1]]:
                    mid=stack[-1]
                    stack.pop()
                    if stack:
                        left=stack[-1]
                        right=i
                        w=right-left-1
                        h=heights[mid]
                        res=max(res,w*h)
                stack.append(i)
        return res

图论

回溯算法,其实就是dfs的过程

841. 钥匙和房间

有向图搜索全路径问题。只能用深度搜索DFS/广度搜索BFS

class Solution(object):
    def canVisitAllRooms(self, rooms):
        self.visited=[False]*len(rooms)
        self.dfs(0,rooms)
        for i in range(len(self.visited)):
            if self.visited[i]!=True:return False
        return True
    def dfs(self,key,rooms):
        if self.visited[key]:return
        self.visited[key]=True
        keys=rooms[key]
        for i in keys:
            self.dfs(i,rooms)

127. 单词接龙

无向图求最短路,广搜最为合适,广搜只要搜到了终点,那么一定是最短的路径。因为广搜就是以起点中心向四周扩散的搜索。

class Solution(object):
    def ladderLength(self, beginWord, endWord, wordList):
        from collections import deque
        wordset=set(wordList)
        if len(wordset)==0 or endWord not in wordset:return 0
        mapp={beginWord:1}
        que=deque([beginWord])
        while que:
            word=que.popleft()
            path=mapp[word]
            for i in range(len(word)):
                word_list=list(word)
                for j in range(26):
                    word_list[i]=chr(ord('a')+j)
                    newword=''.join(word_list)
                    if newword==endWord:
                        return path+1
                    if newword in wordset and newword not in mapp:
                        mapp[newword]=path+1
                        que.append(newword)
        return 0

并查集

并查集主要解决集合问题,两个节点在不在一个集合,也可以将两个节点添加到一个集合中

模板

int n = 1005; // 节点数量3 到 1000
int father[1005];

// 并查集初始化
void init() {
    for (int i = 0; i < n; ++i) {
        father[i] = i;
    }
}
// 并查集里寻根的过程
int find(int u) {
    return u == father[u] ? u : father[u] = find(father[u]);
}
// 将v->u 这条边加入并查集
void join(int u, int v) {
    u = find(u);
    v = find(v);
    if (u == v) return ;
    father[v] = u;
}
// 判断 u 和 v是否找到同一个根
bool same(int u, int v) {
    u = find(u);
    v = find(v);
    return u == v;
}

684. 冗余连接

从前向后遍历每一条边,边的两个节点如果不在同一个集合,就加入集合(即:同一个根节点)。

如果边的两个节点已经出现在同一个集合里,说明着边的两个节点已经连在一起了,如果再加入这条边一定就出现环了。

class Solution(object):
    def __init__(self):
        n=1005
        self.father=[i for i in range(n)]
    def find(self,u):
        if u==self.father[u]:return u
        self.father[u]=self.find(self.father[u])
        return self.father[u]
    def join(self,u,v):
        u=self.find(u)
        v=self.find(v)
        if u==v:return
        self.father[v]=u
    def same(self,u,v):
        u=self.find(u)
        v=self.find(v)
        return u==v
    def findRedundantConnection(self, edges):
        self.__init__()
        for i in range(len(edges)):
            if self.same(edges[i][0],edges[i][1]):return edges[i]
            else:self.join(edges[i][0],edges[i][1])
        return []

685. 冗余连接 II

并查集为什么可以判断 一个图是不是树呢?

因为如果两个点所在的边在添加图之前如果就可以在并查集里找到了相同的根,那么这条边添加上之后 这个图一定不是树了

模拟

657. 机器人能否返回原点

class Solution(object):
    def judgeCircle(self, moves):
        x,y=0,0
        for i in range(len(moves)):
            if moves[i]=='U':y+=1
            elif moves[i]=='D':y-=1
            elif moves[i]=='R':x+=1
            elif moves[i]=='L':x-=1
        return x==0 and y==0

31. 下一个排列

从后向前遍历,发现nums[j]>nums[i],进行交换,对i+1到数据结束的区间进行排序

class Solution(object):
    def nextPermutation(self, nums):
        lenght=len(nums)
        for i in range(lenght-1,-1,-1):
            for j in range(lenght-1,i,-1):
                if nums[j]>nums[i]:
                    nums[i],nums[j]=nums[j],nums[i]
                    self.reverse(nums,i+1,lenght-1)
                    return nums
        return self.reverse(nums,0,lenght-1)
    def reverse(self,nums,l,r):
        while l<r:
            nums[l],nums[r]=nums[r],nums[l]
            l+=1
            r-=1

463. 岛屿的周长

遍历每一个空格,遇到岛屿,计算其上下左右的情况,遇到水域或者出界的情况,就可以计算边了

class Solution(object):
    def islandPerimeter(self, grid):
        sum_=0
        direction=[[0,1],[0,-1],[-1,0],[1,0]]
        for i in range(len(grid)):
            for j in range(len(grid[0])):
                if grid[i][j]==1:
                    for k in range(len(direction)):
                        x=i+direction[k][0]
                        y=j+direction[k][1]
                        if x<0 or x>=len(grid) or y<0 or y>=len(grid[0]) or grid[x][y]==0:
                            sum_+=1
        return sum_

位运算

1356. 根据数字二进制下 1 的数目排序

&位运算符

class Solution(object):
    def sortByBits(self, arr):
        arr.sort(key=lambda num:(self.countbit(num),num))
        return arr
    def countbit(self,num):
        count=0
        while num:
            num&=num-1
            count+=1
        return count

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值