动态规划

Leetcode中级算法-动态规划01

99封情书 提交于 2020-02-22 16:53:24
1. 感性认识“动态规划” 1. 基本概念    是求解决策过程(decision process)最优化的数学方法。 把多阶段过程转化为一系列单阶段问题,利用各阶段之间的关系,逐个求解,是一种解决这类过程优化问题的新方法。 2. 使用技巧:    动态规划算法通常用于求解具有某种最优性质的问题!!!特别的 ,动态规划(Dynamic Programming)对于子问题重叠的情况特别有效,因为它将子问题的解保存在表格中,当需要某个子问题的解时,直接取值即可,从而避免重复计算! 3. 基本思想与策略 我们通过一个问题来引出: 提问:动态规划与分治法有什么不同?    答:适合于用动态规划求解的问题,经分解得到 子问题往往不是互相独立的 。若用分治法来解这类问题,则分解得到的子问题数目太多,有些子问题被重复计算了很多次。如果我们能够保存已解决的子问题的答案,而在需要时再找出已求得的答案,这样就可以避免大量的重复计算,节省时间。我们可以用一个表来记录所有已解的子问题的答案。不管该子问题以后是否被用到,只要它被计算过,就将其结果填入表中。这就是动态规划法的基本思路。具体的动态规划算法多种多样,但它们具有相同的填表格式。 说明:具体的填表情况还是要看具体所涉及的情景,有时可能不需要保存全部的子状态,而只需要保存之前的1~2个状态即可。 比如:爬楼梯问题等 4. 适用的情况 1)两个必备要素

【OfferX】动态规划

