算法基础之暴力递归到动态规划

6.暴力递归转动态规划 动态规划 1.什么是动态规划? 动态规划就是暴力递归(回溯)的过程中有重复调用的过程,动态规划在算过每次调用后把答案记下来,下次再遇到重复过程直接调用这个行为就叫动态规划。 动态规划就是对有重复调用过程的暴力递归过程的优化。 例子:斐波那契数列f(n) = f(n - 1) + f(n - 2),f(1) = 1, f(2) = 1。求f(5) 可以看出求F(5)的过程中会有很多的重复调用(红色的为重复调用),这种重复过程会浪费大量的时间。 如果我们重复过程我们之前算过,我们给它记到一个表里去,如果下次再 阅读详情

一斐波那契数列:

public class Fibonacci {
    public static int f(int n) {
        if (n == 1) {
            return 1;
        }
        if (n == 2) {
            return 1;
        }
        return f(n - 1) + f(n - 2);
    }
}

中间存在大量的重复过程:可以缓存起来

    public static int dp(int n) {
        int[] dp = new int[n + 1];
        if (n == 1) {
            dp[1] = 1;
            return 1;
        }
        if (n == 2) {
            dp[2] = 1;
            return 1;
        }
        dp[n] = f(n - 1) + f(n - 2);
        return dp[n];
    }

题目二

假设有排成一行的N个位置,记为1~N,N一定大于或等于2

开始时机器人在其中的M位置上(M一定是1~N中的一个)

如果机器人来到1位置,那么下一步只能往右来到2位置;

如果机器人来到N位置,那么下一步只能往左来到N-1位置﹔

如果机器人来到中间位置,那么下一步可以往左走或者往右走;

规定机器人必须走K步,最终能来到P位置(P也是1~N中的一个)的方法有多少种

给定四个参数N、M、K、P,返回方法数。

递归方法:

package com.zh.class18;

public class RobotWalk {
    public static void main(String[] args) {
        System.out.println(ways(4, 2, 4, 4));
    }
    public static int ways(int N, int M, int K, int P) {
        if (N < 2 || M < 1 || M > N || P < 1 || P > N || K < 1) {
            return -1;
        }
        return process(M, K, P, N);
    }

    /**
     *
     * @param cur 当前的位置
     * @param rest 剩余的步数
     * @param aim 目标位置
     * @param N 所有的位置数目
     * @return 返回满足的数目
     */
    private static int process(int cur, int rest, int aim, int N) {
        if (rest == 0) {
            return cur == aim ? 1 : 0;
        }
        if (cur == 1) {
            return process(2, rest - 1, aim, N);
        }
        if (cur == N) {
            return process(N - 1, rest - 1, aim, N);
        }
        return process(cur - 1, rest - 1, aim, N) + process(cur + 1, rest - 1, aim, N);
    }
}

从递归中可以看出cur和rest是决定递归的key值,并且有重复过程,那么可以使用缓存的方法(即记忆化搜索):

cur的范围是1 ~ N,rest的范围是0 ~ K

package com.zh.class18;

public class RobotWalk {
    public static void main(String[] args) {
        System.out.println(ways(4, 2, 4, 4));
        System.out.println(ways1(4, 2, 4, 4));
    }
 

    public static int ways1(int N, int M, int K, int P) {
        if (N < 2 || M < 1 || M > N || P < 1 || P > N || K < 1) {
            return -1;
        }
        int[][] dp = new int[N + 1][K + 1];
        for (int i = 0; i <= N; i++) {
            for (int j = 0; j <= K; j++) {
                dp[i][j] = -1;
            }
        }
        return process1(M, K, P, N, dp);
    }

    /**
     *
     * @param cur 当前的位置 范围是1 ~ N
     * @param rest 剩余的步数 范围是0 ~ K
     * @param aim 目标位置
     * @param N 所有的位置数目
     * @return 返回满足的数目
     */
    private static int process1(int cur, int rest, int aim, int N, int[][] dp) {
        if (dp[cur][rest] != -1) {
            return dp[cur][rest];
        }
        int ans = 0;
        if (rest == 0) {
            ans =  cur == aim ? 1 : 0;
        } else if (cur == 1) {
            ans =  process1(2, rest - 1, aim, N, dp);
        } else if (cur == N) {
            ans = process1(N - 1, rest - 1, aim, N, dp);
        } else {
            ans = process1(cur - 1, rest - 1, aim, N, dp) + process1(cur + 1, rest - 1, aim, N, dp);
        }
        dp[cur][rest] = ans;
        return ans;
    }
}

