动态规划(dp)初步学习案例讲解

 问题(来源:leetcode300):

给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。

子序列 是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的子序列。

示例 1:

输入:nums = [10,9,2,5,3,7,101,18]
输出:4
解释:最长递增子序列是 [2,3,7,101],因此长度为 4 。

示例 2:

输入:nums = [0,1,0,3,2,3]
输出:4

 举例说明:

从上述案例nums可以看出(1 2 4)或者(1 2 3)都可以是最长的一个答案,而我们只要求出他的长度即可。

方案一,暴力穷举:

暴力穷举往往是最简单也最容易想到的,通过一步步逐步筛选,逐步搜索进行穷举。将其通过循环逐步套取,把每个子序列都进行一遍搜索,完成答案的求解,取最长数列长度即可。

通过一个getLen函数进行最长子序列的求取,需要注意的是,当i取到序列的最后一位时,返回长度1,停止搜索,而当你本身被搜索时就是一个长度单位,所以每次搜索的maxlen初始长度为1。

时间复杂度:假定数组长度为n,即可生成2^n个子序列(数组中的每个数字可以选择取用或者不取用两个方式,n个长度,即可为2^n个),每个子序列都需要进行n次遍历,即为O(n),所以时间 复杂度为O(2^n)*O(n)。

#include <iostream>
#include <algorithm> 
#include <cmath> 
#include <vector> 
#include <chrono>

using namespace std;

int getLen(vector<int> num, int i) {
    if (i == num.size() - 1) return 1;
    int maxlen = 1;
    for (int j = i + 1;j < num.size();j++) {
        if (num[j] > num[i]) {
            maxlen = max(maxlen, getLen(num, j) + 1);
        }
    }
    return maxlen;
}

int main() {
    auto start = chrono::high_resolution_clock::now(); // 记录开始时间
    int nums[25] = { 1,5,2,4,3,7,15,35,61,2,58,64,9,15,3,44,12,33,65,15,22,49,85,2,34};
    int ans = 0;
    vector<int> num(nums, nums +25);
    for (int i = 0;i < num.size();i++) {
        ans = max(ans, getLen(num, i));
    }
    cout << ans << endl;
    auto end = chrono::high_resolution_clock::now(); // 记录结束时间
    auto duration = chrono::duration_cast<chrono::microseconds>(end - start); // 计算程序运行时间
    cout << "程序运行时间:" << duration.count() << "微秒" << endl;
    return 0;
}

算法优化:空间换时间

方案二,用哈希进行回溯剪枝:

由于在暴力穷举的过程中,存在当你访问过一个数据时又一次访问该数据,即如图,第一次在(1 2 4)中已经检索过4,而在后续过程中又一次访问了4(1 4),即可用空间来换取时间,创建一个哈希表进行记录存储最大子序列长度,即可减少访问步骤。

依然是通过getLen方法来获取最大子序列长度,不过本次加入了memo哈希表来进行数据存储,当memo中数据非0时,即表明该处内容已被检索,即可直接返回memo[i],减少搜索时间。

 时间复杂度大大减少

#include <iostream>
#include <algorithm> 
#include <cmath> 
#include <vector> 
#include <chrono>

using namespace std;
vector<int> memo(25);

int getLen(vector<int> num, int i) {
    if (i == num.size() - 1) return 1;
    if (memo[i] != 0) return memo[i];
    int maxlen = 1;
    for (int j = i + 1;j < num.size();j++) {
        if (num[j] > num[i]) {
            maxlen = max(maxlen, getLen(num, j) + 1);
        }
    }
    memo[i] = maxlen;
    return maxlen;
}

int main() {
    auto start = chrono::high_resolution_clock::now(); // 记录开始时间
    int nums[25] = { 1,5,2,4,3,7,15,35,61,2,58,64,9,15,3,44,12,33,65,15,22,49,85,2,34 };
    int ans = 0;
    vector<int> num(nums, nums + 25);
    for (int i = 0;i < num.size();i++) {
        ans = max(ans, getLen(num, i));
    }
    cout << ans << endl;
    auto end = chrono::high_resolution_clock::now(); // 记录结束时间
    auto duration = chrono::duration_cast<chrono::microseconds>(end - start); // 计算程序运行时间
    cout << "程序运行时间:" << duration.count() << "微秒" << endl;
    return 0;
}

方案三,改写成迭代形式:

通过反推的方式,从序列最后一位开始寻找最长子序列,逐步倒推归纳迭代,一直访问到第一位时的最长子序列,即可完成数据的搜寻访问。

