LeetCode做题笔记之动态规划
LeetCode之动态规划
时间有限只做了下面这几道:70、338、877、96、120、95、647,后续会继续更新
70:爬楼梯
先来道简单的练练手,一道经典的动态规划题目
可以采用动态规划的备忘录法,第n节楼梯的数目等于第n-1节和n-2节的和,因为第n节一定由n-1或n-2上去的。可以不使用递归而使用简单的for循环实现:
public int climbStairs(int n) {
int[] ints = new int[n + 1];
ints[1] = 1;
if (n > 1) ints[2] = 2;
for (int i = 3; i <= n; i++) {
ints[i] = ints[i - 1] + ints[i - 2];
}
return ints[n];
}
这道题的难点在于想到第n节的数目等于n-1和n-2节的数目,对于没有接触过动态规划的菜鸟来说还是有点意思的。
PS:如果数目过大超出了int类型的最大值,可以使用BigInteger类
338:比特位计数
这道题也还行,对二进制数来说,一个偶数的最后一位一定是0,基于这个原理可以得出下面的代码:
for (int i = 0; i < arr.length; i++) {
if (i % 2 == 0) {
arr[i] = arr[i / 2];
}else {
arr[i] = arr[i /2] + 1;
}
}
然而~~大佬们总是有强大的方法,我那if else用一行代码就搞定了:arr[i] = arr[i >> 1] + (i & 1),右移倒也还好,这个i & 1用的就简直了,佩服佩服。
话说这和动态规划没什么关系吧?可我是专门挑的动态规划的题做的欸
877:石子游戏
感觉这题出的不太好,因为我想看到的是你的算法比我的算法厉害,而不是你直接给我说先手必赢,因为我完全没有往这方面考虑过(估计大佬能想出来吧)。先手必赢的原因是先手可以决定拿所有的偶数堆还是奇数堆,而对偶数堆和奇数堆两个一定有一个是数目比较多的(总数为奇数)
最开始我觉得比较一下前后的的大小直接挑大的就行,但是对于[3,2,10,4]这样的排列先手会得7分而后手得12分,这显然是错误的。
这一题的思路是以局部最优解得出整体最优解,典型的动态规划
public static boolean stoneGame(int[] piles) {
int length = piles.length;
//results[i][j]存储的是piles中第i个数到第j个数组成序列的最佳拿取方式下的得分
int[][] results = new int[length][length];
//当集合中只有一个堆的时候,拿的那个人直接得分
for(int i=0;i<length;i++){
results[i][i]=piles[i];
}
//当集合中有两个数的时候,先选的人肯定是拿较大数,分数为max-min
for(int i=0;i<length-1;i++){
results[i][i+1]=Math.abs(piles[i]-piles[i+1]);
}
for(int i=length-3;i>=0;i--){
for(int j=i+2;j<length;j++){
results[i][j]=Math.max(piles[i]-results[i+1][j],piles[j]-results[i][j-1]);
}
}
return results[0][length-1]>0;
}
对于二维数组results[i][j]:
第一个for循环计算的是绿色的方块,第二个for循环计算蓝色的方块,第三个填充右上的白色的方块

最后只要看右上角的值是否大于0即可。
96:不同的二叉搜索树
这一道题的难点在于找出节点增加时二叉搜索树种类如何增加。
首先,新增加的节点默认是最大的(不然没什么意义),对于n+1个节点的树来说,有C(n+1) = C0 * Cn + C1 * C(n-1) + ... + C(n-1) * C1 + Cn * C0其中C0 = 1, C1 = 1解释:对于第n+1个节点的树来说,C0 * Cn对应以最小节点为根节点,左节点为0个,右节点为n个;C1 * C(n-1)对应以倒数第二小的为根节点,左边1个节点,右边n-1个节点......直到第n+1个节点为子节点。这样的话代码就很容易写出来了。
public static int numTrees(int n) {
if(n<=1)return 1;
int[] dp=new int[n+1];
dp[0]=1;
dp[1]=1;
for(int i=2;i<=n;i++){
for(int j=1;j<=i;j++){
dp[i]+=dp[j-1]*dp[i-j];
}
}
return dp[n];
}
话说这道题根本和动态规划没多大关系啊,完全是在计算CatAlan数。。。
120:三角形最小路径和
这一题和第877题比较像,可以把三角形斜向左上,就像这样:

