动态规划

题目分类

一维dp

矩阵型DP

Unique Paths II : 矩阵型DP,求所有方法总数

方法一:自顶向下

递归法,time limited

class Solution {
int helper(int[][] g, int x, int y){
int top = 0, left = 0;
if(g[x][y] == 1) return 0; if(x == 0 && y == 0) return 1; if(x > 0){
top = helper(g, x - 1, y);
} if(y > 0){
left = helper(g, x, y - 1);
} return top + left;
}
public int uniquePathsWithObstacles(int[][] obstacleGrid) {
return helper(obstacleGrid, obstacleGrid.length - 1, obstacleGrid[0].length -1);
}
}

方法一:自顶向下

递归法 + memo ac

class Solution {
Map<Long, Integer> m = new HashMap<>(); int helper(int[][] g, int x, int y){
int top = 0, left = 0;
if(g[x][y] == 1) return 0; if(x == 0 && y == 0) return 1; long key = ((long)x) << 32 | y; // long key = x << 32 | y; 错误 if(m.containsKey(key)) return m.get(key); if(x > 0){
top = helper(g, x - 1, y);
} if(y > 0){
left = helper(g, x, y - 1);
} m.put(key, top + left);
return top + left;
}
public int uniquePathsWithObstacles(int[][] obstacleGrid) {
return helper(obstacleGrid, obstacleGrid.length - 1, obstacleGrid[0].length -1);
}
}

方法三:自底向上

递推 + memo

这里用了二维memo,其实状态转移中,当前step只与上一step有关系,只用一维memo就可以了。

class Solution {
public int uniquePathsWithObstacles(int[][] g) {
if(g.length == 0) return 0; int[][] ps = new int[g.length][g[0].length];
boolean obstacle = false; for(int i = 0; i < g.length; i ++){
if(g[i][0] == 1){
obstacle = true;
}
ps[i][0] = obstacle ? 0 : 1;
} obstacle = false;
for(int i = 0; i < g[0].length; i ++){
if(g[0][i] == 1){
obstacle = true;
}
ps[0][i] = obstacle ? 0 : 1;
} for(int i = 1; i < g.length; i++){ for(int j = 1; j < g[0].length; j++){
if(g[i][j] == 1){
ps[i][j] = 0;
}
else{
ps[i][j] = ps[i-1][j] + ps[i][j-1];
}
}
} return ps[g.length-1][g[0].length-1];
}
}

Minimum Path Sum:矩阵型,求最大最小值

方法一:自底向上 + 二维memo

class Solution {
public int minPathSum(int[][] g) {
if (g.length == 0) return 0; int[][] sum = new int[g.length][g[0].length];
sum[0][0] = g[0][0]; for(int i = 1; i < g.length; i++){
sum[i][0] = g[i][0] + sum[i-1][0];
} for(int i = 1; i < g[0].length; i++){
sum[0][i] = g[0][i] + sum[0][i-1];
} for(int i = 1; i < g.length; i ++){ for(int j = 1; j < g[0].length; j++){
sum[i][j] = g[i][j] + Math.min(sum[i-1][j], sum[i][j-1]);
}
} return sum[g.length-1][g[0].length-1];
}
}

方法二:自底向上 + 一维memo

class Solution {
public int minPathSum(int[][] g) {
if (g.length == 0) return 0; int[] sum = new int[g[0].length]; sum[0] = g[0][0];
for(int i = 1; i < g[0].length; i++){
sum[i] = g[0][i] + sum[i-1];
} for(int i = 1; i < g.length; i ++){
sum[0] = sum[0] + g[i][0]; for(int j = 1; j < g[0].length; j++){
sum[j] = g[i][j] + Math.min(sum[j], sum[j-1]);
}
} return sum[g[0].length-1];
}
}

Triangle : 矩阵型,求最小值

方法一 : 自定向下

递归 + memo

问题拆分、状态、状态转移方程、初始值,一个都不能少

class Solution {
Map<Long, Integer> m = new HashMap<>(); int helper(List<List<Integer>> tri, int row, int col){ long key = (long)row << 32 | col;
if(m.containsKey(key)){
return m.get(key);
} if ( row == 0 && col == 0 ){ //不能忽略此逻辑
return tri.get(0).get(0);
} int left = Integer.MAX_VALUE;
int top = Integer.MAX_VALUE;
if(row > 0){
if(col < tri.get(row).size() - 1){
top = helper(tri, row - 1, col);
} if(col > 0){
left = helper(tri, row - 1, col - 1);
}
} int val = Math.min(top, left) + tri.get(row).get(col);
m.put(key, val);
return val;
} public int minimumTotal(List<List<Integer>> tri) {
if(tri.size() == 0) return 0; int sum = Integer.MAX_VALUE;
for(int j = 0; j < tri.get(tri.size()-1).size(); j++){
sum = Math.min(sum, helper(tri, tri.size()-1, j));
} return sum;
}
}

方法二 : 自底向上

递推 + memo,下面的方法还可以进一步优化

class Solution {
public int minimumTotal(List<List<Integer>> tri) {
if(tri.size() == 0) return 0; int[] memo = new int[tri.get(tri.size()-1).size()];
memo[0] = tri.get(0).get(0); for(int i = 1; i < tri.size(); i ++){
for(int j = tri.get(i).size() -1; j >= 0 ; j--){
if(j == 0){
memo[j] = memo[j] + tri.get(i).get(j);
}
else if(j == tri.get(i).size() - 1){
memo[j] = memo[j-1] + tri.get(i).get(j);
}
else{
memo[j] = Math.min(memo[j-1], memo[j]) + tri.get(i).get(j);
}
}
} int sum = Integer.MAX_VALUE;
for(int i=0; i<memo.length; i++){
sum = Math.min(sum, memo[i]);
} return sum;
}
}

Maximum Square :矩阵型,求最大最小值

方法一:自底向上

递推 + memo

主要看斜对角线,当前位置能成为多大square,要看左上角位置有多大square。本地弯弯道道挺多。

class Solution {
public int maximalSquare(char[][] m) {
if(m.length == 0) return 0; int[][] memo = new int[m.length + 1][m[0].length + 1]; for(int i = 0; i <= m.length; i++ ){
memo[i][0] = 0;
} for(int i = 0; i <= m[0].length; i++){
memo[0][i] = 0;
} int maxi = 0; for(int i = 0; i < m.length; i++){ for(int j = 0; j < m[0].length; j++){
if(m[i][j] != '1'){
memo[i+1][j+1] = 0;
continue;
} if(memo[i][j] <= 0){
memo[i+1][j+1] = 1;
}
else {
int k = 1;
for(; k <= memo[i][j]; k++){
if(m[i-k][j] != '1' || m[i][j-k] != '1'){
break;
}
}
memo[i+1][j+1] = k;
}
//System.out.println("i" + i + " j" + j + " =" + memo[i+1][j+1]);
maxi = Math.max(memo[i+1][j+1], maxi);
}
} return maxi * maxi;
}
}

Range Sum Query 2D - Immutable

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

class NumMatrix {

    private int[][] memo;

    public NumMatrix(int[][] m) {
if(m.length == 0 || m[0].length == 0) return; memo = new int[m.length][m[0].length + 1]; for(int i = 0; i < m.length; i++){
for(int j = 0; j < m[0].length; j++){
memo[i][j+1] = memo[i][j] + m[i][j];
}
}
} public int sumRegion(int row1, int col1, int row2, int col2) {
int sum = 0;
for(int i = row1; i <= row2; i++){
sum += (memo[i][col2+1] - memo[i][col1]);
}
return sum;
}
}

