单序列型DP

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

Perfect Squares :

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

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

  1. class Solution {
  2. public int numSquares(int n) {
  3. int[] memo = new int[n];
  4. for(int i = 1; i <= n; i++){
  5. if(i * i <= n){
  6. memo[i*i - 1] = 1;
  7. }
  8. }
  9. if(memo[n-1] == 1) return 1;
  10. memo[1] = 2;
  11. for(int i = 3; i <= n; i++){
  12. if(memo[i-1] == 1) continue;
  13. int left = 1;
  14. int right = i - 1;
  15. int mini = Integer.MAX_VALUE;
  16. while(left <= right){
  17. if(left + right == i){
  18. mini = Math.min(mini, memo[left - 1] + memo[right - 1]);
  19. }
  20. left ++; right--;
  21. }
  22. memo[i-1] = mini;
  23. }
  24. return memo[n - 1];
  25. }
  26. }

方法二: 递推 + memo

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

  1. class Solution {
  2. public int numSquares(int n) {
  3. int[] memo = new int[n + 1];
  4. memo[0] = 0;
  5. for(int i = 1; i <= n; i++){
  6. int mini = Integer.MAX_VALUE;
  7. for(int j = 1; j <= i; j ++){
  8. int t = j*j;
  9. if(t > i) break;
  10. if(t == i) mini = 1;
  11. else mini = Math.min(mini, memo[t] + memo[i-t]);
  12. }
  13. memo[i] = mini;
  14. }
  15. return memo[n];
  16. }
  17. }

Longest Increasing Subsequence

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

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

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

  1. class Solution {
  2. public int lengthOfLIS(int[] nums) {
  3. if(nums.length == 0) return 0;
  4. int[] memo = new int[nums.length];
  5. memo[0] = 1;
  6. int maxi = 1;
  7. for(int i = 1; i < nums.length; i++){
  8. memo[i] = 1;
  9. for(int j = i - 1; j >= 0; j--){
  10. if(nums[i] > nums[j])
  11. memo[i] = Math.max(memo[i], memo[j] + 1);
  12. }
  13. maxi = Math.max(memo[i], maxi);
  14. }
  15. return maxi;
  16. }
  17. }

Increasing Triplet Subsequence : 求是否存在

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

  1. class Solution {
  2. public boolean increasingTriplet(int[] nums) {
  3. if(nums.length == 0) return false;
  4. int[] memo = new int[nums.length];
  5. memo[0] = 1;
  6. boolean exist = false;
  7. for(int i = 1; i < nums.length; i ++){
  8. memo[i] = 1;
  9. for(int j = 0; j < i; j ++){
  10. if(nums[i] > nums[j]){
  11. memo[i] = Math.max(memo[j] + 1, memo[i]);
  12. }
  13. }
  14. if(memo[i] == 3){
  15. exist = true;break;
  16. }
  17. }
  18. return exist;
  19. }
  20. }

Coin Change

方法一: 自底向上

递推 + memo

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

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

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

  1. class Solution {
  2. public int coinChange(int[] coins, int amount) {
  3. Arrays.sort(coins);
  4. int[] memo = new int[amount + 1];
  5. for(int i = 1; i <= amount; i++){
  6. memo[i] = Integer.MAX_VALUE;
  7. for(int j = coins.length - 1; j >= 0; j--){
  8. if(i < coins[j]) continue;
  9. if(i == coins[j]){
  10. memo[i] = 1;
  11. continue;
  12. }
  13. int m = i - coins[j];//此处若修改为 m = i % coins[j]会出错
  14. if(memo[m] != -1){
  15. memo[i] = Math.min(memo[i], 1 + memo[m]);
  16. }
  17. }
  18. memo[i] = (memo[i] == Integer.MAX_VALUE) ? -1 : memo[i];
  19. }
  20. return memo[amount];
  21. }
  22. }

Integer Break

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

与coin change很像

  1. class Solution {
  2. public int integerBreak(int n) {
  3. int[] memo = new int[n + 1];
  4. memo[0] = 1;
  5. memo[1] = 1;
  6. memo[2] = 1;
  7. for(int i = 3; i <= n; i++){
  8. int a = i / 2 + 1;
  9. for(int j = 1; j < a; j++){
  10. int x = Math.max(j, memo[j]);
  11. int y = Math.max(i - j, memo[i - j]);
  12. memo[i] = Math.max(memo[i], x * y);
  13. }
  14. }
  15. return memo[n];
  16. }
  17. }

