深度优先搜索与动态规划|778, 403

深度优先搜索|778. 水位上升的泳池中游泳,403. 青蛙过河

778. 水位上升的泳池中游泳

写了一个普通的深度优先搜索,勉强写出来了但是超时了,走了一半的例子,21/43,应该是没问题的但是需要更多的剪枝,看了解析可以用二分法+深度优先搜索。

class Solution:
    def swimInWater(self, grid: List[List[int]]) -> int:
        n = len(grid)
        used = [[False]*n for _ in range(n)]
        t = [grid[0][0]]
        res = []
        def dfs(i,j):
            nonlocal t
            if i == n-1 and j == n-1:
                res.append(t[-1])
                return 
            used[i][j] = True
            for k1,k2 in [[i,j+1],[i+1,j],[i,j-1],[i-1,j]]:
                if res and t[-1] >= min(res): break
                if 0<=k1<n and 0<=k2<n and not used[k1][k2]:
                    #print(t)
                    if t[-1] >= grid[k1][k2]:
                        dfs(k1,k2)
                        used[k1][k2] = False
                    else:
                        t.append(grid[k1][k2])
                        dfs(k1,k2)
                        t.pop()
                        used[k1][k2] = False

                    
        dfs(0,0)
        #print(res)
        return min(res)

二分法+深度优先搜索

首先第一点,初始的时间(水位线)一定是grid[0][0]grid[n-1][n-1]里大的那个,也是节省时间的一步。
第二点就是如果起始时间就可以留到最后一格的,那肯定是最小的,也没必要继续二分了,直接输出。
第三点grid的最大值是 n 2 − 1 n^2-1 n21,也就是说时间是 n 2 n^2 n2肯定能留到最后一格,那么我们就可以以max(grid[0][0],grid[n-1][n-1])为left, n 2 − 1 n^2-1 n21为right来进行二分法,而这样写的话在dfs里也不用更新时间了,只需要判断能不能走通就行,因为二分的时候就可以判断。

class Solution:
    def swimInWater(self, grid: List[List[int]]) -> int:
        def dfs(t,i,j,used):
            if i == n-1 and j == n-1:
                return True
            used[i][j] = True
            for k1,k2 in [[i,j+1],[i+1,j],[i,j-1],[i-1,j]]:
                #这里不用改t了,小了直接就走不通
                if 0<=k1<n and 0<=k2<n and not used[k1][k2] and t >= grid[k1][k2]:
                    #print(t)
                    if dfs(t,k1,k2,used):
                        return True
            return False
                    
        n = len(grid)
        left = max(grid[0][0],grid[n-1][n-1])
        used = [[False]*n for _ in range(n)]
        if dfs(left,0,0,used):
            return left
        right = n**2 - 1
        while left <= right:
            mid = (left + right) // 2
            used = [[False]*n for _ in range(n)]
            if dfs(mid,0,0,used):
                right = mid - 1
            else:
                left = mid + 1
        return left

403. 青蛙过河

写了一个dfs,然后超时了,但是走了十多个了,写法应该没问题

class Solution:
    def canCross(self, stones: List[int]) -> bool:
        jump = [] 
        if stones[1]-stones[0] != 1:
            return False
        else:
            jump.append(stones[0])
        
        def dfs(i,jump):
            if i == stones[-1]:
                return True
            
            jump.append(i)
            st = jump[-1] - jump[-2]
            for k in [st,st+1,st-1]:
                if k > 0 and k+i in stones:
                    if dfs(k+i,jump):
                        return True 
                    #jump.pop()
            return False
        
        return dfs(stones[1],jump)

如果不要jump.pop()的话,就能到44/53,但是会出错,现在还不是很理解为啥44了才出问题。
开个作弊器把,想不出来了。

class Solution:
    def canCross(self, stones: List[int]) -> bool:
        if stones[1]-stones[0] != 1:
            return False 
        @functools.lru_cache(None)
        def dfs(i,step):
            if i == stones[-1]:
                return True
            
            for k in [step+1,step-1,step]:
                if k > 0 and k+i in stones:
                    if dfs(k+i,k):
                        return True 

            return False
        
        return dfs(stones[1],stones[1]-stones[0])
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值