动态规划

归纳程序员必须掌握的核心算法(详细)

大城市里の小女人 提交于 2020-02-02 07:22:59
由于我之前一直强调数据结构以及算法学习的重要性,所以就有一些读者经常问我, 数据结构与算法应该要学习到哪个程度呢? ,说实话,这个问题我不知道要怎么回答你,主要取决于你想学习到哪些程度,不过针对这个问题,我稍微总结一下我学过的算法知识点,以及我觉得值得学习的算法。这些算法与数据结构的学习大多数是 零散 的,并没有一本把他们全部覆盖的书籍。下面是我觉得值得学习的一些算法以及数据结构,当然,我也会整理一些看过不错的文章给大家。大家也可以留言区补充。 一、算法最最基础 1、时间复杂度 2、空间复杂度 一般最先接触的就是时间复杂度和空间复杂度的学习了,这两个概念以及如何计算,是必须学的,也是必须最先学的,主要有最大复杂度、平均复杂度等,直接通过博客搜索学习即可。 文章推荐: 算法分析神器—时间复杂度 二、基础数据结构 1、线性表 列表(必学) 链表(必学) 跳跃表(知道原理,应用,最后自己实现一遍) 并查集(建议结合刷题学习) 不用说,链表、列表必须,不过重点是链表。 三分钟基础数据结构:如何轻松手写链表? 以后有面试官问你「跳跃表」,你就把这篇文章扔给他 2、栈与队列 栈(必学) 队列(必学) 优先队列、堆(必学) 多级反馈队列(原理与应用) 特别是优先队列,再刷题的时候,还是经常用到的,队列与栈,是最基本的数据结构,必学。可以通过博客来学习。相关文章: 三分钟基础知识:什么是栈?

动态规划之四边形不等式优化

