动态规划(上)

2023-11-14

在这里插入图片描述

题目一:109 · 数字三角形 - LintCode

image-20220503220401906

分治
利用递归可以很快的写出程序

class Solution {
public:
    int traverse(vector<vector<int>> &triangle,int x,int y)
    {
        int n=triangle.size();
        if(x==n)    return 0;
        return triangle[x][y]+min(traverse(triangle,x+1,y),traverse(triangle,x+1,y+1));
    }
    int minimumTotal(vector<vector<int>> &triangle) {
        int ret=traverse(triangle,0,0);
        return ret;
    }
};

image-20220503220424420

简单是简单,但是由于在计算的过程中,每一个位置都有重复计算,时间复杂度达到了O(2^N);

记忆化搜索

    int traverse(vector<vector<int>> &triangle,int x,int y)
    {
        int n=triangle.size();
        if(x==n)    return 0;
        if(hash[x][y]!=INT_MAX)
        {
            //如果已经被遍历过
            return hash[x][y];
        }
        hash[x][y]=triangle[x][y]+min(traverse(triangle,x+1,y),traverse(triangle,x+1,y+1));
        return hash[x][y];
    }

自底而上的动态规划

class Solution {
public:
    int minimumTotal(vector<vector<int>> &triangle) {
        int n=triangle.size();
        vector<int>sum{triangle.back()};
        for(int i=n-2;i>=0;i--)
        {
            for(int j=0;j<=i;j++)
            {
                sum[j]=triangle[i][j]+min(sum[j],sum[j+1]);
            }
        }
        return sum[0];
    }
};

自顶而下的动态规划
自顶而下的动态规划思维更直接,思路更简单

class Solution {
public:
    int minimumTotal(vector<vector<int>> &triangle) {
        //开数组
        if(triangle.size()==0)  return 0;
        vector<int> f(triangle[triangle.size()-1].size());
        //按照一般的想法,应该是开二维数组,但是下一层的f[][]都是来着于上一层的f[][]再加上最短距离
        //所以开一维数组就可以完成动态规划,此时f[i]存放的是到第i层的第i个位置的最短距离;
        f[0]=triangle[0][0];
        //由于数字三角形的最左边和左右边都只有一条路,所以只有一种可能
        for(int i=1;i<triangle.size();i++)
        {
            //倒着遍历,因为需要使用上一层的最短距离的结果,如果是正着遍历
            //那么上一层的最短距离还没有被使用就被修改掉
            for(int j=triangle[i].size()-1;j>=0;j--)
            {
                if(j==0)    
                    f[j]=triangle[i][j]+f[j];
                else if(j==triangle[i].size()-1)
                    f[j]=triangle[i][j]+f[j-1];
                else
                    f[j]=min(f[j],f[j-1])+triangle[i][j];
            }
        }
        int ret=INT_MAX;
        for(int i=0;i<f.size();i++)
        {
            ret=min(ret,f[i]);
        }
        return ret;
    }
};

题目二:110 · 最小路径和 - LintCode

image-20220503231604961

class Solution {
public:

    int minPathSum(vector<vector<int>> &grid) {
        if(grid.size()==0||grid[0].size()==0)
            return 0;
        //开数组,
        int f[1000][1000];
        f[0][0]=grid[0][0];
        //第一行和第一列为特殊路径
        for(int i=1;i<grid.size();i++)
            f[i][0]=grid[i][0]+f[i-1][0];
        for(int j=1;j<grid[0].size();j++)
            f[0][j]=grid[0][j]+f[0][j-1];
        //一般的情况
        for(int i=1;i<grid.size();i++)
        {
            for(int j=1;j<grid[0].size();j++)
            {
                f[i][j]=grid[i][j]+min(f[i-1][j],f[i][j-1]);
            }
        }
        return f[grid.size()-1][grid[0].size()-1];
    }
};

题目三:114 · 不同的路径 - LintCode

image-20220503231533440

