leetcode-----寻找不同路径1,2,3(动态规划、回溯法)

[一]  不同路径1,图中无障碍

在判断一个问题能不能使用动态规划解决时,首先要判断:

1. 每个阶段的状态或值是否能通过上一阶段的状态或值推导出来 (满足)

2. 每个阶段的状态或值一旦决定,是不受后面阶段的状态或值影响的 (满足)

3. 是否有重复子问题的计算 (满足)

4. 是否有边界 (满足)

 

下面仔细讲上述4个点:

1.。 每个阶段的状态或值是否能通过上一阶段的状态或值推导出来

    由于题目说,机器人只能往右或者往下走。设置  d(i,j)表示 从起点走到 i 列 j 行位置总共的路径数。则d(i,j)可以表示为:

d(i,j) = d(i-1,j)+d(i,j-1)

这就叫做 每个阶段的状态或值可以通过上一阶段的状态或值推导出来 。

2.。 每个阶段的状态或值一旦决定,是不受后面阶段的状态或值影响的

因为题目说明,只能往右,下走,不能往左,上方向走。因此当前阶段是不会受到后面阶段的影响的。

3.。 是否有重复子问题的计算

d(i,j) = d(i-1,j)+d(i,j-1)

满足整个问题,没有特殊例子。所以满足。

4.。是否有边界

d(i,0)和 d(0,j)就是问题的边界。 另外 d(i,0)和 d(0,j)都等于1。

 

代码:

def uniqePaths(m, n):
    cache = [ [1 for _ in range(m)] if j==0 else [1 if i==0 else None for i in range(m)] for j in range(n)]

    for x in range(1, n):  # 每一行就是一個階段,因為第一行已經知道結果了,所以從第二行開始
        for y in range(1, m):  # 每一個階段內部,因为第一列已经知道了,从第二列开始
            cache[x][y] = cache[x-1][y] + cache[x][y-1]
    return cache,cache[n-1][m-1]

def show(res):
    cache,n = res
    for i in cache:
        print(i)
    print('到达终点的路径总数有:{}'.format(n))
show(uniqePaths(4,5))

输出:

 

[二]  不同路径2,图中有障碍

图中有障碍,即有障碍那点不可到达。如:

思想:

1. 创建矩阵cache,记录某点的可到达路径数

2. 计算路径数时,用cache和输入矩阵grid比对,即,正常情况 cache[i][j] = cache[i][j-1]+cache[i-1][j],但如果 grid[i-1][j]==1,表示[i-1][j]处有障碍,所以cache[i][j] = cache[i][j-1]。同理,当grid[i][j-1]==1,则cache[i][j] = cache[i-1][j]。

class Solution(object):
    def uniquePathsWithObstacles(self, grid): #grid是输入矩阵,矩阵中0表示没障碍,1表示有障碍
        n = len(grid[0]) #列
        m = len(grid) #行

        if grid[0][0]==1:return 0  #若障碍点在入口,则直接返回0
        cache = [[0]*n for j in range(m)]  #初始化cache矩阵,cache用于记录 到达某点有多少种方法
        '''边界初始化,因为动态规划肯定得有边界'''
        cache[0][0] = 1
        for i in range(1,m):
            if grid[i][0]==1:cache[i][0]=0
            else:cache[i][0] = cache[i-1][0]
        for j in range(1,n):
            if grid[0][j]==1:cache[0][j]=0
            else:cache[0][j] = cache[0][j-1]
        '''正式开始用动态规划计算某点的可到达路径数'''
        for i in range(1,m):
            for j in range(1,n):
                if grid[i][j] == 1:
                    cache[i][j] = 0
                    continue
                if grid[i-1][j]==1:
                    cache[i][j] = cache[i][j-1]
                if grid[i][j-1]==1:
                    cache[i][j] = cache[i-1][j]
                if grid[i][j-1]==0 and grid[i-1][j]==0:
                    cache[i][j] = cache[i][j-1]+cache[i-1][j]
        print(cache)  #[[1, 1, 1], [1, 0, 1], [1, 1, 2]]
        return cache[-1][-1]

ss =Solution()
grid = [
  [0,0,0],
  [0,1,0],
  [0,0,0]
]
res=ss.uniquePathsWithObstacles(grid)
print(res)   #2

时间复杂度:O(mn),m、n表示输入矩阵的行数和列数

空间复杂度:O(mn),因为需要新建跟输入矩阵grid尺寸一样的矩阵cache

 

[三]  不同路径3,图中有障碍且图中所有格子都必须经过

思想:(回溯法)

创建一个字典(矩阵也可以)用于记录图中各个点是否已经经过。经过了为True,未经过为False。

从起始位置开始遍历,并修改每个遍历点的状态,如果到达结束位置,并且所有点的状态都为True,则是一条路径。遍历到结束位置后,回溯到上一个点,将该点状态重新修改为False,找新路径继续遍历。

class Solution:
    def uniquePathsIII(self,grid):
        from collections import defaultdict
        start = None
        end = None
        visited_dict = defaultdict(bool)
        row = len(grid)
        col = len(grid[0])

        for i in range(row):
            for j in range(col):
                if grid[i][j] == 1:
                    start = (i,j)
                elif grid[i][j] == 2:
                    end = (i,j)
                elif grid[i][j] == -1:
                    visited_dict[(i,j)] = True
                elif grid[i][j] == 0:
                    visited_dict[(i, j)]  = False
        visited_dict[start] = True
        self.counter = 0
        self.backTrace(start,end,visited_dict,grid,row,col)
        return self.counter

    def backTrace(self,cur,end,visited_dict,grid,row,col):
        if cur == end and all(visited_dict.values()):#结束回溯条件
            self.counter+=1
            return
        for x,y in [[-1,0],[1,0],[0,1],[0,-1]]: #上、下、左、右四个方向
            tmp_i = cur[0]+x
            tmp_j = cur[1]+y
            if 0<=tmp_i<row and 0<=tmp_j<col: #新坐标的边界判断
                if grid[tmp_i][tmp_j] == -1: #如果到了障碍点,则选择其他方向
                    continue
                else:
                    if visited_dict[(tmp_i,tmp_j)] == True: #若新坐标已经经过了,则下一个
                        continue
                    visited_dict[(tmp_i,tmp_j)] = True #走过的路标为True
                    #新坐标继续进行回溯
                    self.backTrace((tmp_i,tmp_j),end,visited_dict,grid,row,col)
                    visited_dict[(tmp_i,tmp_j)] = False

grid = [[1,0,0,0],[0,0,-1,0],[0,0,2,0]]
s = Solution()
res=s.uniquePathsIII(grid)
print(res)  #1

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值