我怕爱的太早我们不能终老 提交于 2020-02-22 13:55:41
1.变成回文串的最少插入次数 题目 : 1312. Minimum Insertion Steps to Make a String Palindrome 状态转移: f(i,j) = min{f(i+1,j), f(i,j-1)} class Solution { int n ; int [ ] [ ] dp ; String s ; public int minInsertions ( String s ) { this . s = s ; n = s . length ( ) ; dp = new int [ n ] [ n ] ; for ( int i = 0 ; i < n ; ++ i ) { for ( int j = 0 ; j < n ; ++ j ) { dp [ i ] [ j ] = - 1 ; } } return f ( 0 , n - 1 ) ; // 如果不同 f(xXy) -> y + f(xX) +y // x + f(Xy) + x // // f(i,j) -> f(i+1,j) + 1, f(i,j-1)+1 } public int f ( int i , int j ) { if ( i >= j ) { return 0 ; } if ( dp [ i ] [ j ] != - 1 ) { return dp [ i ] [ j ]

Leetcode分门别类 - 动态规划-Leetcode70-Climbing Stairs

眉间皱痕 提交于 2020-02-22 13:50:20
动态规划 Leetcode 70 爬楼梯问题 问题描述:每次爬楼梯可以爬一阶或者两阶,爬上N阶楼梯共有多少种爬法。 问题分析:爬到n阶的那一步可能分为两种情况,又第n-1阶或者n-2阶爬上来,于是F(n) = F(n-1) + F(n-2)又回到斐波拉契数列。 记忆搜索解法 class Solution { private: vector<int> memo; int calcWays( int n ){ if (n==0 || n==1) return 1; if (memo[n] == -1) memo[n] = calcWays(n-1) + calcWays(n-2); return memo[n]; }; public: int climbStairs(int n) { memo = vector<int>(n+1, -1); return calcWays(n); }; }; 动态规划解法 class Solution { private: vector<int> memo; int calcWays( int n ){ memo[0] = 1; memo[1] = 1; for(int i=2; i<=n; i++) memo[i] = memo[i-1] + memo[i-2]; return memo[n]; }; public: int climbStairs

动态规划

被刻印的时光 ゝ 提交于 2020-02-22 08:54:45
算法思想 动态规划(Dynamic programming,简称DP);核心思想是 把原问题分解成子问题进行求解 ,也就是分治的思想。 那么什么问题适合用动态规划呢?我们通过一个现实中的例子,来理解这个问题。大家可能在公司里面都有一定的组织架构,可能有高级经理、经理、总监、组长然后才是小开发,今天我们通过这个例子,来讲讲什么问题适合使用动态规划。又到了一年一度的考核季,公司要挑选出三个最优秀的员工。一般高级经理会跟手下的经理说,你去把你们那边最优秀的3个人报给我,经理又跟总监说你把你们那边最优秀的人报给我,经理又跟组长说,你把你们组最优秀的三个人报给我,这个其实就动态规划的思想! 首先是重叠子问题 ,不同的问题,可能都要求1个相同问题的解。假如A经理想知道他下面最优秀的人是谁,他必须知道X,Y,Z,O,P组最优秀的人是谁, 甲总监想知道自己下面最优秀的人是谁,也要去知道X,Y,Z组里面最优秀的人是谁?这就有问题重叠了,两个人都需要了解X,Y,Z三个小组最优秀的人。 其次是最优子结构 ,最优解肯定是有最优的子解转移推导而来,子解必定也是子问题的最优解。甲总监下面最优秀的3个人肯定是从X,Y,Z提交上来的3份名单中选择最优秀的三个人。例如Q哥是X组长下面的第5名,那么他肯定不可能是甲总监下面最优秀的三个。 第三是无后效性 ,这个问题可能比较难理解

[动态规划] leetcode 123 Best Time to Buy and Sell Stock III

☆樱花仙子☆ 提交于 2020-02-21 11:13:43
problem: https://leetcode.com/problems/best-time-to-buy-and-sell-stock-iii/ 题目的意思已知每天股票的价格,最多进行两次交易(买卖操作),能够赚取的最大利润。(每天最多只能进行一次操作:买或卖;且必须卖出手头持有股票后,才能进行下一次购买) 思路很简单,我们可以把区间划分为两部分,分别求两部分的最大利润值,然后叠加。比较所有划分,求得最大值。 当然,由于我们也可以只进行一次交易,所以还需要考虑不划分时的最大利润值。 基于以上思路,可以很快写出如下O(n^2) 复杂度的算法: class Solution { public: int maxProfit(vector<int>& prices) { int n = prices.size(); int profit = max(0, getMax(prices, 0, n)); for(int i = 2; i < n - 1;i++) { profit = max(profit, getMax(prices, 0, i) + getMax(prices, i, n)); } return profit; } int getMax(vector<int>& prices, int i, int j) { int maxnum = INT_MIN; int

(动态规划,状态机) leetcode 股票问题

泄露秘密 提交于 2020-02-21 11:08:58
https://leetcode.com/problems/best-time-to-buy-and-sell-stock/ 思路参考链接: https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-with-cooldown/solution/yi-ge-fang-fa-tuan-mie-6-dao-gu-piao-wen-ti-by-lab/ 个问题的「状态」有三个,第一个是天数,第二个是允许交易的最大次数,第三个是当前的持有状态(即之前说的 rest 的状态,我们不妨用 1 表示持有,0 表示没有持有)。然后我们用一个三维数组就可以装下这几种状态的全部组合: class Solution { public: int maxProfit(vector<int>& prices) { int dp_i_0 = 0, dp_i_1 = INT_MIN; //base case for(int i=0; i<prices.size(); ++i){ dp_i_0 = max(dp_i_0, dp_i_1+prices[i]); dp_i_1 = max(dp_i_1, -prices[i]); } return dp_i_0; } }; https://leetcode.com/problems/best

HDOJ题目分类

你。 提交于 2020-02-21 07:22:40
1001 整数求和 水题 1002 C语言实验题——两个数比较 水题 1003 1、2、3、4、5... 简单题 1004 渊子赛马 排序+贪心的方法归并 1005 Hero In Maze 广度搜索 1006 Redraiment猜想 数论:容斥定理 1007 童年生活二三事 递推题 1008 University 简单hash 1009 目标柏林 简单模拟题 1010 Rails 模拟题(堆栈) 1011 Box of Bricks 简单题 1012 IMMEDIATE DECODABILITY Huffman编码 1013 STAMPS 搜索or动态规划 1014 Border 模拟题 1015 Simple Arithmetics 高精度计算 1016 Shoot-out 博弈+状态压缩DP 1017 Tour Guide 1018 Card Trick 简单题 1019 Necklace Decomposition 贪心 1020 Crashing Robots 模拟题 1021 Electrical Outlets 简单题 1022 Watchdog 简单题 1023 Taxi Cab Scheme 图论:最小路径覆盖--->最大二分匹配 1024 Pseudo-random Numbers 数论 1025 Card Game Cheater 简单题 1026

蒟蒻の小窝(关于动态规划再总结)

我怕爱的太早我们不能终老 提交于 2020-02-17 06:16:01
我们以城市交通网和挖地雷来说明两个常见DP!!! 我谔谔,你们肯定觉得很简单的。。。 ` 样例输入: 10 0 2 5 1 0 0 0 0 0 0 0 0 0 0 12 14 0 0 0 0 0 0 0 0 6 10 4 0 0 0 0 0 0 0 13 12 11 0 0 0 0 0 0 0 0 0 0 3 9 0 0 0 0 0 0 0 0 6 5 0 0 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0 0 0 【样例输出】short.out minlong=19 1 3 5 8 10 【算法分析】逆推法 设f[i]表示点i到v10的最短路径长度,则 f[10]=0 f[i]=min{ a[i][x]+f[x] 当a[i][x]>0 ,i<x<=n时} # include <iostream>   # include <cstring>   # include <cstdio>  using namespace std ;   int main ( ) {   long n , i , j , x , f [ 100 ] , c [ 100 ] , a [ 100 ] [ 100 ] ;   memset ( a , 0 , sizeof ( a ) ) ;   memset

线性动态规划

二次信任 提交于 2020-02-16 23:30:54
一,概念篇 1,动态规划:通过计算出小问题的最优解,可以推出大问题的最优解,从而可以推出更大问题的最优解,最小问题即是边界情况。 2,子问题(小问题):子问题是一个与原问题有着类似的结构,但规模比原问题小的问题。 3,最优子结构:动态规划的问题一般是求解全局最优解,而全局最优解是由局部的最有解一步一步推出,局部的最优解称为最优子结构。 4,动态规划的基本思想:将待求解的问题划分为若干个阶段(子问题),按顺序求解子问题,子问题的求解为更大子问题的求解提供信息,由于动态规划解决的问题多数有重叠子问题这个特点,为减少重复计算,对每一个子问题只解一次。 动态规划的核心思想也有减少冗余,对于会发生重叠的子问题只计算一次,去除冗余。 5,状态表示和最优化值。 状态表示是对当前子问题的解的局面的(条件)一种全面的描述。 最优化值是该状态表示下的最优化值(方案值),我们最终能通过其直接或间接得到答案。 6,状态的设计 具有最优化总结构,能够全面描述某一个局面,尽量简洁。 设计状态的关键是充分描述,尽量简洁。 7,动态规划的精髓——状态转移:通过已知的较小问题的最优值得出较大问题的最有值的过程。状态的转移需要满足要考虑到所有的可能性。状态转移的实质是一个DAG,可以把状态抽象成点,转移抽象成边,转移就是从子问题指向当前状态。 8,无后效性:因为动态规划的转移过程是一个DAG

动态规划和递归算法求解斐波那契数列的效率对比

五迷三道 提交于 2020-02-16 12:05:52
动态规划有效的解决了递归算法的效率低下的问题,它剔除了递归中的重叠的子问题,对每个子问题只求解一次。 斐波那契数列格式为:1、1、2、3、5、8、13、21、34、......, 递归(状态转移)函数为 f[n]=f[n-1]+f[n-2] 采用递归求解: #采用递归求解 def f_recu(n): assert isinstance(n,int),'必须输入一个整数' assert n>=1,'不能小于1' if n==1 or n==2: return 1 return f_recu(n-1) + f_recu(n-2) #测试,n=40 计算时间 %time f_recu(40) 输出: Wall time: 48.4 s 102334155 采用动态规划求解: #采用动态规划方法求解 def f_dyna(n): assert isinstance(n,int),'必须输入一个整数' assert n>=1,'不能小于1' if n == 1 or n==2: return 1 else: pre_n_2 = 1 pre_n_1 = 1 for i in range(3,n+1): target_n = pre_n_2 + pre_n_1 pre_n_1 = pre_n_2 pre_n_2 = target_n return target_n #测试,n=40 计算时间