class Solution {
public:
    int uniquePaths(int m, int n) {
        vector<vector<int>> dp(m,vector<int>(n));
        if(m==0||n==0)  return 1;
        dp[0][0]=1;
        //初始化第一行和第一列
        for(int i=1;i<m;i++)
        {
            dp[i][0]=1;
        }
        for(int j=1;j<n;j++)
        {
            dp[0][j]=1;
        }
        for(int i=1;i<m;i++)
        {
            for(int j=1;j<n;j++)
            {
                dp[i][j]=dp[i-1][j]+dp[i][j-1];
            }
        }
        return dp[m-1][n-1];
    }
};

题目四:LintCode - LintCode

image-20220503231628804

class Solution {
public:
    bool canJump(vector<int> &a) {
        if(a.size()==0)
            return true;
        vector<bool> dp(a.size());
        dp[0]=true;
        for(int i=1;i<a.size();i++)
        {
            for(int j=0;j<i;j++)
            {
                if(dp[j]&&j+a[j]>=i)
                {
                    dp[i]=true;
                    break;
                }
            }
        }
        return dp[a.size()-1];
    }
};

题目五:117 · 跳跃游戏 II - LintCode

image-20220503231653993

class Solution {
public:
    int jump(vector<int> &a) {
        vector<int> dp(a.size());
        dp[0]=0;
        for(int i=1;i<a.size();i++)
        {
            //假设目前需要的步数很大
            dp[i]=INT_MAX;
            for(int j=0;j<i;j++)
            {
                //如果可以从j跳到i
                if(j+a[j]>=i)
                {
                    dp[i]=min(dp[i],dp[j]+1);
                }
            }
        }
        return dp[a.size()-1];
    }
};

题目六:76 · 最长上升子序列 - LintCode

image-20220503232835873

这道题属于很经典的动态规划题,也是面试中的高频题目

算法思路
  • 因为所求为子序列,很容易想到一种线性动态规划。
  • 对于求最长上升子序列,上升我们肯定需要知道当前阶段最后一个元素为多少,最长我们还要知道当前我们的序列有多长。
  • 那么我们就可以这样定义状态:设 dp[i] 表示以 nums[i] 为结尾的最长上升子序列的长度,为了保证元素单调递增肯定只能从 i 前面且末尾元素比 nums[i] 小的状态转移过来
代码思路
  • 状态转移方程为

    dp[i]=max0≤j<i,nums[j]<nums[i]dp[j]+1dp[i]=max0≤j<i,nums[j]<nums[i]dp[j]+1

  • 每个位置初始值为 dp[i]=1(将自己作为一个序列)

  • 答案可以是任何阶段中只要长度最长的那一个,所以我们边转移边统计答案

class Solution {
public:
    int longestIncreasingSubsequence(vector<int> &nums) {
       if(nums.size()==0)   return 0;
        //设置初始的最大值
       int ret=1;
       vector<int> dp(nums.size());
       for(int i=0;i<nums.size();i++)
       {
           dp[i]=1;
           for(int j=0;j<i;j++)
           {
               //如果以nums[j]的值小于nums[i],更新dp[i];
               if(nums[j]<nums[i])
               {
                   dp[i]=max(dp[i],dp[j]+1);
               }
           }
           //更新最长子序列的最大值
           ret=max(ret,dp[i]);
       } 
       return ret;
    }
};

除了上面的一般动态规划,还可以使用二分对其进行优化

算法思路
  • dp[i] 表示长度为 i 的最长上升子序列的末尾元素的最小值,显然这个数组的权值一定单调不降。
  • 于是我们按顺序枚举数组nums,每一次对dp数组二分查找,找到小于nums[i]的最大的 dp[j],并更新 dp[j+1]
