面试题梳理(LeetCode深搜,一)

深搜经典题目小总结

深搜是递归的使用。通常用于n*n矩阵组成的地图中。从某个状态出发,沿着定义的几个方向遍历地图,通过定义边界条件或记录路径定义递归输出。directions常用来定义深搜的方向。
一、岛屿数量(Leetcode 200)
对于每个陆地,从某一点出发(grid[i][j]=“1”),使用深搜的方式,把可以连接在一起的陆地连接起来并把陆地值设置成水域值“0”(也可以设置成其他值),防止陷入死循环。

class Solution:
    def numIslands(self, grid: List[List[str]]) -> int:
        ##定义搜索
        directions=[(-1,0),(1,0),(0,-1),(0,1)]
        ##从(x,y)开始遍历,
        def dfs(x,y):
            grid[x][y]="0"
            for i in directions:
                ix,iy=i
                dx=x+ix
                dy=y+iy
                #定义边界条件
                if(dx<0 or dx>=len(grid) or dy<0 or dy>=len(grid[0])):
                    continue
                else:
                    if(grid[dx][dy]=="1"):
                        dfs(dx,dy)    
            return


        if(grid==[]):
            return 0
        total=0
        for i in range(len(grid)):
            for j in range(len(grid[0])):
                if(grid[i][j]=="1"):
                    dfs(i,j)
                    total+=1
        return total

二、矩阵中的最长递增路径(Leetcode 329)
1.使用DP优化深搜过程
2.使用step=max(step,1+dfs(dx,dy))寻找当前点出发的最长递增路径。

class Solution:
    def longestIncreasingPath(self, matrix: List[List[int]]) -> int:
        if(matrix==[]):
            return 0
        directions=[(-1,0),(1,0),(0,-1),(0,1)]
        xlen=len(matrix)
        ylen=len(matrix[0])
        dp=[[0]*ylen for i in range(xlen)]
        def dfs(x,y):
            if(dp[x][y]>0):
                return dp[x][y]
            step=1
            for i in directions:
                ix,iy=i
                dx=x+ix
                dy=y+iy
                if(dx<0 or dx>=xlen or dy<0 or dy>=ylen):
                    continue
                if(matrix[dx][dy]>matrix[x][y]):
                    step=max(step,1+dfs(dx,dy))
            dp[x][y]=step
            return step

        maxLength=0
        for i in range(xlen):
            for j in range(ylen):
                if(dp[i][j]!=0):
                    temp=dp[i][j]
                else:
                    temp=dfs(i,j)
                if(temp>maxLength):
                    maxLength=temp
        return maxLength

三、岛屿的最大面积(Leetcode 695)
在循环外定义count=1,在dfs返回值处定义count+=dfs(dx,dy)。这样,在dfs处返回的就是要求的x,y处的值。

class Solution:
    def maxAreaOfIsland(self, grid: List[List[int]]) -> int:
        directions=[(-1,0),(1,0),(0,-1),(0,1)]
        icount=0
        def dfs(x,y):
            grid[x][y]=0
            count=1
            for i in directions:
                ix,iy=i
                dx=x+ix
                dy=y+iy
                if(dx<0 or dx>=len(grid) or dy<0 or dy>=len(grid[0])):
                   continue
                if(grid[dx][dy]==1):
                    count+=dfs(dx,dy)
            return count
            
        maxSize=0
        for i in range(len(grid)):
            for j in range(len(grid[0])):
                if(grid[i][j]==1):
                    num=dfs(i,j)
                    if(num>maxSize):
                        maxSize=num
        return maxSize

四、机器人的运动范围(剑指offer 13)
岛屿数量的变型

class Solution:

    def movingCount(self, m: int, n: int, k: int) -> int:
        book=[([0] * n) for i in range(m)]
        directions=[(-1,0),(0,-1),(1,0),(0,1)]
        def sum_gezi(x,y):
            total=0
            while(x!=0):
                total+=x%10
                x=int(x/10)
            while(y!=0):
                total+=y%10
                y=int(y/10)
            return total
        
        def get_dir():
            total=0
            for i in range(m):
                for j in range(n):
                    if(book[i][j]==1):
                        total+=1
            return total

        def dfs(x,y):
            book[x][y]=1
            if(x==m-1 and y==n-1):
                return get_dir()
            for res in directions:
                ix,iy=res
                dx=x+ix
                dy=y+iy
                if(dx<0 or dx>=m or dy<0 or dy>=n):
                    continue
                if(book[dx][dy]==0 and sum_gezi(dx,dy)<=k):
                    dfs(dx,dy)
            return get_dir()
        return dfs(0,0)

上述程序没有直接返回运动格子总数,优化一下,边搜索,边记录走过路径的长度,可以降低时间复杂度。

