数据结构与算法笔记七(暴力递归到动态规划)

暴力递归到动态规划
摘要由CSDN通过智能技术生成

暴力递归到动态规划

阶段:

尝试,递归 --》 记忆化搜索,DP --》 严格表结构,DP --》 严格表精版

某些问题上,记忆化搜索 和 严格表结构 用同样的时间复杂度。

机器人运动问题

一个整数n代表 你有n个位置,
一个整数s代表 开始的位置, 1到n之间。
一个整数e 代表 代表要去的 目标位置
一个整数k 代表 机器人必须走k步

走的规则: 1位置只能走向2, n位置下一步只能走向n-1

问: 走k步,从s到e有多少种方法?

在这里插入图片描述展开表示:
在这里插入图片描述
暴力递归:

public static int ways1(int N, int M, int K, int P) {
   
		// 参数无效直接返回0
		if (N < 2 || K < 1 || M < 1 || M > N || P < 1 || P > N) {
   
			return 0;
		}
		// 总共N个位置,从M点出发,还剩K步,返回最终能达到P的方法数
		return walk(N, M, K, P);
	}

	// N : 位置为1 ~ N,固定参数
	// cur : 当前在cur位置,可变参数
	// rest : 还剩res步没有走,可变参数
	// P : 最终目标位置是P,固定参数
	// 该函数的含义:只能在1~N这些位置上移动,当前在cur位置,走完rest步之后,停在P位置的方法数作为返回值返回
	public static int walk(int N, int cur, int rest, int P) {
   
		// 如果没有剩余步数了,当前的cur位置就是最后的位置
		// 如果最后的位置停在P上,那么之前做的移动是有效的
		// 如果最后的位置没在P上,那么之前做的移动是无效的
		if (rest == 0) {
   
			return cur == P ? 1 : 0;
		}
		// 如果还有rest步要走,而当前的cur位置在1位置上,那么当前这步只能从1走向2
		// 后续的过程就是,来到2位置上,还剩rest-1步要走
		if (cur == 1) {
   
			return walk(N, 2, rest - 1, P);
		}
		// 如果还有rest步要走,而当前的cur位置在N位置上,那么当前这步只能从N走向N-1
		// 后续的过程就是,来到N-1位置上,还剩rest-1步要走
		if (cur == N) {
   
			return walk(N, N - 1, rest - 1, P);
		}
		// 如果还有rest步要走,而当前的cur位置在中间位置上,那么当前这步可以走向左,也可以走向右
		// 走向左之后,后续的过程就是,来到cur-1位置上,还剩rest-1步要走
		// 走向右之后,后续的过程就是,来到cur+1位置上,还剩rest-1步要走
		// 走向左、走向右是截然不同的方法,所以总方法数要都算上
		return walk(N, cur + 1, rest - 1, P) + walk(N, cur - 1, rest - 1, P);
	}

第一步优化: 记忆化搜索,就加了缓存

第二步优化: 动态规划,纠结位置依赖顺序
严格表结构的动态规划。
时间复杂度:

在这里插入图片描述

硬币问题

leetcode322
给你一个正数数组,里面每一个值,代表一枚硬币的面值。
一个数代表一枚硬币。

aim = 10.
组成这个10,最少用多少硬币。 7 + 3

在这里插入图片描述

递归:

package com.wanghaha.algorithm;

public class Day8_03_62CoinsMin {

    public static int minCoins1(int[] arr, int aim){
        process(arr, 0, aim);
    }

    // arr[index..]组成出rest这么多钱,最少的硬币数量返回
    public static int process(int[] arr, int index, int rest){
        if(rest < 0){
            return -1;
        }
        if( rest == 0 ){
            return 0;
        }
        // rest > 0
        if(index == arr.length ){
            return -1;
        }
        // rest > 0 and  也有硬币
        int p1 = process(arr, index +1 , rest);
        int p2Next = process(arr, index + 1 , rest - arr[index]);
        if(p1 == -1 && p2Next == -1){
            return -1;
        }else {
            if(p1 == -1){
                return p2Next + 1 ;
            }
            if(p2Next == -1 ){
                return p1;
            }
        }
        return Math.min(p1, p2Next);
    }
}

记忆化搜索

    public static int minCoins2(int[] arr, int aim){
   
        int[][] dp = new int[arr.length  +1 ][aim + 1];

        for (int i = 0; i < arr.length + 1; i++) {
   
            for (int j = 0; j < aim + 1; j++) {
   
                dp[i][j] = -2;
            }
        }
        return process2(arr, 0, aim, dp);
    }

    // arr[index..]组成出rest这么多钱,最少的硬币数量返回
    public static int process2(int[] arr, int index, int rest,int[][] dp){
   
        if(rest < 0){
   
            return -1;
        }
        if(dp [index][rest] != -2 ){
   
            return dp[index][rest];
        }

        if( rest == 0 ){
   
            dp[index][rest] = 0;
        }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值