您的位置:首页 > 产品设计 > UI/UE

leetcode做题总结,动态规划I(Triangle,Unique PathsI/II,Minimum Path Sum,Climbing Stairs,Jump Game,Word Break)

2014-08-23 12:26 435 查看
主要是动态规划的前两类,数组和序列。需要想到dp的题目如1.找最大最小值 2.xxx是否可行?3.计算所有可行解的数量。

数组类常见题型包括最短路径,可能路径数;

序列类常见题型:不同步长前进能否到达,几种组合。序列的不同分割方式。

解法:1.分析 2.用方程表示解,通常为递归如f(n)=min{f(n-1)+1,f(n-2)+1} 3. 创建储存数组,对初始值如f(0)赋值。4.对数组依次计算赋值 5.解通常为数组最后的值如f(s.length)

1. Triangle 这道题是一个三角形二维数组找出连接上下的最小节点路径。典型的dp,每个点都可以有两条路到达,比较两边然后递归。第一步分析,做法是从下往上算,用一个和最后一行一样大的数组存储中间结果。第二步写出公式:f(n)=value(n)+min{f(n),f(n+1)} 第三步就是写代码,先对初始数组赋值,然后用循环不断向上走。

public int minimumTotal(List<List<Integer>> triangle) {
int num = triangle.size();
int[] min = new int[triangle.get(num-1).size()];
for(int i=0;i<min.length;i++){
min[i]=triangle.get(num-1).get(i);
}
for(int i=num-2;i>-1;i--){
for(int j=0;j<triangle.get(i).size();j++){
min[j]=triangle.get(i).get(j)+Math.min(min[j],min[j+1]);
}

}
return min[0];
}


Update 2015/08/26: 上面的代码思路正确但是太教条,实际上根本不用创建新的数组,直接使用原本的list记录改变即可。

public class Solution {
/**
* @param triangle: a list of lists of integers.
* @return: An integer, minimum path sum.
*/
public int minimumTotal(ArrayList<ArrayList<Integer>> triangle) {
// write your code here
int num = triangle.size();
if (num == 0)
return 0;
for (int i = num - 2; i >= 0; i--){
ArrayList<Integer> current = triangle.get(i);
ArrayList<Integer> next = triangle.get(i + 1);
for (int j = 0; j < current.size(); j++){
current.set(j, current.get(j) +
Math.min(next.get(j), next.get(j + 1)));
}
}
return triangle.get(0).get(0);
}
}


2.unique paths I/II

第一题是问有多少条唯一路径,这需要建立一个和矩阵一样大的数组,存储到达每个节点的路径数,第二题是添加了障碍,这个不影响,遇到障碍时把该点的路径数清零即可

public int uniquePaths(int m, int n) {
if(m==0||n==0)return 1;
int[][] pa = new int[m]
;

for(int i=0;i<m;i++){
for(int j=0;j<n;j++){
if(i==0&&j==0)pa[0][0]=1;
else if(i==0) pa[i][j]=pa[i][j-1];
else if(j==0) pa[i][j]=pa[i-1][j];
else pa[i][j]=pa[i][j-1]+pa[i-1][j];
}
}
return pa[m-1][n-1];
}


public int uniquePathsWithObstacles(int[][] obstacleGrid) {
int m=obstacleGrid.length;
int n=obstacleGrid[0].length;
if(m==0||n==0)return 1;
int[][] pa = new int[m]
;

for(int i=0;i<m;i++){
for(int j=0;j<n;j++){
if(i==0&&j==0)pa[0][0]=1;
else if(i==0) pa[i][j]=pa[i][j-1];
else if(j==0) pa[i][j]=pa[i-1][j];
else pa[i][j]=pa[i][j-1]+pa[i-1][j];
if(obstacleGrid[i][j]==1) pa[i][j]=0;
}
}
return pa[m-1][n-1];
}


update 08/04/2015: 这两道题有个更好的方法可以只用一维数组即可

update 08/26/2015: 又看了一下这道题,首先I中的res[0] = 1可以删去,没有意义。这两道题的思路都是用一维数组,在每次计算res[j]时,里面记录的正好的是正上方的值。