Largest Divisible Subset

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

  1. class Solution {
  2. public List<Integer> largestDivisibleSubset(int[] nums) {
  3. if(nums.length < 1) return new ArrayList<>();
  4. List<List<Integer>> memo = new ArrayList<List<Integer>>();
  5. Arrays.sort(nums);
  6. int gIdx = 0;
  7. int gLen = 0;
  8. List<Integer> li = new ArrayList<>();
  9. li.add(nums[0]);
  10. memo.add(li); // 1
  11. for(int i = 1; i < nums.length; i ++){
  12. int longIdx = i;
  13. int longLen = 0;
  14. for(int j = 0; j < i; j++){
  15. int tlen = memo.get(j).size();
  16. if(nums[i] % memo.get(j).get(tlen - 1) == 0){
  17. if(longLen < tlen){
  18. longLen = tlen; longIdx = j;
  19. }
  20. }
  21. }
  22. if(longIdx == i){
  23. List<Integer> li2 = new ArrayList<>();
  24. li2.add(nums[i]);
  25. memo.add(li2);
  26. }
  27. else{
  28. List<Integer> li3 = new ArrayList<>(memo.get(longIdx));
  29. li3.add(nums[i]);
  30. memo.add(li3);
  31. if(memo.get(i).size() > gLen){
  32. gIdx = i; gLen = memo.get(i).size();
  33. }
  34. }
  35. }
  36. if(gLen == 0) return memo.get(0);
  37. return memo.get(gIdx);
  38. }
  39. }

Combination Sum IV

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

  1. class Solution {
  2. public int combinationSum4(int[] nums, int target) {
  3. Arrays.sort(nums);
  4. return dfs(nums, target);
  5. }
  6. int dfs(int[] nums, int tgt){
  7. if(tgt == 0){
  8. return 1;
  9. }
  10. else if(tgt < 0){
  11. return 0;
  12. }
  13. int sumC = 0;
  14. for(int i = 0; i < nums.length; i ++){
  15. int newTgt = tgt - nums[i];
  16. if(newTgt >= 0){
  17. sumC += dfs(nums, newTgt);
  18. }
  19. else{
  20. break;
  21. }
  22. }
  23. return sumC;
  24. }
  25. }

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

  1. class Solution {
  2. public int combinationSum4(int[] nums, int target) {
  3. Arrays.sort(nums);
  4. int[] memo = new int[target + 1];
  5. memo[0] = 0;
  6. for(int i = 1; i <= target; i++){
  7. for(int j = 0; j < nums.length; j++){
  8. if(i < nums[j]){
  9. continue;
  10. }
  11. if(i == nums[j]){
  12. memo[i] += 1;
  13. }
  14. else{
  15. int t = i - nums[j];
  16. if(memo[t] != 0){
  17. memo[i] += memo[t];
  18. }
  19. }
  20. }
  21. }
  22. return memo[target];
  23. }
  24. }

646. Maximum Length of Pair Chain

方法一 : 耗时47ms

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

  1. class Solution {
  2. public int findLongestChain(int[][] pairs) {
  3. int len = pairs.length;
  4. if(len < 2) return len;
  5. Integer[][] p = new Integer[len][2];
  6. for(int i = 0; i < len; i ++){
  7. p[i][0] = pairs[i][0];
  8. p[i][1] = pairs[i][1];
  9. }
  10. Arrays.sort(p, new Comparator<Integer[]>(){
  11. public int compare(Integer[] o1, Integer[] o2){
  12. return o1[0] - o2[0];
  13. }
  14. });
  15. int[] dp = new int[len];
  16. dp[0] = 1;
  17. for(int i = 1; i < len; i ++){
  18. int maxi = 1;
  19. for(int j = 0; j < i; j ++){
  20. if(p[j][1] < p[i][0]){
  21. maxi = dp[j] + 1;
  22. }
  23. }
  24. dp[i] = maxi;
  25. }
  26. return dp[len - 1];
  27. }
  28. }

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

  1. class Solution {
  2. public int findLongestChain(int[][] pairs) {
  3. if (pairs == null)
  4. return 0;
  5. int len = pairs.length;
  6. if (len < 2)
  7. return len;
  8. qsort(pairs, 0, len - 1);
  9. int sum = 1;
  10. int end = pairs[0][1];
  11. for (int i = 1; i < len; ++i) {
  12. if (pairs[i][0] > end) {
  13. ++sum;
  14. end = pairs[i][1];
  15. }
  16. }
  17. return sum;
  18. }
  19. private void qsort(int[][] pairs, int begin, int end) {
  20. if (begin >= end)
  21. return;
  22. int key = pairs[begin][1];
  23. int[] keyPair = pairs[begin];
  24. int i = begin, j = end;
  25. while(i < j) {
  26. while(i < j && key <= pairs[j][1])
  27. --j;
  28. pairs[i] = pairs[j];
  29. while(i < j && key >= pairs[i][1])
  30. ++i;
  31. pairs[j] = pairs[i];
  32. }
  33. pairs[i] = keyPair;
  34. qsort(pairs, begin, i - 1);
  35. qsort(pairs, i + 1, end);
  36. }
  37. }

