单序列型DP

相比一维DP,这种类型状态转移与过去每个阶段的状态都有关。

Perfect Squares :

方法一 : 自底向上 递推 + memo

f(n) = min{f(i) + f(n-i), i = 1...n-1}

class Solution {
public int numSquares(int n) {
int[] memo = new int[n]; for(int i = 1; i <= n; i++){
if(i * i <= n){
memo[i*i - 1] = 1;
}
} if(memo[n-1] == 1) return 1; memo[1] = 2;
for(int i = 3; i <= n; i++){
if(memo[i-1] == 1) continue; int left = 1;
int right = i - 1; int mini = Integer.MAX_VALUE;
while(left <= right){
if(left + right == i){
mini = Math.min(mini, memo[left - 1] + memo[right - 1]);
}
left ++; right--;
}
memo[i-1] = mini;
} return memo[n - 1];
}
}

方法二: 递推 + memo

另外,本题有个四平方数之和定理,具体参考

class Solution {
public int numSquares(int n) {
int[] memo = new int[n + 1];
memo[0] = 0; for(int i = 1; i <= n; i++){
int mini = Integer.MAX_VALUE; for(int j = 1; j <= i; j ++){
int t = j*j; if(t > i) break;
if(t == i) mini = 1;
else mini = Math.min(mini, memo[t] + memo[i-t]);
} memo[i] = mini;
}
return memo[n];
}
}

Longest Increasing Subsequence

方法一 : 自底向上,递推 + memo

这道题的状态转移想了比较久,没有想出来,给出grandyang的参考.

参考中,还介绍了nlog(n)的解法,用了二搜法。

class Solution {
public int lengthOfLIS(int[] nums) {
if(nums.length == 0) return 0; int[] memo = new int[nums.length];
memo[0] = 1; int maxi = 1;
for(int i = 1; i < nums.length; i++){ memo[i] = 1; for(int j = i - 1; j >= 0; j--){
if(nums[i] > nums[j])
memo[i] = Math.max(memo[i], memo[j] + 1);
}
maxi = Math.max(memo[i], maxi);
} return maxi;
}
}

Increasing Triplet Subsequence : 求是否存在

方法一 : 自底向上 递推 + memo

class Solution {
public boolean increasingTriplet(int[] nums) {
if(nums.length == 0) return false; int[] memo = new int[nums.length];
memo[0] = 1; boolean exist = false;
for(int i = 1; i < nums.length; i ++){
memo[i] = 1;
for(int j = 0; j < i; j ++){
if(nums[i] > nums[j]){
memo[i] = Math.max(memo[j] + 1, memo[i]);
}
} if(memo[i] == 3){
exist = true;break;
}
} return exist;
}
}

Coin Change

方法一: 自底向上

递推 + memo

如果直接用用模除,将得到错误结果

dp方法没有可优化了,用 递归 + 减枝还可以优化,参考

减枝是一种优化方法,一般用于dfs/bfs中,通过条件过滤掉对搜索空间树的搜索,参考

class Solution {
public int coinChange(int[] coins, int amount) { Arrays.sort(coins);
int[] memo = new int[amount + 1]; for(int i = 1; i <= amount; i++){ memo[i] = Integer.MAX_VALUE; for(int j = coins.length - 1; j >= 0; j--){
if(i < coins[j]) continue; if(i == coins[j]){
memo[i] = 1;
continue;
} int m = i - coins[j];//此处若修改为 m = i % coins[j]会出错
if(memo[m] != -1){
memo[i] = Math.min(memo[i], 1 + memo[m]);
}
} memo[i] = (memo[i] == Integer.MAX_VALUE) ? -1 : memo[i];
} return memo[amount];
}
}

Integer Break

方法一 : 自底向上, 递推 + memo

与coin change很像

class Solution {
public int integerBreak(int n) {
int[] memo = new int[n + 1];
memo[0] = 1;
memo[1] = 1;
memo[2] = 1; for(int i = 3; i <= n; i++){
int a = i / 2 + 1;
for(int j = 1; j < a; j++){
int x = Math.max(j, memo[j]);
int y = Math.max(i - j, memo[i - j]);
memo[i] = Math.max(memo[i], x * y);
}
} return memo[n];
}
}

Largest Divisible Subset

方法一 : 自底向上, 递推 + memo

class Solution {
public List<Integer> largestDivisibleSubset(int[] nums) {
if(nums.length < 1) return new ArrayList<>(); List<List<Integer>> memo = new ArrayList<List<Integer>>();
Arrays.sort(nums); int gIdx = 0;
int gLen = 0; List<Integer> li = new ArrayList<>();
li.add(nums[0]);
memo.add(li); // 1 for(int i = 1; i < nums.length; i ++){
int longIdx = i;
int longLen = 0; for(int j = 0; j < i; j++){
int tlen = memo.get(j).size();
if(nums[i] % memo.get(j).get(tlen - 1) == 0){
if(longLen < tlen){
longLen = tlen; longIdx = j;
}
}
} if(longIdx == i){
List<Integer> li2 = new ArrayList<>();
li2.add(nums[i]);
memo.add(li2);
}
else{
List<Integer> li3 = new ArrayList<>(memo.get(longIdx));
li3.add(nums[i]);
memo.add(li3);
if(memo.get(i).size() > gLen){
gIdx = i; gLen = memo.get(i).size();
}
}
} if(gLen == 0) return memo.get(0);
return memo.get(gIdx);
}
}