实现方式:通过getLen方法来获取子序列最长长度,通过倒序搜索来寻找子序列中各自的最长数组长度,i从倒数第二位开始访问,由于倒数第一位一定是1,一直搜索到第一位,而j则是通过i+1到最后一位进行搜索,在找完各自的最长数组后,进行排序,找出最大值即可。

时间复杂度: 由于只进行了两个循环,即为O(n^2)。

#include <iostream>
#include <algorithm> 
#include <cmath> 
#include <vector> 
#include <chrono>

using namespace std;

int getLen(vector<int> num) {
    int n = num.size();
    vector<int> L(n,1);
    for (int i = n-2;i>=0;i--) {
        for (int j = i + 1;j < n;j++) {
            if (num[j] > num[i]) L[i] = max(L[i], L[j] + 1);
        }
    }
    sort(L.begin(), L.end());
    return L[n-1];
}

int main() {
    auto start = chrono::high_resolution_clock::now(); // 记录开始时间
    int nums[25] = { 1,5,2,4,3,7,15,35,61,2,58,64,9,15,3,44,12,33,65,15,22,49,85,2,34 };
    int ans = 0;
    vector<int> num(nums, nums + 25);
    cout << getLen(num) << endl;
    auto end = chrono::high_resolution_clock::now(); // 记录结束时间
    auto duration = chrono::duration_cast<chrono::microseconds>(end - start); // 计算程序运行时间
    cout << "运行时间:" << duration.count() << "微秒" << endl;
    return 0;
}

 动态规划思路总结:

  1.  使用穷举法完成暴力搜索,可画出递归树
  2. 在搜索过程中发现重复搜索的痕迹,即可用哈希表进行数据回溯剪枝
  3. 将计算的过程用迭代的方式表示出来

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/232717.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

HarmonyOS--ArkTS(1)--基本语法(1)

目录 基本语法概述 声明式UI描述 自定义组件 创建自定义组件 自定义组件的结构--struct &#xff0c;Component&#xff0c;build()函数 生命周期 基本语法概述 装饰器&#xff1a; 用于装饰类、结构、方法以及变量&#xff0c;并赋予其特殊的含义。如上述示例中Entry、C…

TypeScript基本语法

想在自己电脑上快速演示下方代码&#xff1f;点击ts官方演练场&#xff1a;https://www.typescriptlang.org/play 变量声明&#xff1a;TypeScript 在 Javascript的基础上加入了静态类型检查功能&#xff0c;因此每一个变量都有固定的数据类型。 //string: 字符串&#xff0c;…

GPT-4 变懒了?官方回复

你是否注意到&#xff0c;最近使用 ChatGPT 的时候&#xff0c;当你向它提出一些问题&#xff0c;却得到的回应似乎变得简短而敷衍了&#xff1f;对于这一现象&#xff0c;ChatGPT 官方给出了回应。 译文&#xff1a;我们听到了你们所有关于 GPT4 变得更懒的反馈&#xff01;我…

智能优化算法应用:基于蜉蝣算法3D无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于蜉蝣算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于蜉蝣算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.蜉蝣算法4.实验参数设定5.算法结果6.参考文献7.MA…

区块链实验室(30) - 区块链期刊:Distributed Ledger Technologies: Research and Practice

区块链涉及多学科及技术&#xff0c;众多期刊接收区块链文章。Distributed Ledger Technologies: Research and Practice是ACM出版集团的一本期刊。 Distributed Ledger Technologies: Research and Practice创刊历史很短&#xff0c;始于2022年&#xff0c;出版期数也不多。 载…

FastAPI之Hello World