解法也和877比较像:
public static int minimumTotal(List<List<Integer>> triangle) {
int[][] arr = new int[triangle.size()][triangle.size()];
List<Integer> lastList = triangle.get(triangle.size() - 1);
for (int i = 0; i < lastList.size(); i++) {
arr[arr.length - 1 - i][i] = lastList.get(i);
}
for (int n = triangle.size() -2; n >= 0; n--) {
List<Integer> list = triangle.get(n);
for (int i = 0; i <= n; i++) {
int j = n-i;
arr[i][j] = list.get(j) + Math.min(arr[i + 1][j], arr[i][j + 1]);
}
}
return arr[0][0];
}
然后再新建个一样的二维数组记录由该点到底部所需的最小和。
95:不同的二叉搜索树2
这一题是第96题的增强题,不仅要求求出多少个,还要求出每个什么样子。这一题其实最开始没解出来,看了答案之后才动了怎么做,原来是通过暴力递归(貌似也只能这么做了),题目做多了之后下意识地觉得肯定不是暴力解,总想着找一种更省力的方法,然而有时候就是会陷入其中。
private static List<TreeNode> helper(int start, int end) {
List<TreeNode> res = new ArrayList<>();
if (start > end) {
res.add(null);
return res;
}
for (int val = start; val <= end; val++) {
List<TreeNode> left = helper(start, val - 1);
List<TreeNode> right = helper(val + 1, end);
for (TreeNode l : left) {
for (TreeNode r : right) {
TreeNode root = new TreeNode(val);
root.left = l;
root.right = r;
res.add(root);
}
}
}
return res;
}
647:回文子串
最开始看到这一题时想到了第五题:最长回文子串,然后想到了Manacher(马拉车)算法,马拉车的数组P[]既然可以求出最长回文子串,那么就能求出回文子串的个数:
//此方法对字符串进行加工
public static String preProcess(String s) {
StringBuilder sb = new StringBuilder(s.length()*2+3);
sb.append("^");
for (int i = 0; i < s.length(); i++) {
sb.append("#").append(s.charAt(i));
}
sb.append("#$");
return sb.toString();
}
// 马拉车算法
public static int countSubstrings(String s) {
String T = preProcess(s);
// System.out.println(Arrays.toString(T.toCharArray()));
int n = T.length();
int[] P = new int[n];
int C = 0, R = 0;
for (int i = 1; i < n - 1; i++) {
int i_mirror = 2 * C - i;
if (R > i) {
P[i] = Math.min(R - i, P[i_mirror]);// 防止超出 R
} else {
P[i] = 0;// 等于 R 的情况
}
// 碰到之前讲的三种情况时候,需要继续扩展
while (T.charAt(i + 1 + P[i]) == T.charAt(i - 1 - P[i])) {
P[i]++;
}
// 判断是否需要更新 R
if (i + P[i] > R) {
C = i;
R = i + P[i];
}
}
//此时P[]数组已经求出,根据该数组可以获得回文子串的个数
int sum = 0;
for (int i = 1; i < P.length - 1; i++) {
if (i % 2 == 0) {
sum += (P[i] + 1) / 2;
} else {
sum += P[i] / 2;
}
}
// System.out.println(Arrays.toString(P));
return sum;
}
结果一看评论全都是用的两边扫描……我就纳闷了,做第五题的时候都在马拉车,就我两边扫描,结果到这题了都是两边扫描就我马拉车,难道我思维比较奇葩?
贴个中心扫描的答案:
public int countSubstrings2(String s) {
for (int i=0; i < s.length(); i++){
count(s, i, i);//回文串长度为奇数
count(s, i, i+1);//回文串长度为偶数
}
return num;
}
public void count(String s, int start, int end){
while(start >= 0 && end < s.length() && s.charAt(start) == s.charAt(end)){
num++;
start--;
end++;
}
}
┓(;´_`)┏
LeetCode做题笔记之动态规划的更多相关文章
- C语言程序设计做题笔记之C语言基础知识(下)
C 语言是一种功能强大.简洁的计算机语言,通过它可以编写程序,指挥计算机完成指定的任务.我们可以利用C语言创建程序(即一组指令),并让计算机依指令行 事.并且C是相当灵活的,用于执行计算机程序能完成的 ...
- C语言程序设计做题笔记之C语言基础知识(上)
C语言是一种功能强大.简洁的计算机语言,通过它可以编写程序,指挥计算机完成指定的任务.我们可以利用C语言创建程序(即一组指令),并让计算机依指令行事.并且C是相当灵活的,用于执行计算机程序能完成的几乎 ...
- SDOI2017 R1做题笔记
SDOI2017 R1做题笔记 梦想还是要有的,万一哪天就做完了呢? 也就是说现在还没做完. 哈哈哈我竟然做完了-2019.3.29 20:30
- SDOI2014 R1做题笔记
SDOI2014 R1做题笔记 经过很久很久的时间,shzr又做完了SDOI2014一轮的题目. 但是我不想写做题笔记(
- SDOI2016 R1做题笔记
SDOI2016 R1做题笔记 经过很久很久的时间,shzr终于做完了SDOI2016一轮的题目. 其实没想到竟然是2016年的题目先做完,因为14年的六个题很早就做了四个了,但是后两个有点开不动.. ...
- LCT做题笔记
最近几天打算认真复习LCT,毕竟以前只会板子.正好也可以学点新的用法,这里就用来写做题笔记吧.这个分类比较混乱,主要看感觉,不一定对: 维护森林的LCT 就是最普通,最一般那种的LCT啦.这类题目往往 ...
- java做题笔记
java做题笔记 1. 初始化过程是这样的: 1.首先,初始化父类中的静态成员变量和静态代码块,按照在程序中出现的顺序初始化: 2.然后,初始化子类中的静态成员变量和静态代码块,按照在程序中出现的顺序 ...
- SAM 做题笔记(各种技巧,持续更新,SA)
SAM 感性瞎扯. 这里是 SAM 做题笔记. 本来是在一篇随笔里面,然后 Latex 太多加载不过来就分成了两篇. 标 * 的是推荐一做的题目. trick 是我总结的技巧. I. P3804 [模 ...
- LeetCode刷题笔记和想法(C++)
主要用于记录在LeetCode刷题的过程中学习到的一些思想和自己的想法,希望通过leetcode提升自己的编程素养 :p 高效leetcode刷题小诀窍(这只是目前对我自己而言的小方法,之后会根据自己 ...
随机推荐
- chromedriver版本问题
最新的chromedriver 66.0.3359.117 的对应chromedriver版本为2.38 http://npm.taobao.org/mirrors/chromedriver/ Web ...
- 深入理解JVM Note
第2章 Java内存区域与内存溢出异常 运行时数据区域 在虚拟机有栈.堆和方法区. 线程共享的:堆.方法区 不共享的:栈.程序计数器(代码执行的行号) 程序计数器(Program Counter Re ...
- jmeter简单压测、下载文件
一.jmeter做简单压测(单机) 1.添加需要压测的HTTP请求 2.添加聚合报告 3.设置压测场景 4.查看聚合报告 二.多机同时进行压测 1.在需要连接的电脑上打开jmeter bin目录下的 ...
- 用QEMU模拟运行uboot从SD卡启动Linux
平台:Qemu + vexpress-a9 u-boot:u-boot-2019.10 Linux:linux-4.14.13 之前介绍过用Qemu模拟运行uboot,然后从网络启动lin ...
- 【剑指Offer】面试题32 - I. 从上到下打印二叉树
题目 从上到下打印出二叉树的每个节点,同一层的节点按照从左到右的顺序打印. 例如: 给定二叉树: [3,9,20,null,null,15,7], 3 / \ 9 20 / \ 15 7 返回: [3 ...
- 51nod 1423:最大二“货”
1423 最大二"货" 题目来源: CodeForces 基准时间限制:1 秒 空间限制:131072 KB 分值: 80 难度:5级算法题 收藏 取消关注 白克喜欢找一个序列 ...
- ubuntu下pip的安装、升级和使用
系统虽然自带了不同版本的python,但都没有安装pip,pyhton2.7下使用的是pip2,python3.5下使用的是pip3.下面是各自安装命令. 安装 pip2: sudo apt-get ...
- HTML的文档结构与语法(二)
3.7 超链接标记 语法:<a 属性=“值”>对当前链接的描述</a> 作用:网页进行跳转 常用的属性: Href:链接的网址或ip或地址 值:就是具体的地址 T ...
- 小程序开发顶部TAB栏和侧边分类点击
先上一个效果图: 根据这个效果图我来说内容. 首先是顶部tab栏 效果实现依靠的是一个组件scroll-view.这个组件很有意思,可以多层嵌套,当然它的属性也很多. 这里主要用的是scroll-x, ...
- JAVA-数据类型-复习
JAVA-数据类型-复习 Java中,一共有8种数据类型,4种整型,2种浮点型,1种用于表示Unicode编码的字符单元的字符类型char,1种布尔类型. 整型 类型 存储需求(字节)一个字节包含8个 ...