class Solution {
public:
    int longestIncreasingSubsequence(vector<int> &nums) 
    {
        if (nums.size() == 0)
        {
            return 0;
        }
        int dp[nums.size() + 1];
        int ans = 1;
        dp[0] = 0;
        dp[1] = nums[0];
        for (int i = 1; i < nums.size(); i++) {
            // nums[i]比最长的末尾元素的都大,直接更新
            if (nums[i] > dp[ans]) 
            {
                ans++;
                dp[ans] = nums[i];
            }
            else 
            { // 二分查找nums[i]可以放到dp数组的哪个数后面
                int left = 1;
                int right = ans;
                while (left < right)
                {
                int mid = (left + right) / 2;
                    if (nums[i] <= dp[mid])
                    {
                        right = mid;
                    }
                    else
                    {
                        left = mid + 1;
                    }
                }
                int j = left - 1;
                dp[j + 1] = min(nums[i], dp[j + 1]);
            }
        }
        return ans;
    }
};
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

动态规划(上) 的相关文章

  • STM32 基础系列教程 30 - 文件系统

    前言 学习stm32中FATFS 文件系统的基础使用 学会文件的打开及读写删除等基本操作 理解文件系统基本概念 示例详解 基于硬件平台 STM32F10C8T6最小系统板 MCU 的型号是 STM32F103c8t6 使用stm32cube
  • 学习HC-SR04超声波测距模块,代码附带卡尔曼滤波

    硬件引脚 VCC 供5V的电压 一定要是5v GND 接地 Trig HC SR04超声波测距模块上的触发引脚 用于向模块发送一个10微秒的高电平触发信号 触发模块开始进行距离测量 Echo 用于接收超声波回波信号的引脚 工作原理 使用HC
  • js根据本地文件路径上传文件(流上传)

    最近使用vue做了个项目 把本地指定url下的png图片上传 废话不多说 直接上代码 var fs require fs 需要引入nodejs中的文件操作部分 var http require http 需要引入nodejs中http请求部