再次优化为动态规划:

    public static int ways2(int N, int M, int K, int P) {
        if (N < 2 || M < 1 || M > N || P < 1 || P > N || K < 1) {
            return -1;
        }
        int[][] dp = new int[N + 1][K + 1];
        dp[P][0] = 1;
        for (int rest = 1; rest <= K; rest++) {
            dp[1][rest] = dp[2][rest - 1];

            for (int cur = 2; cur < N; cur++) {
                dp[cur][rest] = dp[cur - 1][rest - 1] + dp[cur + 1][rest - 1];
            }

            dp[N][rest] = dp[N - 1][rest - 1];
        }
        return dp[M][K];
    }

题目三:

给定一个整型数组arr,代表数值不同的纸牌排成一条线

玩家A和玩家B依次拿走每张纸牌

规定玩家A先拿,玩家B后拿,但是每个玩家每次只能拿走最左或最右的纸牌

玩家A和玩家B都绝顶聪明

请返回最后获胜者的分数。

暴力递归方法:

package com.zy.class002;

public class CardsInLine {
    public static void main(String[] args) {
        int[] arr = {5, 7, 4, 5, 8, 1, 6, 0, 3, 4, 6, 1, 7};
        System.out.println(win1(arr));
    }
    // 根据规则,返回获胜者的分数
    public static int win1(int[] arr) {
        if (arr == null || arr.length == 0) {
            return 0;
        }
        int first = first(arr, 0, arr.length - 1);
        int second = after(arr, 0, arr.length - 1);
        return Math.max(first, second);
    }

    // 先手获得的分数
    public static int first(int[] arr, int left, int right) {
        if (left == right) {
            return arr[left];
        }

        int p1 = arr[left] + after(arr, left + 1, right); // 对手拿走了left位置
        int p2 = arr[right] + after(arr, left, right - 1); // 对手拿走了right位置
        return Math.max(p1, p2);

    }

    // 后手获得最好的分数
    public static int after(int[] arr, int left, int right) {
        // 因为是后手,只能是0
        if (left == right) {
            return 0;
        }
        int p1 = first(arr, left + 1, right);
        int p2 = first(arr, left, right - 1);
        // 因为是后手,都是千年的护理,所以只能给你最小的
        return Math.min(p1, p2);
    }
}

 但是暴力递归是存在重复值的:因此可以使用缓存的方法来优化:

package com.zy.class002;

public class CardsInLine2 {
    public static void main(String[] args) {
        int[] arr = {5, 7, 4, 5, 8, 1, 6, 0, 3, 4, 6, 1, 7};
        System.out.println(win1(arr));
    }
    // 根据规则,返回获胜者的分数
    public static int win1(int[] arr) {
        if (arr == null || arr.length == 0) {
            return 0;
        }
        int len = arr.length;
        int[][] fdp = new int[len][len];
        int[][] adp = new int[len][len];
        for (int i = 0; i < len; i++) {
            for (int j = 0; j < len; j++) {
                fdp[i][j] = -1;
                adp[i][j] = -1;
            }
        }
        int first = first(arr, 0, arr.length - 1, fdp, adp);
        int second = after(arr, 0, arr.length - 1, fdp, adp);
        return Math.max(first, second);
    }

    // 先手获得的分数
    public static int first(int[] arr, int left, int right, int[][] fdp, int[][] adp) {
        if (fdp[left][right] != -1) {
            return fdp[left][right];
        }
        int ans = 0;
        if (left == right) {
            ans =  arr[left];
        } else {
            int p1 = arr[left] + after(arr, left + 1, right, fdp, adp); // 对手拿走了left位置
            int p2 = arr[right] + after(arr, left, right - 1, fdp, adp); // 对手拿走了right位置
            ans = Math.max(p1, p2);
        }
        fdp[left][right] = ans;
        return ans;
    }

    // 后手获得最好的分数
    public static int after(int[] arr, int left, int right, int[][] fdp, int[][] adp) {
        int ans = 0;
        if (left != right) {
            int p1 = first(arr, left + 1, right, fdp, adp);
            int p2 = first(arr, left, right - 1, fdp, adp);
            ans = Math.min(p1, p2);
        }
        // 因为是后手,都是千年的护理,所以只能给你最小的
        return ans;
    }
}