class Solution:

    def movingCount(self, m: int, n: int, k: int) -> int:
        book=[([0] * n) for i in range(m)]
        directions=[(-1,0),(0,-1),(1,0),(0,1)]
        def sum_gezi(x,y):
            total=0
            while(x!=0):
                total+=x%10
                x=int(x/10)
            while(y!=0):
                total+=y%10
                y=int(y/10)
            return total

        def dfs(x,y):
            book[x][y]=1
            step=1
            if(x==m-1 and y==n-1):
                return step
            for res in directions:
                ix,iy=res
                dx=x+ix
                dy=y+iy
                if(dx<0 or dx>=m or dy<0 or dy>=n):
                    continue
                if(book[dx][dy]==0 and sum_gezi(dx,dy)<=k):
                    step+=dfs(dx,dy)
            return step
        return dfs(0,0)

五、全排列(LeetCode 46)
使用path记录路径,book记录nums中的元素是否被访问过。

class Solution:
    def permute(self, nums: List[int]) -> List[List[int]]:
        def dfs(nums,length,path,deepth):
            if(deepth==length):
                # path[:]:复制path。否则,因为pop的存在,所有的path最后都是0
                res.append(path[:])
                return
            for i in range(length):
                if(book[i]==0):
                    book[i]=1
                    path.append(nums[i])
                    dfs(nums,length,path,deepth+1)
                    book[i]=0
                    path.pop()
            return
        length=len(nums)
        book=[0]*length
        res=[]
        dfs(nums,length,[],0)
        return res

六、全排列(LeetCode 47)
搜索+剪枝。深搜的两种变型,深搜+DP,深搜+剪枝。

class Solution:
    def permuteUnique(self, nums: List[int]) -> List[List[int]]:
        def dfs(nums,length,depth,path):
            if(depth==length):
                res.append(path[:])
                return
            for i in range(length):
                if(book[i]==0):
                    #如果前后两个元素相同,且刚退出,则说明已经存在该节点,不需再搜索,所以剪枝。
                    if(i>0 and nums[i]==nums[i-1] and book[i-1]==0):
                        continue
                    path.append(nums[i])
                    book[i]=1
                    dfs(nums,length,depth+1,path)
                    book[i]=0
                    path.pop()
            return
        length=len(nums)
        book=[0]*length
        res=[]
        nums.sort()
        dfs(nums,length,0,[])
        return res

七、字符串的排列(剑指Offer 38)
根据字符串排列的特点,考虑深度优先搜索所有排列方案。即通过字符交换,先固定第 1位字符( n 种情况)、再固定第 2位字符(n-1种情况)、… 、最后固定第 n 位字符(1 种情况)。
当字符串存在重复字符时,排列方案中也存在重复方案。为排除重复方案,需在固定某位字符时,保证 “每种字符只在此位固定一次” ,即遇到重复字符时不交换,直接跳过。

class Solution:
    def permutation(self, s: str) -> List[str]:
        c,res=list(s),[]
        def dfs(x):
            if(x==len(c)-1):
                res.append("".join(c))
                return
            dic=[]
            for i in range(x,len(c)):
                if(c[i] in dic):continue
                dic.append(c[i])
                c[i],c[x]=c[x],c[i]
                dfs(x+1)
                c[i],c[x]=c[x],c[i]
        dfs(0)
        return res

根据这几道题,发现一个规律
1.在遍历开始前定义step=1,step=max(step,1+dfs(dx,dy))。记录某个路径step数。
2.在遍历开始前定义step=1,step+=dfs(dx,dy)。记录经过所有点的大小。

除此以外,参考上面的题,还有剪枝和DP两种用法。
八、矩阵中的路径(剑指offer 12)

class Solution:
    def exist(self, board: List[List[str]], word: str) -> bool:
        def dfs(i, j, k):
            if not 0 <= i < len(board) or not 0 <= j < len(board[0]) or board[i][j] != word[k]: return False
            if k == len(word) - 1: return True
            tmp, board[i][j] = board[i][j], '/'
            res = dfs(i + 1, j, k + 1) or dfs(i - 1, j, k + 1) or dfs(i, j + 1, k + 1) or dfs(i, j - 1, k + 1)
            board[i][j] = tmp
            return res

        for i in range(len(board)):
            for j in range(len(board[0])):
                if dfs(i, j, 0): return True
        return False

九、打印从1 到最大的n位数

class Solution:
    def printNumbers(self, n: int) -> [int]:
        def dfs(x):
            if x == n:
                s = ''.join(num[self.start:])
                if s != '0': res.append(int(s))
                if n - self.start == self.nine: self.start -= 1
                return
            for i in range(10):
                if i == 9: self.nine += 1
                num[x] = str(i)
                dfs(x + 1)
            self.nine -= 1
        
        num, res = ['0'] * n, []
        self.nine = 0
        self.start = n - 1
        dfs(0)
        return res
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值