╄→尐↘猪︶ㄣ 提交于 2020-02-02 00:40:55
给出伪代码:(可以看出时间复杂度为O(n^3)) 1 for(int len=1;len<=n;len++){///len为区间长度 2 for(int l=1;l<=n-len+1;l++){ 3 int r=l+len-1; 4 for(int k=l;k<r;k++){ 5 m[l][r]=min(m[l][r],m[l][k]+m[k+1][r]+w[l][r]); 6 } 7 } 8 } 以下介绍两个名词:区间包含的单调性:如果对于i≤i'< j≤j',有w(i',j)≤w(i,j'),那么说明w具有区间包含的单调性。         四边形不等式:如果对于i≤i'< j≤j',有w(i,j)+w(i',j')≤w(i',j)+w(i,j'),我们称函数w满足四边形不等式。 附图理解四边形不等式: 蓝线长和<=红线长和 以下介绍两个定理:定理一:如果上述的w函数同时满足区间包含单调性和四边形不等式性质,那么函数m也满足四边形不等式性质。 定理二: 结论: 时间复杂度变为O(n^2) 来源: https://www.cnblogs.com/wsy107316/p/12250753.html

198/213 打家劫舍(动态规划)

删除回忆录丶 提交于 2020-02-01 21:20:39
你是一个专业的小偷,计划偷窃沿街的房屋,每间房内都藏有一定的现金。这个地方所有的房屋都围成一圈,这意味着第一个房屋和最后一个房屋是紧挨着的。同时,相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。 给定一个代表每个房屋存放金额的非负整数数组,计算你在不触动警报装置的情况下,能够偷窃到的最高金额。 题目求数组非连续元素的最大和,状态转移方程为:   dp[n] = max(dp[n-1],dp[n-2] + num) 第二题要求 取了第0号num就不能要最后一项num,我就正反算了两边,通过了,时间效率比较低,我现在去看看答案。 注意:    我的版本:用了一个二维数组来记录路径,然后再顺序倒序运行两遍。。。    答案版本:直接运行 max(my_rob(nums[: -1]),my_rob(nums[ 1:])) if len(nums) != 1 else nums[ 0] 收获:    状态转移方程一定要想清楚再动笔啊 - - 来源: https://www.cnblogs.com/ChevisZhang/p/12250035.html

动态规划 ---- 最长公共子序列(Longest Common Subsequence, LCS)

末鹿安然 提交于 2020-02-01 14:22:18
分析: 完整代码: // 最长公共子序列 #include <stdio.h> #include <algorithm> using namespace std; const int N = 100; char A[N], B[N]; int dp[N][N]; int main() { freopen("in.txt", "r", stdin); int n; gets(A + 1); // 从下标1开始读入 gets(B + 1); int lenA = strlen(A + 1); // 由于读入时下标从1开始,因此读取长度也从1开始 int lenB = strlen(B + 1); // 边界 for (int i = 0; i <= lenA; i++){ dp[i][0] = 0; } for (int j = 0; j <= lenB; j++){ dp[0][j] = 0; } // 状态转移方程 for (int i = 1; i <= lenA; i++){ for (int j = 1; j <= lenB; j++){ if (A[i] == B[j]){ dp[i][j] = dp[i - 1][j - 1] + 1; } else{ dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]); } } } // dp[lenA

[专题七] 动态规划

痴心易碎 提交于 2020-02-01 12:48:34
01背包 完全背包 多重背包 分组背包 混合背包 对于物品而言只能选择1个或者0个两种情况 对于物品而言可以无限制选取,也可以不选 对于物品而言最多能够选择从s[i]个,同样也可不选 一些物品捆绑在一起,每一组物品中只能选择其中的一个物品 有些物品可以选择1,有些物品可以选择无数个,有些物品只能选择是s[i]个.即:01背包+完全背包+多重背包. 滚动数组 滚动数组 滚动数组 滚动数组 滚动数组 二进制优化或者单调队列优化 其中多重背包部分参考多重背包优化 0 - 1 背包问题 有 N N 件物品和一个容量是 V V 的背包。每件物品只能使用一次。 第 i i 件物品的体积是 v i vi,价值是 w i wi。 求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。 输出最大价值。 /* 特点:每个物品仅能使用一次 f[i][j]:前i个物品,背包容量为j的情况下的最优解 1)当前背包容量不够,为前i-1个物品最优解:j<w[i] f[i][j] = f[i-1][j] 2)当前背包容量够,判断选与不选第i个物品 选:f[i][j] = f[i-1][j-w[i]] + v[i] 不选:f[i][j] = f[i-1][j] */ // 二维表示法 int n, m; int v[N], w[N]; //v为体积 w为价值 int f[N][N]; int

动态规划-2-1

穿精又带淫゛_ 提交于 2020-02-01 10:26:10
最大子序和 public int crossSum ( int [ ] nums , int left , int righ , int p ) { if ( left == right ) return nums [ left ] ; int leftSubsum = Integer . MIN_VALUE ; int currSum = 0 ; for ( int i = p ; i > left - 1 ; -- i ) { currSum += nums [ i ] ; leftSubsum = Math . max ( leftSubsum , currSum ) ; } int rightSubsum = Integer . MIN_VALUE ; currSum = 0 ; for ( int i = p + 1 ; i < right + 1 ; ++ i ) { currSum += nums [ i ] ; rightSubsum = Math . max ( rightSubsum , currSum ) ; } return leftSubsum + rightSubsum ; } public int helper ( int [ ] nums , int left , int right ) { if ( left == right ) return

涉及期望的动态规划

北战南征 提交于 2020-01-31 18:51:57
期望 \(dp\) 概述 做一件事情成功: \(p\) ,失败: \(\overline{p} = 1-p\) 。 和性: \(E[x+y] = E[x] + E[y]\) 期望的意义就是对于做一件事情,期望多少次这件事情可以做成功。 P1291 [SHOI2002]百事世界杯之旅 题目描述 “……在2002年6月之前购买的百事任何饮料的瓶盖上都会有一个百事球星的名字。只要凑齐所有百事球星的名字,就可参加百事世界杯之旅的抽奖活动,获得球星背包,随声听,更克赴日韩观看世界杯。还不赶快行动!” 你关上电视,心想:假设有n个不同的球星名字,每个名字出现的概率相同,平均需要买几瓶饮料才能凑齐所有的名字呢? 题解 首先定义转移状态 \(f[i]\) 为收集到 \(i\) 个不同的球星的期望要买多少个。则 \(f[i]\) 这个状态可以从两个状态转移过来,一种是对于 \(f[i - 1]\) 这种状态买了不同的一个球星,另外一种就是 \(f[i]\) ,但是买的和原来的一样。 所以我们可以粗略的得到以下的转移方程: \[ f[i] = f[i - 1] \frac {n - (i - 1)}{n} + f[i] \frac {i}{n} \] 但是我们会非常遗憾地发现,上面这个式子当中的概率总和 \(P_S = \frac {n - (i -1)} {n} + \frac {i}{n} =

逐行递推的动态规划

自古美人都是妖i 提交于 2020-01-31 18:47:24
逐行递推 逐行递推: \(dp\) 在某种情况下按照一行一行的顺序进行递推。 P2704 [NOI2001]炮兵阵地 题目描述 司令部的将军们打算在N*M的网格地图上部署他们的炮兵部队。一个N*M的地图由N行M列组成,地图的每一格可能是山地(用“H” 表示),也可能是平原(用“P”表示),如下图。在每一格平原地形上最多可以布置一支炮兵部队(山地上不能够部署炮兵部队);一支炮兵部队在地图上的攻击范围如图中黑色区域所示: 如果在地图中的灰色所标识的平原上部署一支炮兵部队,则图中的黑色的网格表示它能够攻击到的区域:沿横向左右各两格,沿纵向上下各两格。图上其它白色网格均攻击不到。从图上可见炮兵的攻击范围不受地形的影响。 现在,将军们规划如何部署炮兵部队,在防止误伤的前提下(保证任何两支炮兵部队之间不能互相攻击,即任何一支炮兵部队都不在其他支炮兵部队的攻击范围内),在整个地图区域内最多能够摆放多少我军的炮兵部队。 输入输出格式 输入格式: 第一行包含两个由空格分割开的正整数,分别表示N和M; 接下来的N行,每一行含有连续的M个字符(‘P’或者‘H’),中间没有空格。按顺序表示地图中每一行的数据。N≤100;M≤10。 输出格式: 仅一行,包含一个整数K,表示最多能摆放的炮兵部队的数量。 输入样例#1: 复制 5 4 PHPP PPHH PPPP PHPP PHHP 输出样例#1: 复制 6

LeetCode-Greedy-44-M:跳跃游戏

杀马特。学长 韩版系。学妹 提交于 2020-01-31 10:24:42
文章目录 思路 解法1-清奇 解法2-巧妙 给定一个非负整数数组,你最初位于数组的第一个位置。 数组中的每个元素代表你在该位置可以跳跃的最大长度。 判断你是否能够到达最后一个位置。 输入: [2,3,1,1,4] 输出: true 解释: 我们可以先跳 1 步,从位置 0 到达 位置 1, 然后再从位置 1 跳 3 步到达最后一个位置。 思路 官方题解 这是一个动态规划问题,通常解决并理解一个动态规划问题需要以下 4 个步骤: (1)利用递归回溯解决问题 (2)利用记忆表优化(自顶向下的动态规划) (3)移除递归的部分(自底向上的动态规划) (4)使用技巧减少时间和空间复杂度 解法1-清奇 一个个遍历,如果当前位置能到终点就ok,巧妙在于一直更新截止到当前点位置时所能到达的最远点。 执行用时 :2 ms, 在所有 Java 提交中击败了61.87%的用户 内存消耗 :40.6 MB, 在所有 Java 提交中击败了31.63%的用户 https://leetcode-cn.com/problems/jump-game/solution/55-by-ikaruga/ class Solution { public boolean canJump ( int [ ] nums ) { int k = 0 ; for ( int i = 0 ; i < nums . length ; i

动态规划:最大子串和

人走茶凉 提交于 2020-01-30 22:59:42
题目链接(点击直达) 问题 B: X额宝 时间限制: 1 Sec 内存限制: 256 MB 提交: 46 解决: 33 [ 状态 ] [ 提交 ] [命题人: 外部导入] 题目描述 【理财有风险,投资需谨慎】 Alice计划将自己的所有红包拿去投资。 在粗略预测了该理财产品的各日收益后,Alice希望通过一次买卖获得最大的收益。 买卖当天均可以享受到当日盈亏,允许一天内先买后卖。 希望你帮她计算一下最大盈利。 输入 第一行是样例个数K(1<=K<=100) 每个样例的第一行是天数N(1<=N<=100) 第二行包含N个整数Ai(-100<=Ai<=100),表示当天盈亏。 输出 对于每个样例,输出一个数字表示Alice的最大盈利。 如果该理财产品赚不到钱,她也可以选择不购入此产品,请直接输出0。 样例输入 4 3 1 0 0 9 -2 1 -3 4 -1 2 1 -5 4 6 -4 -1 5 -4 1 -1 3 -9 -9 -6 样例输入 1 6 5 0 原理:先定义一个dp的数组变量,以n为长度,从dp[1]开始进行一次for循环(ps:如果从0开始会导致数组越界),利用max函数判断是当前的a[i]大还是上一个dp加上当前的a[i]之和大,即max(a[i],dp[i-1]+a[i]);找出两者中较大的一个,作为当前dp[i]中的内容。之后再做一次i从0到9的for循环