650. 2 Keys Keyboard

方法一:递推 + memo

还有递推方法,参考

  1. class Solution {
  2. public int minSteps(int n) {
  3. int[] dp = new int[n];
  4. dp[0] = 0;
  5. for(int i = 2; i <= n; i++){
  6. int halfi = i >> 1;
  7. int mini = i;
  8. for(int j = 2; j <= halfi; j++){
  9. if(i % j == 0){
  10. mini = Math.min(mini, dp[j-1] + 1 + i / j - 1);
  11. }
  12. }
  13. dp[i-1] = mini;
  14. }
  15. return dp[n-1];
  16. }
  17. }

376. Wiggle Subsequence :

方法一: 递推 + memo

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

  1. class Solution {
  2. public int wiggleMaxLength(int[] nums) {
  3. if(nums.length == 0) return nums.length;
  4. int[][] dp = new int[nums.length][2];
  5. dp[0][0] = dp[0][1] = 1;
  6. for(int i = 1; i < nums.length; i ++){
  7. dp[i][0] = dp[i][1] = 1;
  8. for(int j = 0; j < i; j ++){
  9. if(nums[i] > nums[j]){
  10. dp[i][0] = Math.max(dp[i][0], dp[j][1] + 1);
  11. }
  12. if(nums[i] < nums[j]){
  13. dp[i][1] = Math.max(dp[i][1], dp[j][0] + 1);
  14. }
  15. }
  16. }
  17. return Math.max(dp[nums.length - 1][0], dp[nums.length - 1][1]);
  18. }
  19. }

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. 京东 PC 首页 2019 改版前端总结 原创: 何Jason,EC,小屁 凹凸实验室 今天

    京东 PC 首页 2019 改版前端总结 原创: 何Jason,EC,小屁 凹凸实验室 今天

  2. JS 数组对象的某一项抽离出来放在外面

    数组类型: shamDeviceData: [ { "projectKey":"5555", "productKey":"5555 ...

  3. 一起入门Python1之python的介绍

    之前在某安全论坛发表的一些关于python的文章,但是由于一些问题一直没有完成,那个论坛也歇菜了.放到这儿来吧. 说句默心掏肺的话,我也是才学习python.之所以要这个版主,是为了锻炼自己,也是为了 ...

  4. 服务器端实时推送技术之SseEmitter的用法

    这是SpringMVC提供的一种技术,可以实现服务端向客户端实时推送数据.用法非常简单,只需要在Controller提供一个接口,创建并返回SseEmitter对象,发送数据可以在另一个接口调用其se ...

  5. Python3基础 函数 参数 多个参数都有缺省值,需要指定参数进行赋值

             Python : 3.7.3          OS : Ubuntu 18.04.2 LTS         IDE : pycharm-community-2019.1.3    ...

  6. 003-结构型-05-桥接模式(Bridge)

    一.概述 将抽象部分与它的具体实现部分分离.使它们都可以独立地变化.通过组合的方式建立两个类之间联系,而不是继承. Bridge 模式又叫做桥接模式,是构造型的设计模式之一.Bridge模式基于类的最 ...

  7. Python - Django - ORM F查询和Q查询

    models.py: from django.db import models # 出版社 class Publisher(models.Model): id = models.AutoField(p ...

  8. Mysql8.0.17版本不能自动创建activiti表的坑

    maven项目如下: 配置好数据库,和activiti的配置之后,开始执行流程部署 package com.yuanqiao.first_activiti.deployment; import jav ...

  9. 迅速生成项目-react-static

    推荐指数:

  10. 测试框架nunit之assertion断言使用详解

    任何xUnit工具都使用断言进行条件的判断,NUnit自然也不例外,与其它的xUnit(如Junit.phpUnit.pythonUnit)相比,由于大量使用了Generic.Attribute等语言 ...