动态规划算法

[算法] 刷题-动态规划

拟墨画扇 提交于 2020-04-08 12:16:07
索引 最大正方形 最短三角形路径 最大子序和 题解 最大正方形 class Solution: def maximalSquare(self, matrix: List[List[str]]) -> int: nums = matrix if len(nums) ==0 or len(nums[0]) ==0: return 0 height = len(nums) width = len(nums[0]) masks = [[0]*(width+1) for i in range(height+1)] max_len = 0 for j in range(0,height): for i in range(0,width): val = int(nums[j][i]) if val == 1: masks[j+1][i+1] = min( masks[j][i], masks[j+1][i], masks[j][i+1] ) +1 max_len = max(max_len,masks[j+1][i+1]) return max_len*max_len 最短三角形路径 class Solution: def minimumTotal(self, triangle: List[List[int]]) -> int: nums = triangle if len(nums) ==0

【数据结构与算法】动态规划——最小路径和(普通矩阵、三角形两题)

◇◆丶佛笑我妖孽 提交于 2020-04-06 13:00:27
最小路径和 LeetCode: 最小路径和 题目描述: 给定一个包含非负整数的 m x n 网格,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。 说明:每次只能向下或者向右移动一步。 示例: 输入: [ [1,3,1], [1,5,1], [4,2,1] ] 输出: 7 解释: 因为路径 1→3→1→1→1 的总和最小。 思想: 动态规划,可以用原数组作为dp数组 代码: class Solution { public int minPathSum(int[][] grid) { int i=0,j=0; for(i=0;i<grid.length;++i){ for(j=0;j<grid[0].length;++j){ if(i>0&&j>0){ grid[i][j]+= Math.min(grid[i-1][j],grid[i][j-1]); }else{ grid[i][j]+= (i==0?0:grid[i-1][j]) + (j==0?0:grid[i][j-1]); } } } return grid[i-1][j-1]; } } 三角形最小路径和 LeetCode: 三角形最小路径和 题目描述: 给定一个三角形,找出自顶向下的最小路径和。每一步只能移动到下一行中相邻的结点上。 如果你可以只使用 O(n) 的额外空间(n 为三角形的总行数)来解决这个问题

动态规划---子序列的个数

天涯浪子 提交于 2020-04-06 00:16:04
子序列的个数 题目详情: 子序列的定义:对于一个序列a=a[1],a[2],......a[n],则非空序列a'=a[p1],a[p2]......a[pm]为a的一个子序列,其中1<=p1<p2<.....<pm<=n。 例如:4,14,2,3和14,1,2,3都为4,13,14,1,2,3的子序列。 对于给出序列a,有些子序列可能是相同的,这里只算做1个,要求输出a的不同子序列的数量。 输入: 长度为n的数组1<=n<=100,数组元素0<=a[i]<=110 输出:子序列 的个数对1000000007取余数的结果(由于答案比较大,输出Mod 1000000007的结果即可)。 函数头部: C/C++: int run(cons int *a,int n); java public static int run(int [] a);   这道题目也是困扰了我很久,一直找不到比较好的方法,这道题目应该是可以用动态规划做出来的,因此我也特地去学习动态规划的思想,并找了一些练习题做,可是这个状态转移方程着实难住我了,本来数学基础一般般,这就更加大了难度。虽然我最终解决了这道题目,可是那是建立在大神指点的情况下做出来的,我在这里只是把题解写出来,顺便裨补阙漏,看看自己的理解是否正确,其实,想和做是两回事,这里也请大家给与指正。 题解:   假设子序列的 前k 个数的子序列个数为 d(k

动态规划——Palindrome Partitioning II