随机推荐

  • 软件自动化测试工具/平台的挑战

    今天在微信读书偶然读到 高效自动化测试平台 设计与开发实战 作者徐德晨和茹炳晟 该书1 2章节详细讲述了软件自动化测试工具 平台的七个挑战 下面结合一站式开源持续测试平台项目MeterSphere详解这七个挑战 GitHub metersp
  • linux系统编程-1、基础知识

    前言 Linux系统编程的基础系列文章 随着不断学习会将一些知识点进行更新 前期主要是简单了解和学习 文章目录 shell bash 命令和路经补齐 历史记录 目录和文件 类Unix系统目录结构 用户目录 ls cd which pwd m
  • 请用美丽欢呼-------Day38

    周末 双休 疯了两天 敲了寥寥的代码 却没少看了相关的文章 这电子书大行于世的年代 对工具的漠然简直就是对生命的亵渎 颠簸的公交车上算是告别了YY的惬意 这生活 感觉傻了点 可真够味 原本只是想写篇 html的发展历程 的 可XHTML 2
  • Java并发编程:并发容器之CopyOnWriteArrayList(转载)

    http www cnblogs com dolphin0520 p 3938914 html 原文链接 http ifeve com java copy on write Copy On Write简称COW 是一种用于程序设计中的优化策
  • 基于YOLOv8模型和CrowdHuman数据集的行人检测系统(PyTorch+Pyside6+YOLOv8模型)

    摘要 基于YOLOv8模型和CrowdHuman数据集的行人目标检测系统可用于日常生活中检测与定位行人 Human 利用深度学习算法可实现图片 视频 摄像头等方式的目标检测 另外本系统还支持图片 视频等格式的结果可视化与结果导出 本系统采用
  • python 利用表格批量修改文件夹(包括子文件夹)下所有文件名

    首先是获得需要修改文件的路径放入xlsx中 我一般直接在系统的搜索框中搜索 然后全选复制路径 偷个小懒 也可以再写个自动遍历所有文件获取地址 点击这个复制路径即可复制全部选中文件的路径 直接复制在表格第一列即可 便于读取 然后按照自己实际的
  • SQL调优的几个方法

    1 为什么调优 好处是什么 SQL语句在编写之后 对于数据量较少的表基本没有什么性能上的需求 但是如果考虑到性能方面的话 SQL语句优化就是必须的 2 如何调优 调有点方法有哪些 1 对查询进行优化 应尽量避免全表扫描 首先考虑在where
  • node 版本管理器 --- Volta

    鲸腾FE 来自恒生鲸腾网络 是一支专注于 web 前端的开发团队 并在 web 前端领域积累了多年疑难问题解决经验 崇尚高效 优质 成长 自由 快乐 前言 在我们的日常开发中经常会遇到这种情况 手上有好几个项目 每个项目的需求不同 然而不同
  • uniapp 原生安卓开发插件(module),以及android环境本地调试(一)

    uniapp 原生安卓开发插件 module 以及android环境本地调试 1 开发前景 由于uniapp 框架的局限先 有很多功能不能如原生android开发使用顺畅 因此 需要使用插件进行辅助 再由uniapp引入插件 使得功能完善
  • Linux设备驱动开发详解总结(二)之并发与竞争

    转载地址 http blog csdn net lwj103862095 article details 8548500 Linux设备驱动中必须解决一个问题是多个进程对共享资源的并发访问 并发的访问会导致竞态 在当今的Linux内核中 支
  • Netty:ByteBuf写入数据、读出数据

    介绍 Netty的ByteBuf数据位置索引是从0开始的 类似于数组 getByte int index 从指定位置读出一字节 这个操作不会改变ByteBuf的readerIndex或者 writerIndex 的位置 这个操作也不受rea
  • Ubuntu16.04系统安装tensorflow(GPU)

    作者 冯拓 电脑配置如下 配置 HP Z820 CPU核心线程数和主频 intel xeon 至强 E 5 2620 2 0GHz 24 内存 64GB 硬盘 2TB 显卡 NIVDIA TITAN X 12GB 安装过程中使用的安装包 安
  • 用Java实现杨辉三角

    给定一个非负整数 numRows 生成 杨辉三角 的前 numRows 行 在 杨辉三角 中 每个数是它左上方和右上方的数的和 示例 1 输入 numRows 5 输出 1 1 1 1 2 1 1 3 3 1 1 4 6 4 1 示例 2
  • Go语言的大小写

    初学者经常犯Go大小写默认的错误 即在包外引用小写的常量 函数提示错误 对于刚接触Go语言的人会觉得莫明其妙 原因是 Go语言中 常量 函数的首字母大写表示对外公开的相当于Java的public 小写表示私有的相当于Java的private
  • Vue element 二级菜单绑定示例

    2019独角兽企业重金招聘Python工程师标准 gt gt gt 一 element ui 中动态绑定二级菜单示例 1 视图绑定
  • 软考高项之风险管理-攻坚记忆

    软考高项之风险管理 攻坚记忆 一 项目风险管理概述 1 风险相关概念及性质 2 风险分类 二 风险管理的ITO 1 风险管理过程组 规划风险管理ITO 2 风险管理过程组 识别风险ITO 3 风险管理过程组 实施定性风险分析ITO 4 风险
  • Three.js 模型添加标签

    在很多的实际的项目中 你可能需要给一个Three js的模型添加标签 那么我们可以使用three js的精灵模型来表示 使用精灵模型表示一个模型对象的标签 那么精灵模型就要位于模型对象的附近 可以获得要标注模型的世界坐标 然后来设置精灵标签
  • java cron表达式 每天凌晨两点_定时任务的cron表达式

    前言 对于开发人员来说 在做项目的过程中或多或少都会用到定时任务 Java开发一般会用Spring Quartz xxl job Elastic job来做定时任务调度框架 不论使用哪种框架 定时任务表达式都是必不可少的 平时配置cron表
  • linux的TCP连接数量最大不能超过65535个吗,那服务器是如何应对百万千万的并发的?

    首先 问题中描述的65535个连接指的是客户端连接数的限制 在tcp应用中 server事先在某个固定端口监听 client主动发起连接 经过三路握手后建立tcp连接 那么对单机 其最大并发tcp连接数是多少呢 如何标识一个TCP连接 在确
  • 动态规划(上)

    题目一 109 数字三角形 LintCode 分治 利用递归可以很快的写出程序 class Solution public int traverse vector