世界上最著名的程序 from fastapi import FastAPIapp FastAPI()app.get("/") async def root():return {"message": "Hello World"}app.get("/hello/{name}") async def say_hello(name: str):return {"message": f"…

node笔记

文章目录 一、Node.js基础1. 认识Node.js01 nodejs的特性02 使用 Node.js 需要了解多少 JavaScript03 浏览器环境vs node环境 2. 开发环境搭建3. 模块、包、commonJS02 CommonJS规范03 modules模块化规范写法 4. Npm&Yarn01 npm的使用02 全局安装 nrm03 yarn使用 5. 内置模…

数据结构之归并排序及排序总结

目录 归并排序 归并排序的时间复杂度 排序的稳定性 排序总结 归并排序 归并排序大家只需要掌握其递归方法即可&#xff0c;非递归方法由于在某些特殊场景下边界难控制&#xff0c;我们一般很少使用非递归实现归并排序。那么归并排序的递归方法我们究竟是怎样实现呢&#xff…

报错:Parsed mapper file: ‘file mapper.xml 导致无法启动

报错 &#xff1a; Logging initialized using class org.apache.ibatis.logging.stdout.StdOutImpl adapter. Registered plugin: com.github.yulichang.interceptor.MPJInterceptor3b2c8bda Parsed mapper file: file [/Mapper.xml] application无法启动 我这边产生原因是项…

JVM Optimization Learning(六)

目录 一、JVM Optimization 1、Shenandoah Shenandoah的使用方法 2、ZGC ZGC的版本更迭 ZGC的使用方法 ZGC的参数设置 3、JMH测试GC性能 一、JVM Optimization 1、Shenandoah Shenandoah是由Red Hat开发的一款低延迟的垃圾收集器&#xff0c;Shenandoah并发执行大部分…

Qt Creator设置IDE的字体、颜色、主题样式

Qt是一款开源的、跨平台的C开发框架&#xff0c;支持Windows、Linux、Mac系统&#xff0c;从1995发布第一版以来&#xff0c;发展迅猛&#xff0c;最开始是用于Nokia手机的Symbian(塞班)系统和应用程序开发&#xff0c;现在是用于嵌入式软件、桌面软件(比如WPS、VirtualBox)、A…

Tomcat部署开源站点JPress

前言 JPress使用Java开发&#xff0c;是我们常见的开源博客系统。JPress是一个开源的WordPress插件&#xff0c;它提供了一个简单而强大的方式来创建企业级站点。该插件包括许多特性&#xff0c;例如主题定制、页面构建器、性能优化、SEO、安全、电子商务和社交媒体整合等。使用…

Python实战演练之python实现神经网络模型算法

python实现神经网络模型算法 今天&#xff0c;厾罗和大家分享用Python实现神经网络模型算法&#xff0c;仅用于技术学习交流。 实现技巧 1.导入依赖库 主要是安装相关的依赖库。本文实现的环境为&#xff1a;python 3.7。 from __future__ import division import math …

【数值计算方法(黄明游)】迭代法的一般形式与收敛性定理

一、向量、矩阵范数与谱半径 【数值计算方法&#xff08;黄明游&#xff09;】解线性代数方程组的迭代法&#xff08;一&#xff09;&#xff1a;向量、矩阵范数与谱半径【理论到程序】 1. 向量范数 l 1 l_1 l1​ 范数&#xff08;曼哈顿范数&#xff09;&#xff1a; ∣ ∣…

MybatisPlus集成baomidou-dynamic,多数据源配置使用、MybatisPlus分页分组等操作示例

文章目录 MybatisPlus特性MybatisPlus支持数据库MybatisPlus 架构多数据源应用场景pom配置示例代码 MybatisPlus特性 无侵入&#xff1a;只做增强不做改变&#xff0c;引入它不会对现有工程产生影响&#xff0c;如丝般顺滑 损耗小&#xff1a;启动即会自动注入基本 CURD&#…

MySQL深入——8

Order by语句是如何工作的&#xff1f; 首先我们来创建一个表 CREATE TABLE t (id int(11) NOT NULL,city varchar(16) NOT NULL,name varchar(16) NOT NULL,age int(11) NOT NULL,addr varchar(128) DEFAULT NULL,PRIMARY KEY (id),KEY city (city) ) ENGINEInnoDB; 全字段…

JVS低代码表单引擎:数据校验与处理的先锋

随着信息技术的迅速发展&#xff0c;数据校验与处理已经成为了各类应用中不可或缺的一环。尤其是在涉及敏感信息&#xff0c;如密码处理时&#xff0c;其安全性和准确性显得尤为重要。JVS低代码表单引擎提供了强大的文本组件触发逻辑校验功能&#xff0c;它能够在用户填写数据的…

Python数据科学视频讲解:数据清洗、特征工程和数据可视化的注意事项

1.6 数据清洗、特征工程和数据可视化的注意事项 视频为《Python数据科学应用从入门到精通》张甜 杨维忠 清华大学出版社一书的随书赠送视频讲解1.6节内容。本书已正式出版上市&#xff0c;当当、京东、淘宝等平台热销中&#xff0c;搜索书名即可。内容涵盖数据科学应用的全流程…

【calcitonin ; 降钙素 ;降钙素原】

Parathyroid_Hormone -甲状旁腺激素 PTH &#xff1b; 特立帕肽&#xff1b;

【小米电脑管家】安装使用教程--非小米电脑

安装说明功能体验下载资源 Xiaomi HyperOS发布后&#xff0c;小米妙享电脑端独立版本也走向终点&#xff0c;最新的【小米电脑管家】将会内置妙享实现万物互联。那么本篇文章将分享非小米电脑用户如何绕过设备识别验证安装使用【小米电脑管家】实现万物互联 安装说明 1.解压文…