算法基础11-暴力递归思维、动态规划思维 文章目录1 暴力递归、动态规划1.1 暴力递归思维1.1.1 暴力递归下的尝试1.1.1.1 例一:汉诺塔问题1.1.1.2 例二:字符串子序列问题1.1.1.3 例四:字符串全排列问题1.1.1.4 例六:用递归逆序一个栈(考验脑回路)1.2 动态规划模型1.2.1 从左往右尝试模型1.2.1.1 数字字符转化问题1.2.1.2 背包价值问题1.2.2 范围上的尝试模型1.2.2.1 玩家抽取纸牌问题1.2.2.2 N皇后问题如何尝试一件事? 1 暴力递归、动态规划 1.1 暴力递归思维 暴力递归实质就是 阅读详情

相关推荐

LeetCode 70:爬楼梯|递归到动态规划全路径解析

通过 LeetCode 第 70 题“Climbing Stairs”,我们完整经历了从暴力递归到记忆化搜索,再到动态规划及空间优化的整个算法进阶路径。这道看似简单的题目,实际上蕴含了递归思想、状态转移、子问题重叠、空间压缩等一系列动态规划核心理念。掌握它,不仅有助于建立解决问题的框架思维,也为今后应对更复杂的 DP 问题打下基础。推荐进一步挑战的题目:LeetCode 198. 打家劫舍(带状态转移)LeetCode 746. 使用最小花费爬楼梯(与本题模型相近)

2301_79972360的博客 1476

【算法&数据结构体系篇class21】:暴力递归到动态规划

第0个和第1个能组成2,第1个和第2个能组成2,第0个和第2个能组成2。arr是面值数组,其中的值都是正数且没有重复。例如:arr = {1,2,1,1,2,1,2},aim = 4。arr是货币数组,其中的值都是正数。arr是货币数组,其中的值都是正数。例如:arr = {1,1,1},aim = 2。每个值都认为是一种面值,且认为张数是无限的。方法如下:1+1+1+1、1+1+2、2+2。即便是值相同的货币也认为每一张都是不同的,方法:1+1+1+1、1+1+2、2+2。每个值都认为是一张货币,

studyday1的博客 519

采用MPU6050的手势遥控器

随着社会的发展与进步,电子产品日益更新,个人家庭迎来了越来越多的智能家电。然而,现在的智能电子设备产品的遥控器多数都是按键形的。操作繁琐不直观,学习成本大。并且对于有老人小孩的家庭,给他们的操作带来了巨大的障碍。手势遥控器是指利用简单的手势来指挥电子设备,获得便捷的操作体验。让家庭成员都可以享受科技发展带来的福利。MPU6050是一个运动传感器,内置陀螺仪,再由电子设备利用判断结果做出相应的响应即...

Sakura的博客小站 6602

暴力递归