public class Solution {
/**
* @param n, m: positive integer (1 <= n ,m <= 100)
* @return an integer
*/
public int uniquePaths(int m, int n) {
// write your code here
int[] res = new int
;
for (int i = 0; i < n; i++){
res[i] = 1;
}
for (int i = 1; i < m; i++){
res[0] = 1;
for (int j = 1; j < n; j++){
res[j] = res[j] + res[j-1];
}
}
return res[n-1];
}
}


public class Solution {
/**
* @param obstacleGrid: A list of lists of integers
* @return: An integer
*/
public int uniquePathsWithObstacles(int[][] obstacleGrid) {
// write your code here
int[] res = new int[obstacleGrid[0].length];
for (int i = 0; i < obstacleGrid[0].length; i++){
if (obstacleGrid[0][i] != 1){
res[i] = 1;
}else{
while (i < obstacleGrid[0].length){
res[i] = 0;
i++;
}
break;
}
}
for (int i = 1; i < obstacleGrid.length; i++){
if (obstacleGrid[i][0] != 1 && res[0] != 0){
res[0] = 1;
}else{
res[0] = 0;
}
for (int j = 1; j < obstacleGrid[0].length; j++){
if (obstacleGrid[i][j] != 1){
res[j] = res[j] + res[j-1];
}else{
res[j] = 0;
}
}
}
return res[obstacleGrid[0].length-1];
}
}


3.minimal path sum

这道题是上面两题的集合

public int minPathSum(int[][] grid) {
int m=grid.length;
int n=grid[0].length;
if(m==0||n==0)return 1;
int[][] pa = new int[m]
;

for(int i=0;i<m;i++){
for(int j=0;j<n;j++){
if(i==0&&j==0)pa[0][0]=grid[0][0];
else if(i==0) pa[i][j]=grid[i][j]+pa[i][j-1];
else if(j==0) pa[i][j]=grid[i][j]+pa[i-1][j];
else pa[i][j]=grid[i][j]+Math.min(pa[i][j-1],pa[i-1][j]);

}
}
return pa[m-1][n-1];
}


Update 2015/08/26:下面是一维数组版解法。对于这种方格题,二维数组的思路是对于[0][0]以及第一行和第一列单独处理,而一维数组的思路是先通过第一行初始化数组,然后计算之后每一行,但是在每次处理行的时候都要单独计算第一个元素的值

public class Solution {
/**
* @param grid: a list of lists of integers.
* @return: An integer, minimizes the sum of all numbers along its path
*/
public int minPathSum(int[][] grid) {
// write your code here
int[] res = new int[grid[0].length];
res[0] = grid[0][0];
for (int i = 1; i < res.length; i++){
res[i] = res[i - 1] + grid[0][i];
}
for (int i = 1; i < grid.length; i++){
res[0] = res[0] + grid[i][0];
for (int j = 1; j < res.length; j++){
res[j] = grid[i][j] + Math.min(res[j - 1], res[j]);
}
}
return res[res.length - 1];
}
}


4.climb stairs

上楼梯问题,每次可以一步或者两步求总共有多少种走法。

public int climbStairs(int n) {
if(n<2)return 1;
int[] bu = new int[n+1];
bu[0]=1;
bu[1]=1;
for(int i=2;i<=n;i++){
bu[i]=bu[i-1]+bu[i-2];
}
return bu
;
}


5.word break

用一唯数组存储这里之前的串是否为可分割的串,从前往后扫当前部分可分割在从这个节点判断后面的是否匹配,若是,设为true

public boolean wordBreak(String s, Set<String> dict) {
boolean[] sa = new boolean[s.length()+1];
sa[0]=true;
for(int i=0;i<s.length();i++){
if(!sa[i])continue;
for(String tmp:dict){
int len = tmp.length();
if(i+len>s.length()) continue;
if(s.substring(i,i+len).equals(tmp)) sa[i+len]=true;
}
}
return sa[s.length()];

}


Update 2015/08/26: 上面的题目在面试中遇到了,结果面试官要求用trie来做。

6.jump game

严格的说这道题并不是用dp的,虽然dp可以解但是效率太低。

public boolean canJump(int[] A) {
int max=0;
int tp;
for(int i=0;i<A.length;i++){
if(i>max) return false;
tp=i+A[i];
if(tp>max) max=tp;
}
return true;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: