赞
踩
题目描述:
“不同的路径” 的跟进问题:
有一个机器人位于一个 m×n 网格左上角。
机器人每一时刻只能向下或者向右移动一步。机器人试图达到网格的右下角。
现在考虑网格中有障碍物,那样将会有多少条不同的路径?
网格中的障碍和空位置分别用 1 和 0 来表示。
样例 1:
样例 2:
难点:
有障碍,情况分析要添加一种
思路:
public int uniquePathsWithObstacles(int[][] obstacleGrid) { int m = obstacleGrid.length; if (m == 0) return 0; int n = obstacleGrid[0].length; if (n == 0) return 0; int[][] f = new int[m][n]; int i, j; for (i = 0; i < m; i++) { for (j = 0; j < n; j++) { if (obstacleGrid[i][j] == 1) { f[i][j] = 0; }else { if (i == 0 && j == 0) { f[i][j] = 1; }else { //不能直接套用之前的方法,因为设有障碍,注意两题的差异 // if (i == 0 || j == 0) { // f[i][j] = 1; // }else { // f[i][j] = f[i-1][j] + f[i][j-1]; // } f[i][j] = 0; if (i-1 >= 0) { f[i][j] += f[i-1][j]; } if (j-1 >= 0){ f[i][j] += f[i][j-1]; } } } } } return f[m-1][n-1]; }
尝试使用滚动数组:
public int uniquePathsWithObstacles(int[][] obstacleGrid) { if (obstacleGrid == null || obstacleGrid.length == 0 || obstacleGrid[0].length == 0) { return 0; } int m = obstacleGrid.length; int n = obstacleGrid[0].length; int[][] f = new int[2][n]; int i, j; int old = 1, now = 0; for (i = 0; i < m; i++) { // 滚动数组 old = now; now = 1-now; for (j = 0; j < n; j++) { if (obstacleGrid[i][j] == 1) { f[now][j] = 0; }else { if (i == 0 && j == 0) { f[now][j] = 1; }else { f[now][j] = 0; if (i-1 >= 0) { f[now][j] += f[old][j]; } if (j-1 >= 0){ f[now][j] += f[now][j-1]; } } } } } return f[now][n-1]; }
收获:
题目之间有差异,不能套用模板,要具体问题具体分析
题目描述:
给定一个整数数组(下标从 0 到 n-1, n 表示整个数组的规模),请找出该数组中的最长上升连续子序列。(最长上升连续子序列可以定义为从右到左或从左到右的序列。
样例 1:
样例 2:
难点:
逐个遍历找连续上升序列
思路:
public class Solution { /** * @param a: An array of Integer * @return: an integer */ int result = 0; private void calc(int[] a, int n) { int[] f = new int[n]; int i; for (i = 0; i < n; i++) { // option 1 f[i] = 1; // option 2 if (i > 0 && a[i-1] < a[i]) { f[i] = f[i-1] + 1; } if (f[i] > result) { result = f[i]; } } } public int longestIncreasingContinuousSubsequence(int[] a) { int n = a.length; if (n == 0) return 0; calc(a, n); // 翻转数组,查看逆序是否存在更大的最大上升连续子序列 int i, j, t; for (i = 0, j = n-1; i < j; i++, j--) { t = a[i]; a[i] = a[j]; a[j] = t; } calc(a, n); return result; } }
优化空间复杂度为O(1)
private void calc(int[] a, int n) { int[] f = new int[2]; int i; int old, now = 0; for (i = 0; i < n; i++) { old = now; now = 1-now; // option 1 f[now] = 1; // option 2 if (i > 0 && a[i-1] < a[i]) { f[now] = f[old] + 1; } if (f[now] > result) { result = f[now]; } } }
收获:
题目描述:
给定一个只含非负整数的m∗n网格,找到一条从左上角到右下角的可以使数字和最小的路径。
样例 1:
样例 2:
路线是: 1 -> 3 -> 2
难点:
思路:
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) { if (grid == null || grid.length == 0 || grid[0].length == 0) { return 0; } int m = grid.length; int n = grid[0].length; int[][] f = new int[2][n]; int old = 1, now = 0; int i, j, t1, t2; for (i = 0; i < m; i++) { // 滚动数组 old = now; // old is row i - 1 now = 1-now; // now is row i for (j = 0; j < n; j++) { if (i == 0 && j == 0) { f[now][j] = grid[i][j]; continue; } f[now][j] = grid[i][j]; if (i > 0) { t1 = f[old][j]; }else { t1 = Integer.MAX_VALUE; } if (j > 0) { t2 = f[now][j-1]; //f[i][j-1] }else { t2 = Integer.MAX_VALUE; } if (t1 < t2) { f[now][j] += t1; }else { f[now][j] += t2; } } } return f[now][n-1]; } }
收获:
滚动数组
题目描述:
给定一个二维矩阵, 每一个格子可能是一堵墙 W,或者 一个敌人 E 或者空 0 (数字 ‘0’), 返回你可以用一个炸弹杀死的最大敌人数. 炸弹会杀死所有在同一行和同一列没有墙阻隔的敌人。 由于墙比较坚固,所以墙不会被摧毁.
样例1
样例2
难点:
思路:
public class Solution { /** * @param grid: Given a 2D grid, each cell is either 'W', 'E' or '0' * @return: an integer, the maximum enemies you can kill using one bomb */ public int maxKilledEnemies(char[][] grid) { if (grid == null || grid.length == 0 || grid[0].length == 0) { return 0; } int m = grid.length; int n = grid[0].length; int[][] f = new int[m][n]; int[][] res = new int[m][n]; int i, j; for (i = 0; i < m; i++) { for (j = 0; j < n; j++) { res[i][j] = 0; } } // up for (i = 0; i < m; i++) { for (j = 0; j < n; j++) { if (grid[i][j] == 'W') { f[i][j] = 0; }else { f[i][j] = 0; if (grid[i][j] == 'E') { f[i][j] = 1; } if (i-1 >= 0) { f[i][j] += f[i-1][j]; } } res[i][j] += f[i][j]; } } // down for (i = m-1; i >= 0; i--) { for (j = 0; j < n; j++) { if (grid[i][j] == 'W') { f[i][j] = 0; }else { f[i][j] = 0; if (grid[i][j] == 'E') { f[i][j] = 1; } if (i+1 < m) { f[i][j] += f[i+1][j]; } } res[i][j] += f[i][j]; } } // left for (i = 0; i < m; i++) { for (j = 0; j < n; j++) { if (grid[i][j] == 'W') { f[i][j] = 0; }else { f[i][j] = 0; if (grid[i][j] == 'E') { f[i][j] = 1; } if (j-1 >= 0) { f[i][j] += f[i][j-1]; } } res[i][j] += f[i][j]; } } // right for (i = 0; i < m; i++) { for (j = n-1; j >= 0; j--) { if (grid[i][j] == 'W') { f[i][j] = 0; }else { f[i][j] = 0; if (grid[i][j] == 'E') { f[i][j] = 1; } if (j+1 < n) { f[i][j] += f[i][j+1]; } } res[i][j] += f[i][j]; } } int result = 0; for (i = 0; i < m; i++) { for (j = 0; j < n; j++) { if (grid[i][j] == '0') { if (res[i][j] > result) { result = res[i][j]; } } } } return result; } }
题目描述:
这里有n个房子在一列直线上,现在我们需要给房屋染色,分别有红色蓝色和绿色。每个房屋染不同的颜色费用也不同,你需要设计一种染色方案使得相邻的房屋颜色不同,并且费用最小,返回最小的费用。
费用通过一个nx3 的矩阵给出,比如cost[0][0]表示房屋0染红色的费用,cost[1][2]表示房屋1染绿色的费用,依此类推。找到油漆所有房子的最低成本。
样例 1:
样例 2:
难点:
思路:
注意序列型动态规划和坐标型的差异。
实践的时候枚举不同情况即可。
public class Solution { /** * @param costs: n x 3 cost matrix * @return: An integer, the minimum cost to paint all houses */ public int minCost(int[][] costs) { int n = costs.length; if (n == 0) return 0; // n+1 f[0],...,f[n] int[][] f = new int[n+1][3]; int i, j, k, res; f[0][0] = f[0][1] = f[0][2] = 0; for (i = 1; i <= n; i++) { //j is the color of i-1 for (j = 0; j < 3; j++) { f[i][j] = Integer.MAX_VALUE; //k is the color of i-2 for (k = 0; k < 3; k++) { if (j == k) continue; if (f[i-1][k] + costs[i-1][j] < f[i][j]) { f[i][j] = f[i-1][k] + costs[i-1][j]; } } } } res = Math.min(Math.min(f[n][0], f[n][1]), f[n][2]); return res; } }
收获:
注意一下表述:这里前i个指的是,0…i-1,这i个
题目描述:
给出一个 非负 整数 num,对所有满足 0 ≤ i ≤ num 条件的数字 i 均需要计算其二进制表示中数字 1 的个数并以数组的形式返回。
样例1
样例2
public class Solution {
/**
* @param num: a non negative integer number
* @return: an array represent the number of 1's in their binary
*/
public int[] countBits(int num) {
int[] f = new int[num+1];
f[0] = 0;
for (int i = 1; i <= num; i++) {
f[i] = f[i >> 1] + (i % 2);
}
return f;
}
}
题目描述:
有一个消息包含A-Z通过以下规则编码
‘A’ -> 1
‘B’ -> 2
…
‘Z’ -> 26
现在给你一个加密过后的消息,问有几种解码的方式
样例 1:
输入: “12”
输出: 2
解释: 它可以被解码为 AB (1 2) 或 L (12).
样例 2:
输入: “10”
输出: 1
难点:
思路:
时间复杂度:O()
空间复杂度:O()
public class Solution { /** * @param s: a string, encoded message * @return: an integer, the number of ways decoding */ public int numDecodings(String s) { char[] chars = s.toCharArray(); int n = chars.length; if (n == 0) return 0; // n + 1 int[] f = new int[n+1]; f[0] = 1; for (int i = 1; i <= n; i++) { f[i] = 0; //倒数第一个数 int t = chars[i-1] - '0'; if (t >= 1 && t <= 9) { f[i] += f[i-1]; } // 必须要满足长度比1大 if (i >= 2) { // 倒数第二个数 t = chars[i-1] - '0' + (chars[i-2] - '0')*10; if (t >=10 && t <= 26) { f[i] += f[i-2]; } } } return f[n]; } }
收获:
对前i个的理解加深
在Java中,对于字符串的遍历,建议采用:
String.toCharArray()的方法
字符串—>字符数组
使用下标遍历更方便
不然每次都要调用String.charAt(i)这个方法
题目描述:
难点:
思路:
收获:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。