暴力递归 1.逆序栈(不使用其它数据结构) package 暴力递归; import java.util.Stack; public class ReverseStack { public static void reverse(Stack<Integer> stack) { if(stack.isEmpty()) { return ; } int i=f(stack); reverse(stack); stack.push(i); } public stat

weixin_45637300的博客 297

SAP-PM设备模块-PM主数据之功能位置

SAP-PM模块学习

TRUIXIANG的博客 5137

电机控制-PMSM无感FOC控制(四)SVPWM——过调制

上一章我们提到了SVPWM矢量合成的范围在一个平面的矢量圆内,那么当电压矢量超出调制范围时,该怎么做呢?这就是过调制要解决的问题。电机控制-PMSM无感foc控制(三)SVPWM据之前讲解的内容我们可以知道,SVPWM技术在电压空间上模拟了一个近似于圆的电压轨迹,减小了相电流的谐波,降低了电机的谐波损耗,抑制了转矩脉动。然而,SVPWM技术也存在一些问题,合成电压矢量有极限便是其中之一。这个半径为√3/3Vdc的区域也被称作SVPWM的线性区域。

zhuxinmingde的博客 1315

暴力递归到动态规划

暴力递归到动态规划

online46799的博客 421

Multisim 11.0的安装破解汉化步骤

15:打开注册机,选择管理员运行,默认第一项,选择生成文件路径,这里不要随意选择,要找到你安装Multisim安装路径下Shard下的License Manager路径下,否则会报错,破解失败。14:后面会出现一个更新提示,选择否,然后选择重启电脑后,先不要选择重启电脑,在这里出现了问题(可能敲击回车,默认去重启电脑了),所以我说不要重启电脑,重启破解时右下角出现这,点击否。17:重启电脑,如果前面重启过,那可以跳过重启,应用程序下找到下图所示,启动。16:点击确认覆盖,路径下生成了该文件。

qq_53260940的博客 2371

暴力递归到动态规划 02 (绝顶聪明的人的纸牌游戏)

什么是绝顶聪明,比如有指派501002010,绝顶聪明的人第一次手会选择10,则后手不管选哪个,这个先手都能取得100,最后取得最大总和,成为赢家。

niTaoTaoa的博客 986

小样本学习概述

目录 前言 小样本学习存在的意义? 什么是小样本学习? 小样本学习的方法有哪些? 结语 前言 小样本学习(Few-Shot Learning)是近几年兴起的一个研究领域,小样本学习旨在解决在数据有限的机器学习任务。 小样本学习存在的意义? 近些年,以深度卷积神经网络为代表的深度学习方法在各类机器学习任务上取得了优异的成绩——很多任务上已经超越了人类表现。狂欢背后,危机四伏。因为这些深度学习方法work的关键之一是海量标注数据的支持。 但是在工业界,很多时候难以获得海量的训练数据,更.

DwD-的博客 3万+

医疗AI新思路:为什么Graph Neural Network能改善气道分割的漏检问题?

本文探讨了Graph Neural Network(GNN)在医疗AI领域改善气道分割漏检问题的创新应用。通过分析3D UNet等传统方法的局限性,揭示了GNN在图结构建模中的独特优势,特别是在捕捉细小末梢支气管方面的突破性表现。文章详细介绍了UNet-GNN混合架构的设计原理、实验性能对比及优化方向,为CT影像分析提供了新思路。

weixin_30379531的博客 224

【算法基础】暴力递归转动态规划

暴力递归转动态规划

dkz97的博客 270

IC617多线程仿真卡死?手把手教你用TigerVNC替换解决ADE XL Explorer问题(附Manjaro/Centos8实测)

本文针对IC617在Manjaro、CentOS 8等高版本Linux系统中运行ADE XL Explorer进行多线程仿真时出现的卡死问题,提供了详细的诊断与解决方案。文章指出问题根源在于软件内置的旧版VNC组件不兼容,并手把手指导用户通过使用TigerVNC替换原组件来彻底解决,附有在Manjaro和CentOS 8系统上的实测步骤与验证方法。

hill8的博客 774

c++及数据结构基础(一、二)-——暴力枚举、递归迭代、动态规划、贪心算法

4、树形dp:本质上是一个递归函数,返回值是dp数组,dp数组长度为2,所以dp数组(dp table)以及下标的含义:下标为0记录不偷该节点所得到的的最大金钱,下标为1记录偷该节点所得到的的最大金钱。在使用时,首先需要对使用的贪心算法进行严谨的证明,保证这个贪心策略确实可以得到最优解。首先写出暴力递归的解决方法,再写出暴力递归的方法树,看其中是否有重复的节点。分治:是递归的一种特殊形式,每一步自己都会分解问题。用来求解最优解的一种方法,总是寻找这步的局部最优解。递归迭代是枚举的实现方法。

la_la_la_la_h的博客 139

QNX侧触摸屏(TP)Bringup流程与源码深度解析

QNX侧TP Bringup的核心在于构建。

QQ_778132974的博客 477

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

算法与数据结构基础学习十二(从暴力递归到动态规划)

1)空间压缩 2)状态化简 3)四边形不等式 4)其他优化技巧 题目二 题目三 题目四 题目五 ----from左程云算法基础课

Master_guoguo的博客 239

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

牛客网算法基础提升班---第7、8课---暴力递归到动态规划

暴力递归到动态规划 动态规划就是暴力尝试减少重复计算的技巧整,而已这种技巧就是一个大型套路先写出用尝试的思路解决问题的递归函数,而不用操心时间复杂度这个过程是无可替代的,没有套路的,只能依靠个人智慧,或者足够多的经验。 但是怎么把尝试的版本,优化成动态规划,是有固定套路的,大体步骤如下: 1)找到什么可变参数可以代表一个递归状态,也就是哪些参数一旦确定,返回值就确定了 2)把可变参数的所有组合映...

