递归
爬楼梯
https://leetcode.com/problems/climbing-stairs/
package codingTest2;
//1.假设当有n个台阶时假设有f(n)种走法。
//2.最后一步要么跨1个台阶要么跨2个台阶。
//3.当最后一步跨1个台阶时即之前有n-1个台阶,根据1的假设即n-1个台阶有f(n-1)种走法。
//4. 当最后一步跨2个台阶时即之前有n-2个台阶,根据1的假设即n-2个台阶有f(n-2 )种走法。
//5.显然n个台阶的走法等于前两种情况的走法之和即f(n)=f(n-1)+f(n-2)。
//6.找出递推公式后要找公式出口,即当n为1、2时的情况,显然n=1时f(1)等于1,f(2)等于2
//7. | 1, (n=1)
//f(n) = |2, (n=2)
// | f(n-1)+f(n-2) ,(n>2,n为整数)
public class ClimbStairs {
//递归版
public static int ClimbStairs(int n) {
if(n == 1) {
return 1;
}if(n == 2) {
return 2;
}else {
return ClimbStairs(n-1) + ClimbStairs(n-2);
}
}
//循环版本
// public static int ClimbStairs(int n) {
// if(n == 1) {
// return 1;
// }
// if(n == 2) {
// return 2;
// }
//
// int first = 1;
// int second = 2;
// int third = 0;
// for(int i = 3; i <=n; i++) {
// third = first + second;
// first = second;
// second = third;
// }
// return third;
// }
public static void main(String[] args) {
System.out.println(ClimbStairs(1));
System.out.println("------------");
System.out.println(ClimbStairs(2));
System.out.println(ClimbStairs(3));
System.out.println(ClimbStairs(4));
}
}
买卖股票的最佳时期
https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock/comments/
class Solution {
public int maxProfit(int[] prices) {
int low=0;
int high=1;
int result=0;
while(low<high&&high<prices.length)
{
while(high<prices.length)
{
if(prices[high]-prices[low]>result)
{
result=prices[high]-prices[low];
}
high++;
}
low++;
high=low+1;
}
return result;
}
}
Minimum Path Sum(最小路径和)
题目链接:
https://leetcode-cn.com/problems/minimum-path-sum/comments/
方法一:递归
假设当前出发位置就是最右下角的位置,那么经过的最短路径就是最右下角的格子的值;
假设在最后一行格子中,即grid[grid.length-1][j] ,那么从这个点出发到最右下角的最小路径就只能往右走;
假设在最后一列格子中,即grid[i][grid.length-1],那么从这个点出发到最右下角的最小路径和就只能往下走;
假设就在普通的一个位置,既可以往下走又可以往右走:
如果选择往右走,最短路径:往右走的最短路径和 + 我现在自身的值;
如果选择往下走,最短路径:往下走的最短路径和 + 我现在自身的值。
因此,从该点出发到右下角的最小路径值:从以上往左、往下两个中选出最小值 + 我现在自身的值。
package codingTest7;
public class minPath {
/*
* 一个二维数组,里面都是正数,要求从左上到右下,每一步只能向右或者向下。
* 沿途经过的数字要累加起来。返回最小路径和。
*
* */
public static int walk(int[][] matrix ,int i, int j) {
if(i == matrix.length-1 && j == matrix[0].length-1) {
//如果当前已经到达最右下角的点
return matrix[i][j];//直接返回当前点的值
}
if(i == matrix.length - 1) {
return matrix[i][j] + walk(matrix, i, j+1);//到这行的最后一个位置,只能往下走
}
if(j == matrix[0].length - 1) {
return matrix[i][j] + walk(matrix, i+1, j);//到这一列的最后一个位置,只能往右走
}
int right = walk(matrix, i, j+1);//right -> 右边位置到右下角的最短路径和
int down = walk(matrix, i+1, j);//down -> 下边位置到右下角的最短路径和
return matrix[i][j] + Math.min(right, down);
}
public static void main(String[] args) {
int[][] m = {{1, 3, 5, 9},{8, 1, 3, 4},{5, 0, 6, 1},{8, 8, 4, 0}};
System.out.println(walk(m, 0, 0));
}
}
该方法属于暴力枚举,它的复杂度很高!
f(0,0) 会调用 f(0,1),f(1,0) 这两个过程。
f(0,1) 是从该位置走到最右下角的路径和;f(1,0)是从该位置走到最右下角的路径和。
f(0,1)又需要f(1,1),f(0,2)这两个状态;同理,f(1,0)需要f(1,1),f(2,0)这两个状态。
但是可以发现这俩个中的f(1,1)重复了!即就是说他会整棵树都重新算一遍,里面会出现很多重复的状态,代价是很高的!
方法二、动态规划
(无后效性问题)当我们发现递归中有重复状态的时候,而且重复状态与它到达的路径无关的时候,那么就一定可以改写成动态规划。如果参数确定,那么最后的结果一定确定。
(有后效性问题)比如汉诺塔问题,之前的选择会影响后续的解。
由暴力递归解法改写为动态规划;分析可变参数(可以代表返回值的状态)
我们设定两个可变参数i与j,将i遍历所有的行号,将j遍历所有的列号,那么,它们的所有情况都装在一个二维表里。
对于该问题,设置最后一行 /最后一列 /普遍的位置。
回溯
利用回溯算法求解八皇后问题
利用回溯算法求解 0-1 背包问题
分治
利用分治算法求一组数据的逆序对个数
动态规划 0-1 背包问题
最小路径和(详细可看 Minimum Path Sum)
编程实现莱文斯坦最短编辑距离
编程实现查找两个字符串的最长公共子序列
编程实现一个数据序列的最长递增子序列
对应的 LeetCode 练习题
实战递归:完成Leetcode上的Letter Combinations of a Phone Number(17)及permutations(46) (保留往期第六天任务)
实战DP:完成0-1背包问题实现(自我实现)及Leetcode上Palindrome Partitioning II(132) (保留往期第七天任务)
Regular Expression Matching(正则表达式匹配)
Coin Change (零钱兑换)
Best Time to Buy and Sell Stock(买卖股票的最佳时机)
Maximum Product Subarray(乘积最大子序列)
Triangle(三角形最小路径和)