IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 【动态规划】三角矩阵 -> 正文阅读

[数据结构与算法]【动态规划】三角矩阵


三角矩阵之类的题主要就是求最小距离,之后遇见有关于矩阵、网格、字符串间的比较问题,用一维动归难以解决或者难以理解的情况下,可以考虑着用二维动归,接下来就用三角矩阵案例来介绍一下动归问题的各种思想。

牛客链接

题目:给出一个三角形,计算从三角形顶部到底部的最小路径和,每一步都可以移动到下面一行相邻的数字,例如,给出的三角形如下:

[[20],[30,40],[60,50,70],[40,10,80,30]]

最小的从顶部到底部的路径和是20 + 30 + 50 + 10 = 110。

自顶向下

在这里插入图片描述

分析思路:

想要用自顶向下的方法求最短路径之和就需要求从坐标(0, 0)到(i,j)的最小路径之和,最后在三角矩阵的最后一行必然都是到达该点的最短路径和,只需要遍历最后一行,找到其中最小的路径之和就解决了问题

每一个元素都有两种移动路径,坐标(i,j)可以移动到坐标(i+1,j)和(i+1,j+1)处

移动到坐标(i,j)处有出现三种可能

  1. 坐标中的列坐标为0时(i,0),移动到该点的坐标只可能是坐标(i-1, 0)
  2. 坐标中行坐标和列坐标相同时(例如(1, 1)之类的),移动到该坐标的只可能是坐标(i-1,j-1)
  3. 其他情况下,移动到该坐标都有两个坐标(i-1,j-1)和(i-1,j)

那么在求最短路径和时只需要将该坐标的值加上到达该坐标前的最短路径和

将状态设置为F(i,j) :从(0,0)坐标到(i,j)坐标的最短路径和

例如

F(0,0)= 20;

F(1,0)= F(0,0)+ 30 = 50 ;F(1,1)= F(0,0)+ 40 = 60;

F(2,1) = min(F(1,0),F(1,1))+ 50 = 100;

综上所述:

  1. 状态定义F(i,j):从(0,0)坐标到(i,j)坐标的最短路径和
  2. 状态间的转移方程定义F(i,j):
  • min(F(i-1,j-1),F(i-1,j)) + path[i][j] (0 < j < i)
  • F(i-1,0) + path[i][0] (j == 0)
  • F(i-1,j-1) + path[i][j] (i == j)
  1. 状态的初始化F(0,0) = path[0][0]
  2. 返回结果min(F(row-1,j))
import java.util.*;
public class Solution {
    public int minimumTotal(ArrayList<ArrayList<Integer>> triangle) {
        if(triangle==null||triangle.isEmpty()) return 0;//若出现传入的线性表为空或没有元素的情况,返回0
        int row = triangle.size();//triangle的大小就是三角矩阵的行
        int[][] path = new int[row][row];//定义path二维数组来存放三角矩阵中每个坐标的状态即最短路径和
        path[0][0] = triangle.get(0).get(0);//状态的初始化
        for(int i = 1;i < row;i ++) {
            for(int j = 0;j <= i;j ++) {
                if(j == 0) {
                    path[i][j] = path[i-1][j] + triangle.get(i).get(j);//转移方程的情况二
                } else if(i == j) {
                    path[i][j] = path[i-1][j-1] + triangle.get(i).get(j);//转移方程的情况三
                }else {
                    path[i][j] = Math.min(path[i-1][j],path[i-1][j-1]) + triangle.get(i).get(j);
                    //转移方程的情况一
                }
            }
        } 
        int min = path[row-1][0];
        //将三角矩阵状态最后一行的第一个元素当为最小路径和,通过遍历最后一行找到最小的路径和
        for(int j = 1;j < row;j ++) {
            if(path[row-1][j] < min) 
                min = path[row-1][j]; 
        }
        return min;//返回最小路径和
    }
}

自底向上

事实上,比起自顶向下,自底向上的方法会更加简单,也更方便理解

分析思路:

自底向上的思路,设置的状态是从坐标(i,j)到最后一行的最短距离,这就需要三角矩阵的最后一行不变(初始化条件)。另外,三角矩阵的每个元素(除了最后一行)都有两种移动路径,就可以避免了上一种思路中转移方程需要考虑各种情况的麻烦,最后坐标(0,0)处的数值就是三角矩阵最短路径和。

例如

F(3,0)= 40;F(3,1)=10;

F(2,0) = min(F(3,0),F(3,1))+ 60 = 70;

综上所述:

  1. 状态定义F(i,j):从(i,j)坐标到最后一行的最短路径和

  2. 状态间的转移方程定义F(i,j):min(F(i+1,j),F(i+1,j+1)) + path[i][j] (0 <= j <= i)

  3. 状态的初始化F(row-1,0) = path[row-1][j]

  4. 返回结果F(0,0)

import java.util.*;
public class Solution {
    public int minimumTotal(ArrayList<ArrayList<Integer>> triangle) {
        if(triangle==null||triangle.isEmpty()) return 0;//若出现传入的线性表为空或没有元素的情况,返回0
        int row = triangle.size();//triangle的大小就是三角矩阵的行
        int[][] path = new int[row][row];//定义path二维数组来存放三角矩阵中每个坐标的状态即最短路径和
        //状态最后一行的值为三角矩阵最后一行原来的值
        for(int j = 0;j < row;j++) {
            path[row -1][j] = triangle.get(row -1).get(j); //状态的初始化
        }
        //从倒数第二行开始
        for(int i = row-2;i >= 0;i--) {
            for(int j = 0;j <= i;j++) {
                path[i][j] = Math.min(path[i+1][j],path[i+1][j+1]) + triangle.get(i).get(j);//状态转移
            }
        }
        return path[0][0];//返回最后结果
    }
}

O(N)空间

事实上,可以只用O(N)的额外的空间来完成这项工作,其中N是三角形中的行总数。

主要的思路和自底向上的思路是差不多的,只是存储的方式出现了差别,不再将每个坐标的状态单独放在数组里。这里选择用大小为三角矩阵的行数的一维数组来存状态。

在这里插入图片描述

import java.util.*;
public class Solution {
   public int minimumTotal(ArrayList<ArrayList<Integer>> triangle) {
       if(triangle==null||triangle.size()==0){
           return 0;
       }
       int row=triangle.size();
       int[]path=new int[row];
       //初始化状态
       for(int j=0;j<row;j++){
           path[j]=triangle.get(row-1).get(j);
       }
       for(int i=row-2;i>=0;i--){
           for(int j=0;j<=i;j++){
               path[j]=triangle.get(i).get(j)+Math.min(path[j],path[j+1]);//状态转移
           }
       }
       return path[0];//返回结果
   }
}

完!

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2021-12-14 16:12:59  更:2021-12-14 16:13:29 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 16:44:10-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码