ccnuacmhdu的博客 491

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

算法与基础学习十三(暴力递归到动态规划的尝试2)

三个题

Master_guoguo的博客 154

算法与数据结构基础学习十四(暴力递归到动态规划的尝试3)

//题目 //arr是面值数组,其中的值都是正数且没有重复。再给定一个正数aim。 //每个值都认为是一种面值,且认为张数是无限的。 //返回组成aim的方法数 //例如:arr = {1,2},aim = 4 //方法如下:1+1+1+1、1+1+2、2+2 //一共就3种方法,所以返回3 题目二 题目 //arr是货币数组,其中的值都是正数。再给定一个正数aim。 //每个值都认为是一张货币, //即便是值相同的货币也认为每一张都是不同的, //返回组成aim的方法数 //例如:arr = {1,1,1

Master_guoguo的博客 261

算法学习-Day17-暴力递归

暴力递归在leetcode刷题时,虽然经常超时,毕竟递归压栈比较耗时,但是暴力递归可以让我们完成算法上的进阶,许多我们不会的算法题,通过暴力递归都可以做出来,而且,这是一种承上启下的做法,之后,暴力递归可以进化成动态规划,所以,学习暴力递归也是很重要的。

weixin_53239337的博客 1722

【中等】换钱的方法数-Java:暴力递归的方法

package live.every.day.ProgrammingDesign.CodingInterviewGuide.RecursionAndDynamicPrograming; /** * 换钱的方法数 * * 【题目】 * 给定数组arr,arr中所有的值都为正数且不重复。每个值代表一种面值的货币,每种面值的货币可以使用任意张,再给定一个整数aim * 代表要找的钱数,求换钱有多少种方法。 * * 【难度】 * 中等 * * 【解答】 * 首先介绍暴力递归的方法。定义递归函

了解➔熟悉➔掌握➔精通 692

递归和动态规划

暴力递归: 1,把问题转化为了规模缩小了的同类问题的子问题 2,有明确的不需要继续进行递归的条件(base case) 3,有当得到了子问题的结果之后的决策过程 4,不记录每一个子问题的解 例如: public static int getMin(int[] arr, int L, int R){ if(L == R){ return arr[L]; ...

WYH19951220的博客 226

【算法入门】暴力递归:从“简单粗暴”到“化繁为简”的算法基石

暴力递归是算法设计的起点,也是理解动态规划的基础。本文将通过经典案例解析暴力递归的核心思想、实现方法及优化方向,助你掌握这一“简单却强大”的算法思维!

xiaoyu❅的博客 615

算法基础——暴力递归(C++实现)

相传在古印度圣庙中,有一种被称为汉诺塔(Hanoi)的游戏。该游戏是在一块铜板装置上,有三根杆(编号A、B、C),在A杆自下而上、由大到小按顺序放置n个金盘。游戏的目标:把A杆上的金盘全部移到C杆上,并仍保持原有顺序叠好。打印n层汉诺塔从最左边移动到最右边的全部过程。操作规则:每次只能移动一个盘子,并且在移动过程中三根杆上都始终保持大盘在下,小盘在上,操作过程中盘子可以置于A、B、C任一杆上。题目给出一个字符串,要求打印出它所包含的所有子序列,包括空字符串。

Sebastian_Nova的博客 639

动态规划全总结(涵盖所有题型,左神思路全讲解+LeetCode)

动态规划是对暴力递归算法的优化,主要是通过数组记录的方法,优化掉一些重复计算的过程。总结下动态规划的过程:(1) 抽象出一种“试法”,递归解决问题的方法,很重要(2) 找到“试法”中的可变参数,规划成数组表,可变参数一般是0维的,有几个可变参数就是几维的表(3) 找到base case,问题最基础的解,填入数组表中(4) 根据“试法”中的递归过程,和base case已经填到数组表的值,继续填表(5) 根据问题给定的参数,找到数组中对应的位置,就是最终的解。

xvjian7的博客 2547
上一篇: Python学习之列表
下一篇: springCloud学习二之Eureka高可用搭建
给自己加加油
博客等级 码龄8年 302粉丝 110原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值