Combination Sum IV

方法一: 自顶向下 回溯法 TimeLimitExceed, 11 / 17

class Solution {
public int combinationSum4(int[] nums, int target) {
Arrays.sort(nums);
return dfs(nums, target);
} int dfs(int[] nums, int tgt){ if(tgt == 0){
return 1;
}
else if(tgt < 0){
return 0;
} int sumC = 0;
for(int i = 0; i < nums.length; i ++){
int newTgt = tgt - nums[i];
if(newTgt >= 0){
sumC += dfs(nums, newTgt);
}
else{
break;
}
} return sumC;
}
}

方法二:自底向上 递推 + memo

class Solution {
public int combinationSum4(int[] nums, int target) {
Arrays.sort(nums); int[] memo = new int[target + 1];
memo[0] = 0; for(int i = 1; i <= target; i++){ for(int j = 0; j < nums.length; j++){
if(i < nums[j]){
continue;
} if(i == nums[j]){
memo[i] += 1;
}
else{
int t = i - nums[j];
if(memo[t] != 0){
memo[i] += memo[t];
}
}
} } return memo[target];
}
}

646. Maximum Length of Pair Chain

方法一 : 耗时47ms

这是一道变型的Longest Increase Subsequence;注意,这里有二维数组的排序方法

class Solution {
public int findLongestChain(int[][] pairs) {
int len = pairs.length;
if(len < 2) return len;
Integer[][] p = new Integer[len][2];
for(int i = 0; i < len; i ++){
p[i][0] = pairs[i][0];
p[i][1] = pairs[i][1];
} Arrays.sort(p, new Comparator<Integer[]>(){
public int compare(Integer[] o1, Integer[] o2){
return o1[0] - o2[0];
}
}); int[] dp = new int[len];
dp[0] = 1; for(int i = 1; i < len; i ++){ int maxi = 1;
for(int j = 0; j < i; j ++){
if(p[j][1] < p[i][0]){
maxi = dp[j] + 1;
}
} dp[i] = maxi;
} return dp[len - 1];
}
}

方法二 : 使用自己的快排,耗时3ms

class Solution {
public int findLongestChain(int[][] pairs) {
if (pairs == null)
return 0;
int len = pairs.length;
if (len < 2)
return len;
qsort(pairs, 0, len - 1);
int sum = 1;
int end = pairs[0][1];
for (int i = 1; i < len; ++i) {
if (pairs[i][0] > end) {
++sum;
end = pairs[i][1];
}
}
return sum;
} private void qsort(int[][] pairs, int begin, int end) {
if (begin >= end)
return;
int key = pairs[begin][1];
int[] keyPair = pairs[begin];
int i = begin, j = end;
while(i < j) {
while(i < j && key <= pairs[j][1])
--j;
pairs[i] = pairs[j];
while(i < j && key >= pairs[i][1])
++i;
pairs[j] = pairs[i];
}
pairs[i] = keyPair;
qsort(pairs, begin, i - 1);
qsort(pairs, i + 1, end);
}
}

650. 2 Keys Keyboard

方法一:递推 + memo

还有递推方法,参考

class Solution {
public int minSteps(int n) {
int[] dp = new int[n];
dp[0] = 0; for(int i = 2; i <= n; i++){ int halfi = i >> 1;
int mini = i;
for(int j = 2; j <= halfi; j++){
if(i % j == 0){
mini = Math.min(mini, dp[j-1] + 1 + i / j - 1);
}
}
dp[i-1] = mini;
} return dp[n-1];
}
}

376. Wiggle Subsequence :

方法一: 递推 + memo

这道题是LIS的变形,原理都一样

class Solution {
public int wiggleMaxLength(int[] nums) {
if(nums.length == 0) return nums.length; int[][] dp = new int[nums.length][2]; dp[0][0] = dp[0][1] = 1; for(int i = 1; i < nums.length; i ++){ dp[i][0] = dp[i][1] = 1;
for(int j = 0; j < i; j ++){
if(nums[i] > nums[j]){
dp[i][0] = Math.max(dp[i][0], dp[j][1] + 1);
}
if(nums[i] < nums[j]){
dp[i][1] = Math.max(dp[i][1], dp[j][0] + 1);
}
}
} return Math.max(dp[nums.length - 1][0], dp[nums.length - 1][1]);
}
}