百般思念 提交于 2020-03-31 18:29:07
Palindrome Partitioning II 这个题意思挺好理解,提供一个字符串s,将s分割成多个子串,这些字串都是回文,要求输出分割的最小次数。 Example: Input: "aab" Output: 1 Explanation: The palindrome partitioning ["aa","b"] could be produced using 1 cut. 状态:这个题的状态也非常好理解,dp[i]表示将s[0..i]分割成回文子串的最小分割次数。然后不急于寻找状态转移方程,我们先要明确如何用代码判断一个字符串的某个部分是不是回文,其实也很好理解啊,咱们可以分块来理解,毕竟这是个算法题,不可能用常规的那种遍历一半的方式来判断。首先对于这个字符串的某个子串s[j..i](j<=i),满足它是回文的条件两条(1)s[j]==s[i] (2) 只确定两端的两个字符还不够,当这个子串的长度小于4或者去掉两端的相同字符后还是回文即可。现在我们除了递推数组dp,再定义一个记录数组pa[j][i],如果s[j..i]是回文,则pa[j][i] = 1,否则为0。有了这两个条件,我们就可以总结状态转移方程了: dp[i] = min(dp[j-1]+1),当0<j<=i时,并且s[j..i]是回文时 dp[i] = 0 ,当j=0,并且s[j..i]是回文时

【数据结构与算法】动态规划——买卖股票的最佳时机

