1. 零钱兑换
题目
class Solution {
public int coinChange(int[] coins, int amount) {
int n = coins.length;
int[] arr = new int[amount + 1];// 0..amount
// 定义初始条件
arr[0] = 0;
for(int i = 1; i <= amount; i++) {
// 求arr[i]
arr[i] = Integer.MAX_VALUE;
for(int j = 0; j < n; j++) {
if(i >= coins[j] && arr[i - coins[j]] != Integer.MAX_VALUE && arr[i - coins[j]] + 1 < arr[i]) {
arr[i] = arr[i - coins[j]] + 1;
}
}
}
if (arr[amount] == Integer.MAX_VALUE) {
return -1;
}else {
return arr[amount];
}
}
}
2. 不同路径-1
题目
分析:
动态规划第一步:确定状态
a. 最后一步: 无论机器人最后是如何到达终点的,最后一步只有两种情况,那就是从左到右和从上到下。设目标位置为[m - 1][n -1],则是从[m-2][n-1]和[m - 1][n - 2]过来的。
b. 子问题,原问题是从[0][0]到[m-1][n-1]转化为有多少种方式从[0][0]走到[m-2][n-1]和有多少种方式从从[0][0]走到[m-1][n-2]
动态规划第二步:状态转移方程
f[i][j] = f[i - 1][j] + f[i][j - 1]
动态规划第三步:初始条件和边界条件
初始条件:f[0][0] = 1
边界条件:i = 0或者j = 0的时候,只能从一个方向过来f[0][j] =1 f[i][0] = 1
动态规划第四步:计算顺序
计算第0行
计算第1行
。。。
计算第m - 1行
答案就是f[m - 1][n -1]
class Solution {
public int uniquePaths(int m, int n) {
int[][] arr = new int[m][n];
arr[0][0] = 1;
for(int i = 0; i < m; i++) {
for(int j = 0; j < n; j++) {
if (i == 0 || j == 0) {
arr[i][j] = 1;
}else{
arr[i][j] = arr[i][j - 1] + arr[i - 1][j];
}
}
}
return arr[m - 1][n - 1];
}
}
3. 不同路径-2
题目
分析:这个题和1的区别在于 障碍的地方f[i][j] = 0,然后就是边界条件中在最上边和最左边不再是直接等于1了,而是由它前面一个来决定!
动态规划第一步:确定状态
a. 最后一步: 无论机器人最后是如何到达终点的,最后一步只有两种情况,那就是从左到右和从上到下。设目标位置为[m - 1][n -1],则是从[m-2][n-1]和[m - 1][n - 2]过来的。
b. 子问题,原问题是从[0][0]到[m-1][n-1]转化为有多少种方式从[0][0]走到[m-2][n-1]和有多少种方式从从[0][0]走到[m-1][n-2]
动态规划第二步:状态转移方程
f[i][j] = f[i - 1][j] + f[i][j - 1]
动态规划第三步:初始条件和边界条件
初始条件:f[0][0] = 1
边界条件:i = 0或者 j = 0, f[i][j] = f[i ][j - 1]或者f[i - 1][j]
动态规划第四步:计算顺序
class Solution {
public int uniquePathsWithObstacles(int[][] obstacleGrid) {
int m = obstacleGrid.length;
int n = obstacleGrid[0].length;
int[][] arr = new int[m][n];
if(obstacleGrid[0][0] == 1 || obstacleGrid[m - 1][n - 1] == 1) {
return 0;
}else{
arr[0][0] = 1;
for(int i = 0; i < m; i++) {
for(int j = 0; j < n; j++) {
if(obstacleGrid[i][j] == 1) {
arr[i][j] = 0;
}else{
if(i == 0 && j == 0){
arr[i][j] = 1;
}else{
if(i == 0) {
arr[i][j] = arr[i][j - 1];
}
if(j == 0) {
arr[i][j] = arr[i - 1][j];
}
if(i != 0 && j != 0) {
arr[i][j] = arr[i - 1][j]+ arr[i][j - 1];
}
}
}
}
}
}
return arr[m - 1][n - 1];
}
}
4. 跳跃游戏
题目
分析:
动态规划第一步:确定状态
a. 最后一步: 无论怎么样到最后一步,都是前面的某一步直接跳过去的
b. 子问题,能成功跳到最后一步j位置是上一次跳成功了在i位置,并且i位置能跳的步数能够到j
动态规划第二步:状态转移方程
f[j] = or{i = 0到j-1}{f[i] && nums[i] > j - i}
动态规划第三步:初始条件和边界条件
初始条件:f[0]= true
边界条件:无
动态规划第四步:计算顺序
从小到大依次计算。
class Solution {
public boolean canJump(int[] nums) {
// f[j]是true的条件有两个
// 1. f[i] = true 2. nums[i] > j - i
if (nums == null || nums.length == 0) return false;
int n = nums.length;
boolean[] arr = new boolean[n+1];
arr[0] = true;
for(int i = 1; i < n; i++) {
arr[i] = false; // 这儿是个小细节
for(int j = 0; j < i; j++) {
if(arr[j] && nums[j] >= i - j) {
arr[i] = true;
break;
}
}
}
return arr[n - 1];
}
}
5. 粉刷房子
粉刷房子2请移步12题
题目
分析:
序列型动态规划:前i个最小/方式数/最小
序列➕状态
class Solution {
public int minCost(int[][] costs) {
int n = costs.length;// 房子的个数
int[][] arr = new int[3][n];
//arr[0][i] 代表第i栋房子是红色时,前i栋房子的最低价
// arr[1][i] 代表第i栋房子是蓝色时,前i栋房子的最低价
// arr[2][i] 代表第i栋房子是绿色时,前i栋房子的最低价
// 初始条件
for(int i = 0; i < 3; i++) {
arr[i][0] = costs[0][i];
}
for(int i = 1; i < n; i ++) {
arr[0][i] = arr[1][i - 1] > arr[2][i - 1] ? arr[2][i - 1] + costs[i][0]: arr[1][i - 1] + costs[i][0];
arr[1][i] = arr[0][i - 1] > arr[2][i - 1] ? arr[2][i - 1] + costs[i][1]: arr[0][i - 1] + costs[i][1];
arr[2][i] = arr[0][i - 1] > arr[1][i - 1] ? arr[1][i - 1] + costs[i][2]: arr[0][i - 1] + costs[i][2];
}
return getMin(arr[0][n - 1], arr[1][n - 1], arr[2][n - 1]);
}
public int getMin(int a, int b, int c) {
int temp = a>b?b:a;
return temp>c?c:temp;
}
}
6. 解码方法
题目
我的解法,非常啰嗦
class Solution {
public int numDecodings(String s) {
if(s == null || s.charAt(0) == '0') {
return 0;
}else if(s.length() == 1 && s.charAt(0) != '0' ) {
return 1;
}else{
int n = s.length();
int[] arr = new int[n];
arr[0] = 1;
if(s.charAt(0) == '1' && s.charAt(1) != '0') {
// 如果第一位是1或者2的话
arr[1] = 2;
}else if(s.charAt(0) == '2'&& Character.getNumericValue(s.charAt(1)) <= 6 && s.charAt(1) != '0') {
arr[1] = 2;
}else if(Character.getNumericValue(s.charAt(0))>= 3&& s.charAt(1) == '0') {
// arr[1] = 0;
return 0;
}else if(s.charAt(0) == '0'&& s.charAt(1) == '0') {
return 0;
}
else{
arr[1] = 1;
}
for(int i = 2; i < n; i++){
if(s.charAt(i - 1) == '1' && s.charAt(i) != '0') {
// 如果第一位是1或者2的话
arr[i] = arr[i - 1] + arr[i - 2];
}else if(Character.getNumericValue(s.charAt(i - 1))>= 3 && s.charAt(i) == '0') {
// arr[1] = 0;
return 0;
}else if(s.charAt(i - 1) == '0' && s.charAt(i) == '0') {
return 0;
}
else if(s.charAt(i - 1) == '2' && Character.getNumericValue(s.charAt(i)) <= 6 && s.charAt(i) != '0') {
arr[i] = arr[i - 1] + arr[i - 2];
}else if(s.charAt(i - 1) == '1' && s.charAt(i) == '0'){
arr[i] = arr[i - 2];
}else if (s.charAt(i - 1) == '2' && s.charAt(i) == '0'){
arr[i] = arr[i - 2];
}else{
arr[i] = arr[i - 1];
}
}
return arr[n - 1];
}
}
}
一个比较简洁并且具有技巧性的解法
class Solution {
public int numDecodings(String s) {
char[] ss = s.toCharArray();
int n = ss.length;
if (n == 0) {
return 0;
}
int[] arr = new int[n+1];
int m = ss[0] - '0';
arr[0] = 1;
for(int i = 1; i <= n; i++) {
arr[i] = 0;
int t = ss[i - 1] - '0';
if(t >= 1 && t <= 9){
arr[i] += arr[i - 1];
}
if(i >= 2) {
int q = ss[i - 2] - '0';
int p = ss[i - 1] - '0';
if(q * 10 + p >= 10 && q * 10 + p <= 26) {
arr[i] += arr[i - 2];// 学好加等
}
}
}
return arr[n];
}
}
7. 最长连续递增子序列
坐标型动态规划
题目
class Solution {
public int findLengthOfLCIS(int[] nums) {
int n = nums.length;
if(n == 0) {
return 0;
}else{
int[] arr = new int[n];
arr[0] = 1;
int m = 1;
for(int i = 1;i < n; i++) {
if(nums[i]> nums[i - 1]){
arr[i] = arr[i - 1] + 1;
}else{
arr[i] = 1;
}
if(m <= arr[i]){
m = arr[i];
}
}
return m;
}
}
}
8. 最小路径和
题目
class Solution {
public int minPathSum(int[][] grid) {
int m = grid.length;
int n = grid[0].length;
int[][] arr = new int[m][n];
arr[0][0] = grid[0][0];
for(int i = 1; i < m; i++) {
arr[i][0] = arr[i - 1][0] + grid[i][0];
}
for(int i = 1; i < n; i++) {
arr[0][i] = arr[0][i - 1] + grid[0][i];
}
for(int i = 1; i < m; i++) {
for(int j = 1; j < n; j++) {
arr[i][j] = arr[i - 1][j] < arr[i][j - 1] ? grid[i][j] + arr[i - 1][j]: grid[i][j] + arr[i][j - 1];
}
}
return arr[m - 1][n - 1];
}
}
9. 轰炸敌人
题目
public static int maxKillEnemies(char[][] A) {
if (A == null || A.length == 0 || A[0].length == 0) {
return 0;
}
int m = A.length;
int n = A[0].length;
int[][] f = new int[m][n];
int[][] res = new int[m][n];
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
res[i][j] = 0;
}
}
// up
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (A[i][j] == 'W') {
f[i][j] = 0;
}else {
f[i][j] = 0;
if (A[i][j] == 'E') {
f[i][j] = 1;
}
if (i > 0) {
f[i][j] += f[i - 1][j];
}
}
res[i][j] += f[i][j];
}
}
// down
for (int i = m - 1; i >= 0; i--) {
for (int j = n - 1; j >= 0; j--) {
if (A[i][j] == 'W') {
f[i][j] = 0;
}else {
f[i][j] = 0;
if (A[i][j] == 'E') {
f[i][j] = 1;
}
if (i < m - 1) {
f[i][j] += f[i + 1][j];
}
}
res[i][j] += f[i][j];
}
}
// left
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (A[i][j] == 'W') {
f[i][j] = 0;
}else {
f[i][j] = 0;
if (A[i][j] == 'E') {
f[i][j] = 1;
}
if (j > 0) {
f[i][j] += f[i][j - 1];
}
}
res[i][j] += f[i][j];
}
}
// right
for (int i = 0; i < m; i++) {
for (int j = n - 1; j >= 0; j--) {
if (A[i][j] == 'W') {
f[i][j] = 0;
}else {
f[i][j] = 0;
if (A[i][j] == 'E') {
f[i][j] = 1;
}
if (j < n - 1) {
f[i][j] += f[i][j + 1];
}
}
res[i][j] += f[i][j];
}
}
int result = Integer.MIN_VALUE;
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (A[i][j] == '0') {
result = result > res[i][j] ? result:res[i][j];
}
}
}
return result;
}
10.杨辉三角形
题目
class Solution {
public List<List<Integer>> generate(int numRows) {
List<List<Integer>> dp = new ArrayList<List<Integer>>();
List<Integer> tmp = new ArrayList<Integer>();
tmp.add(1);
dp.add(tmp);
if(numRows == 1) {
return dp;
}
List<Integer> tmp2 = new ArrayList<Integer>();
tmp2.add(1);
tmp2.add(1);
dp.add(tmp2);
if(numRows == 2) {
return dp;
}
for(int i = 2; i < numRows; i++) {
List<Integer> t = new ArrayList<Integer>();
t.add(1);
for(int j = 1; j < i; j++) {
t.add(dp.get(i - 1).get(j - 1) + dp.get(i - 1).get(j));
}
t.add(1);
dp.add(t);
}
return dp;
}
}
11. 比特位计数
题目
class Solution {
public int[] countBits(int n) {
if(n == 0) {
return new int[]{0};
}else{
int[] dp = new int[n + 1];
dp[0] = 0;
dp[1] = 1;
for(int i = 2; i <= n; i++) {
dp[i] = dp[i >> 1] + i % 2;
}
return dp;
}
}
}
12. 粉刷房子2
题目
class Solution {
public int minCostII(int[][] costs) {
int n = costs.length; // n个房子
int k = costs[0].length; // k种颜色
int[][] f = new int[n+1][k];
int min1, min2;
int j1 = 0;
int j2 = 0;
// dp[i][j] 油漆前i栋房子,并且i-1栋房子是j颜色的最小代价
for(int j = 0; j < k; j++) {
f[0][j] = 0;
}
for(int i = 1; i <= n; i++) {
//最小值和次小值
min1 = min2 = Integer.MAX_VALUE;
for(int j = 0; j < k; j++) {
if(f[i - 1][j] < min1) {
min2 = min1;
j2 = j1;
min1 = f[i - 1][j];
j1 = j;
}else{
if(f[i - 1][j] < min2) {
min2 = f[i - 1][j];
j2 = j;
}
}
}
for(int j = 0; j < k; j++) {
if(j == j1) {
f[i][j] = costs[i - 1][j] + min2;
}else{
f[i][j] = costs[i - 1][j] + min1;
}
}
}
int res = Integer.MAX_VALUE;
for(int i = 0; i < k; i++) {
res = res < f[n][i] ? res : f[n][i];
}
return res;
}
}
13. 房屋盗窃
题目
class Solution {
public int rob(int[] nums) {
int n = nums.length;
if(n == 1){
return nums[0];
}else if(n == 2){
return Math.max(nums[0], nums[1]);
}else{
int[] f = new int[n];
f[0] = nums[0];
f[1] = Math.max(nums[0], nums[1]);
for(int i = 2; i < n; i++) {
f[i] = f[i - 2] + nums[i] > f[i - 1] ? f[i - 2] + nums[i] : f[i - 1];
}
return f[n - 1];
}
}
}
14. 房屋盗窃2
题目
class Solution {
public int rob(int[] nums) {
int n = nums.length;
if (n == 1) {
return nums[0];
}else if(n == 2) {
return Math.max(nums[0], nums[1]);
}else if(n == 3){
return Math.max(nums[0], Math.max(nums[1], nums[2]));
}else{
int[][] f = new int[n][2];
f[0][0] = nums[0];
f[0][1] = 0;
f[1][0] = nums[0];
f[1][1] = nums[1];
f[2][0] = nums[0];
f[2][1] = Math.max(nums[1], nums[2]);
for(int i = 3; i < n; i++) {
f[i][0] = Math.max(f[i - 1][0], f[i - 2][0]+ nums[i - 1]);
f[i][1] = Math.max(f[i - 1][1], f[i - 2][1]+ nums[i]);
}
return Math.max(f[n - 1][0], f[n - 1][1]);
}
}
}
15. 股票的最大利润
题目
class Solution {
public int maxProfit(int[] prices) {
int n = prices.length;
if(n <= 1) {
return 0;
}else {
int[] dp = new int[n];
dp[0] = 0;
int tmp = prices[0];
for(int i = 1; i < n; i++) {
if(tmp > prices[i]){
tmp = prices[i];
}
if(prices[i] < prices[i - 1]){
dp[i] = dp[i - 1];
}else{
dp[i] = Math.max(prices[i] - tmp, dp[i - 1]);
}
}
return dp[n - 1];
}
}
}