leetcode动态规划笔记三---单序列型的更多相关文章

  1. leetcode动态规划笔记二

    动态规划 题目分类 一维dp 矩阵型DP Unique Paths II : 矩阵型DP,求所有方法总数 Minimum Path Sum:矩阵型,求最大最小值 Triangle : 矩阵型,求最大最 ...

  2. leetcode动态规划笔记一---一维DP

    动态规划 刷题方法 告别动态规划,连刷 40 道题,我总结了这些套路,看不懂你打我 - 知乎 北美算法面试的题目分类,按类型和规律刷题 题目分类 一维dp House Robber : 求最大最小值 ...

  3. 【Python】学习笔记三:序列

    sequence(序列) sequence(序列)是一组有序的元素的集合,序列可以有任何元素,也可以没有元素 元组与表的区别:一旦建立,tuple的各个元素不可再变更,而list的各个元素可以再变更 ...

  4. AngularJS学习笔记(三) 单页面webApp和路由(ng-route)

    就我现在的认识,路由($route)这个东西(也许可以加上$location)可以说是ng最重要的东西了.因为angular目前最重要的作用就是做单页面webApp,而路由这个东西是能做到页面跳转的关 ...

  5. Leetcode 413. Arithmetic Slice 算术序列切片(动态规划,暴力)

    Leetcode 413. Arithmetic Slice 算术序列切片(动态规划,暴力) 题目描述 如果一个数组1.至少三个元素2.两两之间差值相同,那么这个数组就是算术序列 比如下面的数组都是算 ...

  6. 吴恩达《深度学习》-第五门课 序列模型(Sequence Models)-第三周 序列模型和注意力机制(Sequence models & Attention mechanism)-课程笔记

    第三周 序列模型和注意力机制(Sequence models & Attention mechanism) 3.1 序列结构的各种序列(Various sequence to sequence ...

  7. 《MFC游戏开发》笔记三 游戏贴图与透明特效的实现

    本系列文章由七十一雾央编写,转载请注明出处. 313239 作者:七十一雾央 新浪微博:http://weibo.com/1689160943/profile?rightmod=1&wvr=5 ...

  8. 学习笔记(三)--->《Java 8编程官方参考教程(第9版).pdf》:第十章到十二章学习笔记

    回到顶部 注:本文声明事项. 本博文整理者:刘军 本博文出自于: <Java8 编程官方参考教程>一书 声明:1:转载请标注出处.本文不得作为商业活动.若有违本之,则本人不负法律责任.违法 ...

  9. 构建高性能WEB站点笔记三

    构建高性能WEB站点笔记三 第10章 分布式缓存 10.1数据库的前端缓存区 文件系统内核缓冲区,位于物理内存的内核地址空间,除了使用O_DIRECT标记打开的文件以外,所有对磁盘文件的读写操作都要经 ...

随机推荐

  1. openwrt共享打印机需要安装哪几个文件

    opkg updateopkg install luci-app-p910ndopkg install kmod-usb-printer

  2. ORA-39142: incompatible version number 5.1 in dump file

    ORA-39142: incompatible version number 5.1 in dump file http://blog.itpub.net/26664718/viewspace-214 ...

  3. 常见的医学基因筛查检测 | genetic testing | 相癌症早筛 | 液体活检

    NIPT, Non-invasive Prenatal Testing - 无创产前基因检测 (学术名词) NIFTY,胎儿染色体异常无创产前基因检测 (注册商标)华大的明显产品 新生儿耳聋基因检测 ...

  4. spring-data-mongodb中的MongoTemplate与MongoRepository及推荐

    SpringData支持两种关系数据存储技术: JDBCJPA ● SpringData 方法定义JPA规范: 1. 不是随便声明的,而需要符合一定的规范2. 查询方法以find | read | g ...

  5. GIS地理处理工具案例教程-成本距离

    GIS地理处理工具案例教程-成本距离 关键词:最短路径,成本路径,最佳路径,最优路径,路径分析,选线分析 商务合作,科技咨询,版权转让:向日葵,135-4855__4328,xiexiaokui#qq ...

  6. button按钮的状态为disabled禁用状态,click事件无法触发,但是为什么touchstart下却依然可以触发

    切换到移动模拟模式,并点击按钮,查看控制台. 发现click没有事件没有触发,而touch事件依然触发. 解决办法: 对于移动端我们使用css来禁止按钮,达到disable的效果: 对,就是这个神奇的 ...

  7. 算法习题---4-9数据挖掘(Uva1591)

    一:题目 这是最懵逼的一道题,什么鬼......... [刷题]算法竞赛入门经典(第2版) 4-9/UVa1591 - Data Mining(详细题目看这个吧,不想多说) 二:代码实现 #defin ...

  8. Qt编写气体安全管理系统9-数据查询

    一.前言 数据查询模块在整个系统中难度最低,由于Qt对数据库操作的封装堪称完美,所以各种查询都是手到擒来,不费吹灰之力.Qt中内置了sqlite数据库,你可以在数据库插件目录sqldrivers发现q ...

  9. Hadoop记录-部署hadoop环境shell实现

    #!/bin/bash menu() { echo "---欢迎使用hadoop部署管理程序---" echo "# 1.初始化Linux环境" echo &q ...

  10. replicationController 使用

    [root@lab2 nginx-harbor]# cat http-test.yaml apiVersion: v1 kind: ReplicationController metadata: na ...