前提是你 提交于 2020-03-20 01:08:19
买卖股票的最佳时机 LeetCode: 买卖股票的最佳时机 题目描述: 给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。 如果你最多只允许完成一笔交易(即买入和卖出一支股票一次),设计一个算法来计算你所能获取的最大利润。 注意:你不能在买入股票前卖出股票。 示例: 输入: [7,1,5,3,6,4] 输出: 5 解释: 在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。 注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格。 思想: dp思想 记录【今天之前买入的最小值】 计算【今天之前最小值买入,今天卖出的获利】,也即【今天卖出的最大获利】 比较【每天的最大获利】,取最大值即可 代码: class Solution { public int maxProfit(int[] prices) { int L = prices.length; if(L == 0){ return 0; } //min表示当前位置之前的最小值 int min = prices[0],maxProfit = 0; for(int i=1;i<L;++i){ //prices[i]-min表示当前位置抛售可获得的最大利润 maxProfit = Math.max(maxProfit,prices[i]-min);

动态规划、回溯、贪心,分治

帅比萌擦擦* 提交于 2020-03-17 01:24:09
某厂面试归来,发现自己落伍了!>>> 动态规划篇 从斐波那契数列开始 我们先给出斐波那契数列的常用算法类 public class Fibonacci { private static int num = 0 ; private Fibonacci () { } public static int fib ( int n) { num ++ ; if (n == 0 ) { return 0 ; } if (n == 1 ) { return 1 ; } return fib (n - 1 ) + fib (n - 2 ) ; } public static void main (String[] args) { num = 0 ; int n = 20 ; long start = System. nanoTime () ; int res = Fibonacci. fib (n) ; long end = System. nanoTime () ; System. out .println(res) ; System. out .println((end - start) / 1000000000.0 ) ; System. out .println( num ) ; } } 运行结果 6765 3.96599E-4 21891 此时我们调大n的值为40 运行结果

动态规划经典问题

时光毁灭记忆、已成空白 提交于 2020-03-16 08:25:33
## 一、最大子序列和 给定一个数组,求出其最大的子序列之和 定义d[i]代表以下标为i元素的最大子序列和 则d[i] = d[i-1] > 0 ? d[i-1] + a[i] : a[i] 算法: ```c int maxSubArray(int* nums, int numsSize){ if(numsSize == 0) return 0; int m = nums[0]; int d = m; int di; for(int i = 1;i < numsSize;i++) { di = nums[i]; di = d > 0 ? d + di : di; if(di > m) m = di; d = di; } return m; } ``` 来源: https://www.cnblogs.com/lzq666/p/12501665.html

深入理解floyd算法

风格不统一 提交于 2020-03-06 16:40:58
先上floyd算法的代码,本质上是动态规划问题 本质就是DP含有动态规划的思想,满足重叠子问题和最优子结构 dis[k][i][j]=min(dis[k-1][i][j],dis[k-1][i][k]+dis[k-1][k][j]); 我们可以发现他其实是由前k-1的状态来推出第k个点的状态之后你就会发现f[k]只与f[k-1]有关 然后我们可以根据这个性质解决很多问题 for ( k = 1 ; k <= n ; k ++ ) { for ( i = 1 ; i <= n ; i ++ ) { for ( j = 1 ; j <= n ; j ++ ) { if ( dis [ i ] [ k ] + dis [ k ] [ j ] < dis [ i ] [ j ] ) { dis [ i ] [ j ] = dis [ i ] [ k ] + dis [ k ] [ j ] ; } } } } 这个经典代码的难点在于理解为什么k的循环在外面,这里附上一波知乎的高赞解释 可能部分大佬看到这段抽象的解释之后已经豁然开朗,如果还有部分大佬没有看懂的话,本菜鸡尝试用通俗的语言来翻译一下 这里给出一张简单的有向图 1->5,5->6,6->3的距离均为1,如果按照k值在最内部进行循环的话 dist[1][3]的距离无法更新, 因为dist[1][3] = dist[1][6] +

动态规划-矩阵连乘

匆匆过客 提交于 2020-03-03 22:09:06
给定n个矩阵{A 1 ,A 2 ,…,A n },其中A i 与A i+1 是可乘的,i=1,2,…,n-1。考察这n个矩阵的连乘积A 1 A 2 …A n 。由于矩阵乘法满足结合律,故计算矩阵的连乘积可以有许多不同的计算次序,这种计算次序可以用加括号的方式来确定。若一个矩阵连乘积的计算次序完全确定,则可以依此次序反复调用2个矩阵相乘的标准算法(有改进的方法,这里不考虑)计算出矩阵连乘积。若A是一个p×q矩阵,B是一个q×r矩阵,则计算其乘积C=AB的标准算法中,需要进行pqr次数乘。 矩阵连乘积的计算次序不同,计算量也不同,举例如下: 先考察3个矩阵{A 1 ,A 2 ,A 3 }连乘,设这三个矩阵的维数分别为10×100,100×5,5×50。若按((A 1 A 2 )A 3 )方式需要的数乘次数为10×100×5+10×5×50=7500,若按(A 1 (A 2 A 3 ))方式需要的数乘次数为100×5×50+10×100×50=75000。 下面使用动态规划法找出矩阵连乘积的最优计算次序。 I: 设矩阵连乘积A i A i+1 …A j 简记为A[i:j],设最优计算次序在A k 和A k+1 之间断开,则加括号方式为:((A i A i+1 …A k )(A k+1 …A j ))。则依照这个次序,先计算A[i:k]和A[K+1:j]然后再将计算结果相乘,计算量是:A

NOIP需要掌握的内容(大致

旧街凉风 提交于 2020-03-02 11:41:13
1、 排序算法(快排、选择、冒泡、堆排序、 二叉排序树 、桶排序) 2、 DFS/BFS 剪枝 哈希表 3、树 ① 遍历 ② 二叉树 ③二叉排序树(查找、生成、删除) ④堆(二叉堆、左偏树、堆排序) ⑤Trie树 4、图(图论建模) ① 最小生成树 ② 最短路径 ③计算图的传递闭包 ④ 连通分量(其中要掌握并查集技术) 强连通分量tarjin ⑤ 拓扑排序 、关键路径 ⑥哈密尔顿环 ⑦ 欧拉回路 (USACO 3.3 题1 Fence) ⑧ Bell-man Ford、SPFA(能解决负权回路) (USACO 3.2 题6 Butter) ⑨二分图(匈牙利算法)(USACO 4.2 题2 stall) 5、动态规划(背包问题只是其中一种) ① 线性动规 ② 区间动规 ③ 树形动规 ④图形动规 6、 分治 (掌握了动规分治就好学了) 7、 贪心 8、 位运算 (可以用来进行优化) 来源: https://www.cnblogs.com/GldHkkowo/p/8710834.html