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

这篇具有很好参考价值的文章主要介绍了动态规划(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

 举例说明:

动态规划(dp)初步学习案例讲解,leetcode笔记,动态规划,学习,算法,leetcode

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

方案一,暴力穷举:

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

动态规划(dp)初步学习案例讲解,leetcode笔记,动态规划,学习,算法,leetcode

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

动态规划(dp)初步学习案例讲解,leetcode笔记,动态规划,学习,算法,leetcode

时间复杂度:假定数组长度为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),即可用空间来换取时间,创建一个哈希表进行记录存储最大子序列长度,即可减少访问步骤。

动态规划(dp)初步学习案例讲解,leetcode笔记,动态规划,学习,算法,leetcode

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

动态规划(dp)初步学习案例讲解,leetcode笔记,动态规划,学习,算法,leetcode

 时间复杂度大大减少

#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;
}

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

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

动态规划(dp)初步学习案例讲解,leetcode笔记,动态规划,学习,算法,leetcode

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

动态规划(dp)初步学习案例讲解,leetcode笔记,动态规划,学习,算法,leetcode

时间复杂度: 由于只进行了两个循环,即为O(n^2)。文章来源地址https://www.toymoban.com/news/detail-755592.html

#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. 将计算的过程用迭代的方式表示出来

到了这里,关于动态规划(dp)初步学习案例讲解的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 动态规划——斜率优化DP 学习笔记

    适用于求解最优解(最大、最小)问题。 可以将转移方程可以化为 (left[begin{array}{rl} 仅与 space i space 有关 是我们想要最大/最小化的 \\\\ 仅与 space j space 有关 是已知的 \\\\ 与 space i space 和 space j space 都有关 是两项相乘 end{array}right]) 三部分的, 都可以考虑用斜率优化

    2024年02月08日
    浏览(42)
  • 动态规划——矩阵优化DP 学习笔记

    前置知识:矩阵、矩阵乘法。 斐波那契数列 在斐波那契数列当中, (f_1 = f_2 = 1) , (f_i = f_{i - 1} + f_{i - 2}) ,求 (f_n) 。 而分析式子可以知道,求 (f_k) 仅与 (f_{k - 1}) 和 (f_{k - 2}) 有关; 所以我们设矩阵 (F_i = begin{bmatrix} f_{i - 1} f_{i - 2} end{bmatrix}) 。 设矩阵 (text{Ba

    2024年02月08日
    浏览(48)
  • 动态规划——决策单调性优化DP 学习笔记

    对于最优性问题,常有状态转移方程: (f_i = min/max{f_jdots}) , 形象的:如果 (i) 的最优转移点是 (j) , (i\\\') 的最优转移点是 (j\\\') ,当 (ii\\\') 时,有 (jle j\\\') ,则称该 DP 问题具有决策单调性。 即: (i) 单增,其最优转移点单调不减。 如何发现一个转移方程具有决策

    2024年02月08日
    浏览(43)
  • 动态规划——带权二分优化DP 学习笔记

    带权二分其实并不一定用于优化 DP,也可能用于优化贪心等最优化的算法。 带权二分也叫 WQS 二分,最初由王钦石在他的 2012 年国家集训队论文中提出。 使用情况 要解决一个最优化问题(求最大 / 最小值) 有一个限制,一般是某个参数要求一定恰好为 (k) 而带权二分就可以

    2024年02月08日
    浏览(30)
  • AcWing算法学习笔记:动态规划(背包 + 线性dp + 区间dp + 计数dp + 状态压缩dp + 树形dp + 记忆化搜索)

    算法 复杂度 时间复杂度0(nm) 空间复杂度0(nv) 代码 算法 通过滚动数组对01背包朴素版进行空间上的优化 f[i] 与 f[i - 1]轮流交替 若体积从小到大进行遍历,当更新f[i, j]时,f[i - 1, j - vi] 已经在更新f[i, j - vi]时被更新了 因此体积需要从大到小进行遍历,当更新f[i, j]时,f[i - 1,

    2024年02月21日
    浏览(35)
  • 动态规划(DP)C++讲解,看着这一本就够了

    用于求解某种最优性质的问题。 将带求解问题分解为若干个子问题,解决子问题,然后从这些子问题的解得到原问题的解 两个要素:状态和转移。 阶段 :求解的问题的每个过程。 状态 :状态表示每个阶段所处的情况。 策略 :策略是按顺序排列的策略组成的集合。 状态转

    2024年02月08日
    浏览(27)
  • 【动态规划】LeetCode 312. 戳气球 --区间DP问题

      Halo,这里是Ppeua。平时主要更新C语言,C++,数据结构算法......感兴趣就关注我吧!你定不会失望。 🌈个人主页:主页链接 🌈算法专栏:专栏链接       我会一直往里填充内容哒! 🌈LeetCode专栏:专栏链接       目前在刷初级算法的LeetBook 。若每日一题当中有力所能

    2023年04月16日
    浏览(30)
  • Leetcode动态规划篇(0-1背包问题一维和二维dp实现)

    🤗专栏:每日算法学习 💬个人主页:个人主页 🤓情况描述:有n件物品和一个最多能背重量为w 的背包。第i件物品的重量是weight[i],得到的价值是value[i] 。每件物品只能用一次,求解将哪些物品装入背包里物品价值总和最大。每一件物品其实只有两个状态,取或者不取。

    2023年04月09日
    浏览(32)
  • 动态规划(DP)(算法笔记)

    本文内容基于《算法笔记》和官方配套练题网站“晴问算法”,是我作为小白的学习记录,如有错误还请体谅,可以留下您的宝贵意见,不胜感激。 动态规划(Dynamic Programming,DP)是一种用来解决一类最优化问题的算法思想。简单来说,动态规划将一个复杂的问题分解成若干个子

    2024年02月05日
    浏览(38)
  • 【LeetCode动态规划#12】详解买卖股票I~IV,经典dp题型

    力扣题目链接(opens new window) 给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。 你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。 返回你可以从这笔交易中获取的最

    2023年04月24日
    浏览(45)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包