总结一道提交了无数遍的DP问题 :

5. 最长回文子串,这是学习DP的一道提交了很长时间的题目:

这道题目用O(n3)O(n^3)O(n3) 的时间复杂度是比较容易的,显而易见会超时。用之前学的滑动窗口方法也是能做的,但是我的超时了、哭~,最后选择DP,下面是我提交的代码:

class Solution {public String longestPalindrome(String s) {int len = s.length();if(len <= 1) return s;boolean dp[][] = new boolean[len][len];for(int i = 0; i<len; i++)dp[i][i] = true;// ----------上面是初始化过程-----------------------int max = 0;String ret = "";for(int i = len-1; i>=0; i--){for(int j = i; j < len; j++){dp[i][j] = (s.charAt(i) == s.charAt(j))&& (j-i <= 2 || dp[i+1][j-1]);if(dp[i][j] && j-i+1>max){max = j-i+1;ret = s.substring(i,j+1);}}}return ret;}
}

其中dp[i][j]数组是index 的i到j是否是回文子串,这里我判断是根据如果s[i]和s[j] 是否相等,如果不相等那么dp[i][j]直接false,否则接着判断 dp[i+1][j-1]是否相等呢,如果继续相等,那就是回文子串,这里j-i 表示这么一类情况,比如 asa 这种我们只要判断两端相等了,就不用管中间那个单独的字母,这里最重要的是选择for循环的,for循环对解题取得关键作用,之前一直提交失败原因是for循环区间选错了,导致dp[i][j]先于dp[i+1][j-1] 出来,就默认 dp[i+1][j-1]为false,怎么都会失败。


下面还是一个DP问题,这是一道easy题目,但是我为了用DP做出来还是想了很久:

121. 买卖股票的最佳时机

很明显,用暴力两层循环也是能过的,但是没啥意思,暴力做了551ms,DP只要3ms

这里我的思路是不断找最小解之间的关系,我定义的DP[i]表示第i天卖出,最大利润,代码如下:

class Solution {public int maxProfit(int[] prices) {// 尝试用DP解决 dp[i]表示第i天最大的利润int len = prices.length;if(len == 0) return 0;Integer [] dp = new Integer[len];int max = 0;dp[0] = 0;int lastdp0 = prices[0];for(int i = 1; i<len; i++){dp[i] = prices[i] - lastdp0;if(dp[i] <= 0){dp[i] = 0;lastdp0 = prices[i];}else{if(dp[i] > max)max = dp[i];}}return max;}
}

首先明确初始解 dp[0] = 0 ,表示第0天卖出,没利润。dp[1]和dp[0]之间的关系:如果prices[1] < price[0],表示股价跌了,还是没挣钱dp[1] = 0,如果 prices[1] > price[0] ,表示挣了dp[1] = price[1]-price[0],推广开来,第i天最大利润是 prices[i] - (最后一个dp[j] = 0所对应的prices[j]),代码中,我用lastdp0记录下来。


139. 单词拆分,这是一道tag为DP的题目,但是我最终是用 DFS算出来的,每个失眠的夜晚 脑袋都是这种题目~~

先上code:

class Solution {boolean res = false;public boolean wordBreak(String s, List<String> wordDict) {if(s.length() == 0) return true;Map<String,Integer> map = new HashMap();for(int i = 0; i<wordDict.size(); i++)map.put(wordDict.get(i),0);Boolean []mark = new Boolean[s.length()+1];return splits(s,0,s.length(),map,mark);}public boolean splits(String s, int start, int end, Map<String,Integer> map, Boolean []mark){for(int i = start; i<end; i++){String patern = s.substring(start,i+1);if(map.get(patern) != null && i+1 != end){boolean res1 = false;if(mark[i] != null)res1 = mark[i];else{res1 =  splits(s,i+1,end,map,mark);mark[i] = res1;}res = res || res1;}if(map.get(patern) != null && i+1 == end){return true;}}return false || res;}
}

不得不说,我的代码着实写的非常丑,我还是很有必要看一下代码简洁之美。大致解释一下我的代码:

首先,我把所有的wordDict放到map中,这里我后来发现没啥必要了,List有个contains方法就直接解决了这个问题。但是这不重要了,这里我重点还是想总结一下解题思路。这里递归终止的条件是 start到达了字符串最后的同时,最后一个字符串也匹配到了,此时是返回true。不然的话,就对除了匹配到的字符串,剩下的的字串接着匹配,同时为了剪枝,还要记录start位置,所对应的递归字串结果,如果之前已经记录下来了就不用再次递归了。重点是下面的代码:

if(map.get(patern) != null && i+1 != end){boolean res1 = false;if(mark[i] != null)res1 = mark[i];else{res1 =  splits(s,i+1,end,map,mark); //这里不立即返回的原因是还要对下面这种情况判断
// cantsrt   {"can","cant","srt"} 找到can还不能返回,还要接着找cant,最后汇总除can递归字串和除cant递归字串的结果 res = res || res1mark[i] = res1;}res = res || res1;  // 只要有一个递归最后完美结束了,就算找到了}

最后剪枝之后AC了,不剪枝是AC不了,碰到aaaaaaaaaaaa这种,时间复杂度就爆炸了( O(nn)O(n^n)O(nn) )。


下面是一道记忆化搜索问题(这种题目一般可以转DP):

这道题和那道整数拆分一样的套路,也是记忆化搜索来进行剪枝。

class Solution {HashMap<Integer,Integer> map = new HashMap();public int numSquares(int n) {int val = (int)Math.sqrt(n);if(val*val == n) return 1;if(map.get(n) != null) return map.get(n);int res = Integer.MAX_VALUE;  //每次都要初始化这个结果值for(int i = 1; i*i<n;i++)res = Math.min(res,1+numSquares(n-i*i));map.put(n,res);return res;}
}

下面怎么转DP,这是个问题

关于DP的一些解题总结相关推荐

  1. [入门向选讲] 插头DP:从零概念到入门 (例题:HDU1693 COGS1283 BZOJ2310 BZOJ2331)

    转载请注明原文地址:http://www.cnblogs.com/LadyLex/p/7326874.html 最近搞了一下插头DP的基础知识--这真的是一种很锻炼人的题型-- 每一道题的状态都不一样 ...

  2. Python3解题:二叉树路径总和问题

    Python3解题:二叉树路径总和问题 原题 https://leetcode-cn.com/problems/path-sum-ii/ 给定一个二叉树和一个目标和,找到所有从根节点到叶子节点路径总和 ...

  3. 【codevs1048】【codevs115406TG】石子归并、能量项链,序列dp的典型题目

    1048 石子归并 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 黄金 Gold 题解 题目描述 Description 有n堆石子排成一列,每堆石子有一个重量w[i], 每次合并 ...

  4. 关于DFS(深度优先搜索)与DP(动态规划)的思考

    DFS与DP的关系 很多情况下,dfs和dp两种解题方法的思路都是很相似的,这两种算法在一定程度上是可以互相转化的. 想到dfs也就常常会想到dp,当然在一些特定的适用场合下除外. dp主要运用了预处 ...

  5. 动态规划27k字超详细保姆级入门讲解——附DP经典线性、区间、二维图、四维8个模型题解

    动态规划27k字超详细保姆级入门讲解 写在前面: 这篇文章是目前为止我写过最长也是最久的文章,前面关于DP的讲解我查阅了大量的博客资料,学习其他博主对DP的理解,也翻阅了很多经典的纸质书籍,同时做了近 ...

  6. 【leetcode】二叉树与经典问题

    文章目录 笔记 leetcode [114. 二叉树展开为链表](https://leetcode-cn.com/problems/flatten-binary-tree-to-linked-list ...

  7. LeetCode 337. 打家劫舍 III(记忆化+递归)

    文章目录 1. 题目 1.1 相关题目: 2. 解题 2.1 递归 2.2 记忆化递归 1. 题目 在上次打劫完一条街道之后和一圈房屋后,小偷又发现了一个新的可行窃的地区.这个地区只有一个入口,我们称 ...

  8. 动态规划——最小路径和(Leetcode 64)

    题目选自Leetcode 64.最小路径和 题目描述 解题思路 前言: 解题的方法是用动态规划~ 从数据范围可以看出,n.m最多就是200×200的大小,所以dp数组就开201 那么,怎么进行动态规划 ...

  9. 二维动态规划降维误差一般为多少_动态规划--5道题入门

    动态规划是由递归一步步优化出来的 递归–>记忆化递归–>动态规划 动态规划与其说是一个算法,不如说是一种方法论.该方法论主要致力于将合适的问题拆分成三个子目标--击破: 1.建立状态转移方 ...

最新文章

  1. SVM进行手写数字识别
  2. JavaScript的9个陷阱及评点
  3. ipad如何连接电脑_ipad如何将电脑文件下载到本地?
  4. 分布式精华问答 | 分布式系统面临哪些挑战?​
  5. 0804------算法笔记----------最长公共子序列
  6. Android progressBar 自定义
  7. css3 圣诞红包雨效果
  8. YOLOv5图像识别显示中文标签
  9. 《A Tale of Two Worlds (CCS‘19)》笔记
  10. 我还年轻——献给37岁的自己
  11. 2016年蓝桥杯java——分小组
  12. 计算机专业研究生核心能力培养(0)——计算机专业要不要读研?
  13. 移动双臂机器人仿真[0]--概述
  14. win10怎么用计算机的搜索,win10搜索文件内容怎么操作_win10如何搜索文档内的内容...
  15. 使用Python预测黄金AU9999收盘价
  16. 小程序抢购页面倒计时定时器
  17. 医学计算机模型现状,【盘点】计算机模型开发助力多种人类疾病的深入研究
  18. XP下网络连接提示受限制的解决方法
  19. 分享卡通儿童中小学班干竞选PPT模板
  20. 程序人生之真正女程序员是什么样的

热门文章

  1. 如何在eclipse中使用XYLayout布局?在此介绍如何把XYLayout导入到eclipse .
  2. menu---A.2-基本算法实例
  3. HBase基本操作-java api
  4. Java拾遗:007 - 代理模式与动态代理
  5. Jquery根据JSON生成Table
  6. @NotBlank注解地正确使用
  7. JavaScript依赖注入的实现思路
  8. 网页javascript部分
  9. 兼容性测试之VMware
  10. printf 规定数据输出方式