化繁为简解决leetcode第1289题下降路径最小和II

1289.下降路径最小和II

难度:困难

问题描述:

给你一个nxn整数矩阵grid,请你返回非零偏移下降路径数字和的最小值。

非零偏移下降路径定义为:从grid数组中的每一行选择一个数字,且按顺序选出来的数字中,相邻数字不在原数组的同一列。

示例1:

输入:grid=[[1,2,3],[4,5,6],[7,8,9]]

输出:13

解释:

所有非零偏移下降路径包括:

[1,5,9],[1,5,7],[1,6,7],[1,6,8],

[2,4,8],[2,4,9],[2,6,7],[2,6,8],

[3,4,8],[3,4,9],[3,5,7],[3,5,9]

下降路径中数字和最小的是[1,5,7],所以答案是13。

示例2:

输入:grid=[[7]]

输出:7

提示:

n==grid.length==grid[i].length

1<=n<=200

-99<=grid[i][j]<=99

问题分析:

对于非零偏移下降路径,只要考虑当前的一步,这一步是nXn矩阵中的一个索引值,比如n=4,这一步的索引值为2,则下一步的索引值只能取[0,1,3]中的一个,总的来看,下降路径的第一步可以在[0,1,2,...,n-1]选择,共有n种选择,从第二步到第n步都只有n-1种选择,所有总的下降路径共有n*(n-1)*(n-1)...*(n-1)种,即n*(n-1)**(n-1)种。对于一个4阶矩阵,下降路径共有4*3*3*3共108种。

把所有的非零偏移下降路径找到之后,对于其中的每一种路径,根据索引值依次找到矩阵中对应元素的值,求出其和,然后找出其中的最小值输出即可。

为此,对于一个nxn矩阵,为了找到所有非零偏移下降路径,我们将这个问题分解为几个小问题,分别进行处理,然后再组合起来,实现这一功能。

第一步是对于一个索引值,我们如何找到下一步的非零偏移索引值,为此设计函数get_different_nums(n,i),此函数功能是对有n个元素的列表,根据上一步索引值i,找出下一步的非零偏移索引值,并形成列表返回。

第二步是对于一个给定的nxn矩阵、已经形成路径K和向下产生的非零偏移索引值,将已经形成的路径 k与向下产生的非零偏移索值组成新的路径,为此设计函数 get_one_step_group(n,k),n表示索引值有n个,k表示已经生成的向下非零偏移路径。

第三步是在n个元素的索引值列表[0,1,2,......,n-1]中选一个索引值,生成由这个索引值开始的非零偏移下降路径列表,为此设计函数get_one_all(n,i),其中的i表示下降路径的第一个索引值。

第四步是生成所有的非零偏移下降路径列表,为此设计函数get_all_down_path(n)。

第五步是设计计算求一条非零偏移向下路径的和并返回的函数get_one_path_sum(path,grid),path是一条非零偏移下降路径,grid是一个nxn矩阵。

最后根据所有的路径,依次求出每一条路径的元素和,并输出其最小值,问题得以解决。

程序如下:

#已知索引值[0,1,...n-1]中的一个索引值i,找出与这个索引值不同的所有索引值并以列表返回
def get_different_nums(n,i):
    b=list(range(n))
    b.remove(i)
    return b

#对于一个给定的nxn矩阵,找到已经形成的路径K与下一步非零偏移索引值组成的所有新路径
def get_one_step_group(n,k):
    a=[]
    for i in k:
        c=i[-1]
        b=get_different_nums(n,c)
        for j in b:
            d=i+[j]
            a.append(d)
    return a

#找出从索引值i开始在矩阵nXn中所有不同的非零偏移下降组合
def get_one_all(n,i):
    a=[[i]]
    for j in range(n-1):
        b=get_one_step_group(n,a)
        a=b
    return a

#对于一个nxn矩阵,找到所有非零偏移下降路径
def get_all_down_path(n):
    a=[]
    for i in range(n):
        b=get_one_all(n,i)
        a.extend(b)
    return a

#求一条非零偏移向下路径的和并返回
def get_one_path_sum(path,grid):
    n=len(grid)
    a=list(range(n))
    b=list(zip(a,path))
    min_sum=0
    for i in b:
        min_sum=min_sum+grid[i[0]][i[1]]
    return min_sum

#主程序
grid=eval(input('pls input grid='))
#取得所有非零向下偏移路径
a=get_all_down_path(len(grid))
print('所有非零偏移向下路径:',a)
#将取得的所有非零向下偏移路径中的第一条路径和求出并赋值给min_sum
print('索引路径:',a[0],end='     ')
min_sum=get_one_path_sum(a[0],grid)
print('和为:',min_sum)
print('最小和为:',min_sum)
#遍历剩下的所有路径并求和,找出最小和
for i in a[1:]:
    b=get_one_path_sum(i,grid)
    print('索引路径:',i,end='     ')
    print('和为:',b)
    if b<min_sum:
        min_sum=b
    print('最小和为:',min_sum)
#打印最小和
print('所有非零偏移下降路径最小和为:',min_sum)

运行实例一

pls input grid=[[3,2,1],[0,2,4],[4,3,1]]

所有非零偏移向下路径: [[0, 1, 0], [0, 1, 2], [0, 2, 0], [0, 2, 1], [1, 0, 1], [1, 0, 2], [1, 2, 0], [1, 2, 1], [2, 0, 1], [2, 0, 2], [2, 1, 0], [2, 1, 2]]

索引路径: [0, 1, 0]     和为: 9

最小和为: 9

索引路径: [0, 1, 2]     和为: 6

最小和为: 6

索引路径: [0, 2, 0]     和为: 11

最小和为: 6

索引路径: [0, 2, 1]     和为: 10

最小和为: 6

索引路径: [1, 0, 1]     和为: 5

最小和为: 5

索引路径: [1, 0, 2]     和为: 3

最小和为: 3

索引路径: [1, 2, 0]     和为: 10

最小和为: 3

索引路径: [1, 2, 1]     和为: 9

最小和为: 3

索引路径: [2, 0, 1]     和为: 4

最小和为: 3

索引路径: [2, 0, 2]     和为: 2

最小和为: 2

索引路径: [2, 1, 0]     和为: 7

最小和为: 2

索引路径: [2, 1, 2]     和为: 4

最小和为: 2

所有非零偏移下降路径最小和为: 2

运行实例二

pls input grid=[[2,1],[1,3]]

所有非零偏移向下路径: [[0, 1], [1, 0]]

索引路径: [0, 1]     和为: 5

最小和为: 5

索引路径: [1, 0]     和为: 2

最小和为: 2

所有非零偏移下降路径最小和为: 2

运行实例三

pls input grid=[[3]]

所有非零偏移向下路径: [[0]]

索引路径: [0]     和为: 3

最小和为: 3

所有非零偏移下降路径最小和为: 3

要善于化繁为简,把复杂问题分解为很多简单小问题,也许问题就不在有难度,大道至简!诚如斯言。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值