记忆化搜索
并不是所有递归都可以转化成记忆化搜索,记忆化搜索必须是出现完全重复的递归才可以,仅仅相似不可以转化成记忆化搜索
斐波那契数

题目解析:求第n个斐波那契数


java
//递归
class Solution {
public int fib(int n) {
return dfs(n);
}
public int dfs(int n){
if(n == 0 || n == 1){
return n;
}
return dfs(n-1) + dfs(n-2);
}
}
java
//记忆化搜索
class Solution {
int[] memory;
public int fib(int n) {
memory = new int[31];
//初始化这个备忘录
Arrays.fill(memory,-1);
return dfs(n);
}
public int dfs(int n){
//已经计算过,备忘录已经存过了,直接返回
if(memory[n] != -1){
return memory[n];
}
if(n == 0 || n == 1){
memory[n] = n;//将结果对应放入备忘录中
return n;
}
//返回之前将结果放入备忘录
memory[n] = dfs(n-1) + dfs(n-2);
return memory[n];
}
}
java
//动态规划
class Solution {
int[] dp = new int[31];//记忆化搜索
public int fib(int n) {
dp[0] = 0;
dp[1] = 1;
for(int i = 2;i <= n;i++){
dp[i] = dp[i-1] + dp[i-2];
}
return dp[n];
}
}
不同路径

题目解析 :从start位置到finish位置有多少路径可以走,每次只可以向下或向右走一步
解法一 :
直接递归 ,到第(m,n)位置等于 到第(m-1,n) + 到第(m,n-1),递归截止 m==0 || n == 0越界了 ,m = 1 && n=1 起始位置
dfs(m,n) = dfs(m-1,n) + dfs(m,n-1),但是时间超时了
解法二:记忆化搜索这里有重复计算一个位置的问题,可以使用记忆化搜索
int[m+1][n+1] memo每个位置表示(1,1)到这个位置的路径和
解法三:动态规划int[m+1][n+1] dp;先初始化dp[1][1] = 1,直接双重for循环遍历并且给数组对应值即可dp[i][j] = dp[i-1][j] + dp[i][j-1]


java
//记忆化搜索
class Solution {
public int uniquePaths(int m, int n) {
int[][] memo = new int[m+1][n+1];
return dfs(m,n,memo);
}
public int dfs(int m,int n,int[][] memo){
//看是否存过
if(memo[m][n] != 0){
return memo[m][n];
}
if(m == 0 || n == 0){
return 0;
}
if(m == 1 && n == 1){
memo[m][n] = 1;
return 1;
}
//更新meno
memo[m][n] = dfs(m-1,n,memo) + dfs(m,n-1,memo);
return memo[m][n];
}
}
java
//动态规划
class Solution {
public int uniquePaths(int m, int n) {
int[][] dp = new int[m+1][n+1];
dp[1][1] = 1;
for(int i = 1;i <= m;i++){
for(int j = 1;j <= n;j++){
//起始位置不需要进行初始化了
if(i == 1 && j == 1){
continue;
}
dp[i][j] = dp[i-1][j] + dp[i][j-1];
}
}
return dp[m][n];
}
}
最长递增自序列

题目解析 :找出一个最长递增自序列,不一定是连续的,但相对顺序是从前向后
解法一:递归以pos位置开始最长子序列 = 以pos+1位置开始 并且位置值大于 pos位置值开始最长子序列 + 1,但是时间超时
解法二:记忆化搜索和递归一样,因为这里有重复操作,使用一个memo,下标对应从那个位置开始最长子序列,递归前先看memo中是否有值,返回结果前,更新对应memo值
解法三:动态规划
以pos位置开始最长子序列,依赖从pos+1 ~ n 位置开始最长子序列 ,直接其基础上+1即可,因此可以先从后向前将其最长子序列进行赋值,下标对应的下标就是从那个位置开始最长子序列


java
class Solution {
int n;
int[] memo;
public int lengthOfLIS(int[] nums) {
n = nums.length;
memo = new int[n];
int ret = 0;
for (int i = 0; i < n; i++) {
ret = Math.max(ret, dfs(nums, i));
}
return ret;
}
public int dfs(int[] nums, int pos) {
if(memo[pos] != 0){
return memo[pos];
}
int tem = 1;
for (int i = pos + 1; i < nums.length; i++) {
if (nums[i] > nums[pos]) {
tem = Math.max(tem,dfs(nums,i)+1);
}
}
memo[pos] = tem;
return memo[pos];
}
}
java
class Solution {
public int lengthOfLIS(int[] nums) {
int n = nums.length;
int[] dp = new int[n];
int ret = 0;
Arrays.fill(dp,1);//先初始化为1
//从后向前
for(int i = n-1;i >= 0;i--){
for(int j = i+1;j < n;j++){
//从i+1位置开始后面,选那个数使其dp[i]最大
if(nums[j] > nums[i]){
dp[i] = Math.max(dp[i],dp[j]+1);
}
}
ret = Math.max(ret,dp[i]);
}
return ret;
}
}
猜数字大小||

题目解析: 每次猜错数字都会扣除猜的数字金额,给了一个n,可以选1~n中任意数进行猜测,求出最小金额数可以满足无论猜1到n那个数金额都够
思想 :[1,n]中任意选一个数分为两部分,找出左部分最小金额点x,找出右边部分最小金额点y,Math.max(x,y)这样两边都满足,找出以所有起点中最小的金额数即可记忆化搜索:可以使用一个二维数组,下标对应其区间,初始化为0


java
//记忆化搜索
class Solution {
int[][] memo;
public int getMoneyAmount(int n) {
memo = new int[n+1][n+1];
return dfs(1,n);
}
public int dfs(int left,int right){
//left == right此时只有一个值可以选,这个就是结果
//left > right越界了已经
if(left >= right){
return 0;
}
if(memo[left][right] != 0){
return memo[left][right];
}
int ret = Integer.MAX_VALUE;
for(int head = left ; head <= right;head++){
int x = dfs(left,head-1);
int y = dfs(head+1,right);
//x和y最大值,这样才可以无论选什么左右两边都可以猜出数字
//但是要从所有结果中选出最小金额可
ret = Math.min(Math.max(x,y)+head,ret);
}
memo[left][right] = ret;
return memo[left][right];
}
}
矩阵中的最长递增路径

题目解析 :找出最长递增路径,可以从任意位置作为起点
解法:记忆化搜索
找出以某个位置作为起点的最长路径,需要找其上下左右四个方向那个最长递增路径最长
ret = Math.max(ret,dfs(x,y) + 1)
返回以某个起点是最长路径长度

java
class Solution {
int m,n;
int[] dx = {1,-1,0,0};
int[] dy = {0,0,1,-1};
int[][] memo;
public int longestIncreasingPath(int[][] matrix) {
m = matrix.length;
n = matrix[0].length;
memo = new int[m][n];
int ret = 0;
for(int i = 0;i < m;i++){
for(int j = 0;j < n;j++){
ret = Math.max(ret,dfs(matrix,i,j));
}
}
return ret;
}
public int dfs(int[][] matrix,int i,int j){
if(memo[i][j] != 0){
return memo[i][j];
}
int ret = 1;
for(int k = 0;k < 4;k++){
int x = i + dx[k];
int y = j + dy[k];
if(x >= 0 && x < m && y >= 0 && y < n && matrix[x][y] > matrix[i][j]){
ret = Math.max(ret,dfs(matrix,x,y)+1);
}
}
memo[i][j] = ret;
return memo[i][j];
}
}