三角形最小路径和120-力扣(二维数组+DP+c | py)

题目描述:
给定一个三角形 triangle ,找出自顶向下的最小路径和。

每一步只能移动到下一行中相邻的结点上。相邻的结点 在这里指的是 下标 与 上一层结点下标 相同或者等于 上一层结点下标 + 1 的两个结点。也就是说,如果正位于当前行的下标 i ,那么下一步可以移动到下一行的下标 i 或 i + 1 。

示例 1:

输入:triangle = [[2],[3,4],[6,5,7],[4,1,8,3]]
输出:11
解释:如下面简图所示:
2
3 4
6 5 7
4 1 8 3
自顶向下的最小路径和为 11(即,2 + 3 + 5 + 1 = 11)。
示例 2:

输入:triangle = [[-10]]
输出:-10

提示:

1 <= triangle.length <= 200
triangle[0].length == 1
triangle[i].length == triangle[i - 1].length + 1
-104 <= triangle[i][j] <= 104

来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/triangle
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。


Note:

int minimumTotal(int** triangle, int triangleSize, int* triangleColSize)
对于力扣给的函数定义,简单说明一下:

  • triangle参数:是指存放二维数组每行的指针的数组 的指针,有点绕口,其实就是用一个指针去指向存放指针的数组,这主要是因为c语言中列数不等长的二维数组,可以通过先建立每行的数组,然后将每行数组的指针存放到一个新的数组里面,最后用一个指针来指向这个数组。
  • triangleSize:是指的二维数组的行数,也就是存放一维数组的指针的数组的长度。
  • triangleColSize:是指的存放每一行的列数的数组的指针。
  • 只有传入这三个参数才可以去操作这个二维数组。

用下面的例子简单说明一下:

int a1[1] = {0};  //第一行
int a2[2] = {0};  //第二行
int a3[3] = {0};  //第三行
int *a[3] = {a1, a2, a3};  //指针数组
int **p;  //指向指针的指针
p = a;  //令该指针指向盛放二维数组每行的起始地址。

后面只需要将p、a[3]的大小、a[3]中的每个一维数组的长度放到一个数组里形成的数组,传到函数里面就可以了。

而至于访问二维数组中的元素通过p指针就可以了,如p[0][0]就是访问二维数组中的第一行第一列的元素。

因为力扣刷题是函数式编程的方式,相当于给你函数的定义,然后去实现这个函数,而函数中为了跑一些测试用例的方便,所以以指针的形式作为形参,这样直接修改原数据而指针不用改变。


回归正题,分析下这个题目:
分析

画格子,写出递推方程,根据递推的顺序,来遍历格子,然后写代码。
在这里插入图片描述
这道题目比较经典,递推公式也比较容易写出来:
f ( i , j ) = m i n { f [ i + 1 ] [ j ] , f [ i + 1 ] [ j + 1 ] } + a [ i ] [ j ] f(i, j) =min\{ f[i+1][j],f[i+1][j+1] \} + a[i][j] f(i,j)=min{f[i+1][j],f[i+1][j+1]}+a[i][j]

上述式子采用自底向上的递推: f ( i , j ) f(i,j) f(i,j)表示从底端到 f ( i , j ) f(i,j) f(i,j)处的最短路径
代码实现如下:

int minimumTotal(int** triangle, int triangleSize, int* triangleColSize){
    for(int i=triangleSize-2;i>=0;--i){
        for(int j=0;j<=i;++j){
            triangle[i][j]=fmin(triangle[i+1][j],triangle[i+1][j+1])+triangle[i][j];
        }
    }
    return triangle[0][0];
}

另一种方式:像上面这种方式,直接将结果存在了原来的triangle中了,如何才能不改动原来的二维数组,当然也可以直接建立一个新的二维数组,如果还想进一步节省空间的话,可以通过建立一个一维数组来保存当前状态,具体如下:

int minimumTotal(int** triangle, int triangleSize, int* triangleColSize){
    //由于不需要保存所有的状态,而且当前状态只和上一状态有关
    //因此只需要一个一维数组
    int *res = (int*)malloc(sizeof(int) * triangleColSize[triangleSize-1]);
    //结果最后一行就是原来的最后一行
    memcpy(res, triangle[triangleSize - 1], 
                sizeof(int) * triangleColSize[triangleSize-1]);
    //从最后第2行开始递推
    for (int i = triangleSize - 2; i >= 0 ; i-- ){
        for ( int j = 0 ; j < triangleColSize[i]; j++){
            //第(i,j)元素的值为(i+1,j), (i+1,j+1)中的最小值
            res[j] = fmin(res[j], res[j+1]) + triangle[i][j];
        }
    }
    return res[0];
}

本地测试完整代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

int minimumTotal(int** triangle, int triangleSize, int* triangleColSize){
    int *res = (int*)malloc(sizeof(int) * triangleColSize[triangleSize - 1]);
    memcpy(res, triangle[triangleSize - 1], sizeof(int) * triangleColSize[triangleSize-1]);

    for(int i = triangleSize - 2; i >= 0; --i)
    {
        for(int j = 0; j < triangleColSize[i]; j++)
        {
            res[j] = fmin(res[j], res[j+1]) + triangle[i][j];
        }
    }
    return res[0];

}
int main() {
     //二维数组每行的元素
     int a1[1] = {2};
     int a2[2] = {3, 4};
     int a3[3] = {6, 5, 7};

     //存放二维数组每行的起始地址的指针数组
     int *a[3] = {a1, a2, a3};

     //设置一个指针,指向存放各行指针的数组
     int **p;
     p = a;

     int pSize = 3; //二维数组的行数

     int columnSize[3] = {1, 2, 3};  //二维数组每行的列数

     int res = minimumTotal(p, pSize, columnSize);
     printf("%d", res);
}

附:python3版本代码:

```python
class Solution:
    def minimumTotal(self, triangle: List[List[int]]) -> int:
        i = len(triangle) - 2
        for i in range(i, -1, -1):
            for j in range(i, -1, -1):
                triangle[i][j] += min(triangle[i+1][j], triangle[i+1][j+1])
        return triangle[0][0]


class Solution:
    def minimumTotal(self, triangle: List[List[int]]) -> int:
        i = len(triangle) - 1
        res = [x for x in triangle[i]]
        for i in range(len(triangle)-2, -1, -1):
            for j in range(len(triangle[i])):
                res[j] = min(res[j], res[j+1]) + triangle[i][j]
            i -= 1
        return res[0]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爱学习的贝塔

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值