leetcode动态规划笔记二的更多相关文章

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

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

  2. leetcode动态规划笔记三---单序列型

    单序列型DP 相比一维DP,这种类型状态转移与过去每个阶段的状态都有关. Longest Increasing Subsequence : 求最大最小值 Perfect Squares : 求某个规模 ...

  3. 快速上手leetcode动态规划题

    快速上手leetcode动态规划题 我现在是初学的状态,在此来记录我的刷题过程,便于以后复习巩固. 我leetcode从动态规划开始刷,语言用的java. 一.了解动态规划 我上网查了一下动态规划,了 ...

  4. 《CMake实践》笔记二:INSTALL/CMAKE_INSTALL_PREFIX

    <CMake实践>笔记一:PROJECT/MESSAGE/ADD_EXECUTABLE <CMake实践>笔记二:INSTALL/CMAKE_INSTALL_PREFIX &l ...

  5. jQuery源码笔记(二):定义了一些变量和函数 jQuery = function(){}

    笔记(二)也分为三部分: 一. 介绍: 注释说明:v2.0.3版本.Sizzle选择器.MIT软件许可注释中的#的信息索引.查询地址(英文版)匿名函数自执行:window参数及undefined参数意 ...

  6. Mastering Web Application Development with AngularJS 读书笔记(二)

    第一章笔记 (二) 一.scopes的层级和事件系统(the eventing system) 在层级中管理的scopes可以被用做事件总线.AngularJS 允许我们去传播已经命名的事件用一种有效 ...

  7. Python 学习笔记二

    笔记二 :print 以及基本文件操作 笔记一已取消置顶链接地址 http://www.cnblogs.com/dzzy/p/5140899.html 暑假只是快速过了一遍python ,现在起开始仔 ...

  8. WPF的Binding学习笔记(二)

    原文: http://www.cnblogs.com/pasoraku/archive/2012/10/25/2738428.htmlWPF的Binding学习笔记(二) 上次学了点点Binding的 ...

  9. webpy使用笔记(二) session/sessionid的使用

    webpy使用笔记(二) session的使用 webpy使用系列之session的使用,虽然工作中使用的是django,但是自己并不喜欢那种大而全的东西~什么都给你准备好了,自己好像一个机器人一样赶 ...

随机推荐

  1. 如何安全地使用redis的pop命令

    Redis的list经常被当作队列使用,左进右出,一般生产者使用lpush压入数据,消费者调用rpop取出数据. 这是很自然的行为,然而有时会发现lpush成功,但rpop并没有取到数据,特别是一些客 ...

  2. 服务器使用bbr加速配置

    服务器内核升级: 以centos7为例,配置之前可使用以下命令查看内核版本,若是4.0以上则无需对内核升级: uname -r 对内核升级的方法: 直接使用以下命令进行内核版本的下载: rpm --i ...

  3. K8s configMap原理介绍

    给容器内应用程序传递参数的实现方式: 1. 将配置文件直接打包到镜像中,但这种方式不推荐使用,因为修改配置不够灵活. 2. 通过定义Pod清单时,指定自定义命令行参数,即设定 args:[" ...

  4. Appium入门脚本

    没有用框架的代码实现登录功能: import time from selenium import webdriver # 创建字典 desired_caps = {} desired_caps['pl ...

  5. python 项目实战之装饰器

    import logging def use_logging(func): def writelog(*args, **kwargs): logging.warning("%s is run ...

  6. [原创]敏捷管理实践Scrum思维导图

    [原创]敏捷管理实践Scrum思维导图

  7. 【转】gdb typeid 详解

        在揭开typeid神秘面纱之前,我们先来了解一下RTTI(Run-Time Type Identification,运行时类型识别),它使程序能够获取由基指针或引用所指向的对象的实际派生类型, ...

  8. [BUAA软工]Alpha阶段测试报告

    测试报告 一.测试计划 1.1 功能测试 1.2 UI测试 1.3 测试中发现的bug https://github.com/bingduoduo1/backend/issues/21 https:/ ...

  9. 第08组 Beta冲刺(2/4)

    队名 八组评分了吗 组长博客链接(2分) 组员1李昕晖(组长) 过去两天完成了哪些任务 文字/口头描述 12月9号了解各个小组的进度与难以攻破的地方,晚上安排开会,安排新的冲刺任务. 重新分配小组及个 ...

  10. answer

    https://www.cnblogs.com/549294286/p/10451394.html 基于BIO实现的Server端,当建立了100个连接时,会有多少个线程?如果基于NIO,又会是多少个 ...