算法系列之动态规划

devtools/2025/3/5 0:17:43/

_20250227173818.jpg

动态规划(Dynamic Programming,简称DP)是一种用于解决复杂问题的算法设计技术。它通过将问题分解为更小的子问题,并存储这些子问题的解来避免重复计算,从而提高算法的效率。本文将介绍动态规划的基本概念、适用场景、复杂度分析,并通过Java代码实现经典的动态规划问题。

动态规划介绍

动态规划的核心思想是将一个复杂的问题分解为若干个相互重叠的子问题,通过解决这些子问题来构建原问题的解。动态规划通常适用于具有以下两个性质的问题:

  • 最优子结构:问题的最优解包含其子问题的最优解。

  • 重叠子问题:在求解过程中,相同的子问题会被多次计算。

动态规划算法的实现方式:

  • 自底向上(Bottom-Up):通过迭代的方式从最小的子问题开始,逐步构建更大的子问题的解,直到解决原问题。

复杂度分析

动态规划的时间复杂度和空间复杂度取决于问题的规模和子问题的数量。假设问题的规模为n,子问题的数量为m,则:

  • 时间复杂度:通常为O(m * n),其中m是子问题的数量,n是每个子问题的计算复杂度。

  • 空间复杂度:通常为O(m),用于存储子问题的解。

Java实现斐波那契数列

斐波那契数列:斐波那契数列的定义是从0和1开始,后续的每一项都是前两项的和,即0、1、1、2、3、5、8、13、21、34……这个数列在数学、自然界以及日常生活中都有着广泛的应用和意义。‌

我们通过动态规划和递归两种方式实现输入一个正整数 n ,输出斐波那契数列的第 n 项。

/*** 斐波那契数列** 斐波那契数列:斐波那契数列的定义是从0和1开始,后续的每一项都是前两项的和,即0、1、1、2、3、5、8、13、21、34……这个数列在数学、自然界以及日常生活中都有着广泛的应用和意义。‌** 输入一个正整数 n ,输出斐波那契数列的第 n 项。*/
public class FibonacciSequence {/***动态规划解法* @param n* @return*/public static int fibonacciDP(int n) {// 边界条件if (n <= 1) {return n;}//定义初始发f(n-2)的值int prev2 = 0;//定义初始发f(n-1)的值int prev1 = 1;//定义初始发f(n)的值int current = 0;// 循环计算斐波那契数列的第 n 项(f(n) = f(n-1)+f(n-2))for (int i = 2; i <= n; i++) {current = prev1 + prev2;prev2 = prev1;prev1 = current;}return current;}/***递归解法* @param n* @return*/public static int fibonacciRec(int n) {// 边界条件if (n <= 1) {return n;}//递归求解return fibonacciRec(n-1) +fibonacciRec(n-2);}public static void main(String[] args) {System.out.println(fibonacciDP(10));System.out.println(fibonacciRec(10));}}

⼯作安排问题

  • 问题描述:

⼩明每周上班都会拿到⾃⼰的⼯作清单,⼯作清单内包含 n 项⼯作,每项⼯作都有对应的耗时时⻓(单位h)和报酬,⼯作的总报酬为所有已完成⼯作的报酬之和。那么请你帮⼩明安排⼀下⼯作,保证⼩明在指定的⼯作时间内⼯作收⼊最⼤化。

  • 输入描述:

输⼊的第⼀⾏为两个正整数 T , n 。 T 代表⼯作时⻓(单位h, 0 < T < 100000 ) , n 代表⼯作数量( 1 < n < 3000 )

接下来是 n ⾏,每⾏包含两个整数 t , w 。 t 代表该项⼯作消耗的时⻓(单位h, t > 0 ) , w 代表该项⼯作的报酬。

  • 输出描述

输出⼩明指定⼯作时⻓内⼯作可获得的最⼤报酬。

  • 示例

示例1

输入:

40 3
20 10
20 20
20 5

输出:

30

示例2

输入:

100 3
50 10
20 30
50 20

输出:

50
  • 代码实现
public class WorkArrangement {public static void main(String[] args) {Scanner scanner = new Scanner(System.in);// 输⼊最⼤⼯作时间max_time和⼯作数量Nint max_time = scanner.nextInt();// ⼯作数量Nint N = scanner.nextInt();//工作时常数组int[] times = new int[N];//工资数组int[] wages = new int[N];// 输⼊N份⼯作的时间和报酬for (int i = 0; i < N; i++) {times[i] = scanner.nextInt();wages[i] = scanner.nextInt();}Map<Integer,Integer> dpMap = new HashMap<>();//初始化工作时长和工资dpMap.put(0,0);for(int i = 0; i< N; i++){// 复制当前的dpMapMap<Integer, Integer> currentDP = new HashMap<>(dpMap);//当前工作的时长和工资int time = times[i];int wage = wages[i];// 遍历当前currentDP哈希表中,所有的时间和报酬for(Map.Entry<Integer, Integer> entry: currentDP.entrySet()){int preTime = entry.getKey();int preWage = entry.getValue();// 当前的结束时间int endTime = preTime + time;// 当前结束时间对应的工资int endWage = preWage + wage;// 如果结束时间不超过最大时间,则更新dpMapif(endTime <= max_time){dpMap.put(endTime, Math.max(dpMap.getOrDefault(endTime,0),endWage));}}}// 输出dpMap哈希表中的最⼤值int maxWage = 0;for (int wage : dpMap.values()) {maxWage = Math.max(maxWage, wage);}System.out.println(maxWage);}
}

总结

动态规划是一种强大的算法设计技术,适用于解决具有最优子结构和重叠子问题性质的问题。通过合理地分解问题和存储子问题的解,动态规划可以显著提高算法的效率。本文通过斐波那契数列和工作安排问题展示了动态规划的基本思想和Java实现。希望本文能帮助你更好地理解和应用动态规划算法


http://www.ppmy.cn/devtools/164602.html

相关文章

计算机网络 (第一章)

第一章 计算机网络 概述 1. 定义: 计算机网络主要是由一些通用的、可编程的硬件互连而成的&#xff0c;而这些硬件并非专门用来实现某一特定目的(例如&#xff0c;传送数据或视频信号).这些可编程的硬件能够用来传送多种不同类型的数据&#xff0c;并能支持广泛的和日益增长的…

实战-使用 Playbook 批量部署多台 LAMP 环境

实战-使用 Playbook 批量部署多台 LAMP 环境 playbooks 使用步骤 playbook 是一个不同于使用 ansible 命令行执行方式的模式&#xff0c;功能更强大更灵活。 1、在 playbooks 中定义任务&#xff1a; - name&#xff1a; task description #任务描述信息 module_name: modul…

Google chrome拦截某些下载内容

现在越来越多的单位和个人都开始使用Google chrome了&#xff0c;本人也觉得chrome浏览器很好用&#xff0c;页面加载速度极快&#xff0c;能快速呈现网页内容&#xff0c;提升浏览效率。扩展程序丰富&#xff0c;涵盖办公、学习、娱乐、开发等众多领域&#xff0c;可满足各种个…

CogFindCircleTool工具

CogFindCircleTool是专门用于在工业图像中自动检测圆形或圆弧的特征&#xff0c;它通过分析图像中的边缘信息&#xff0c;拟合出最优的圆形集合参数(如圆心坐标、半径)&#xff0c;常用于精密测量、定位或质量控制等场景。 效果图&#xff1a; CogFindCircleTool工具功能 圆…

PHP面试题--后端部分

本文章持续更新内容 之前没来得及整理时间问题导致每次都得找和重新背 这次整理下也方便各位小伙伴一起更轻松的一起踏入编程之路 欢迎各位关注博主不定期更新各种高质量内容适合小白及其初级水平同学一起学习 一起成为大佬 数组函数有那些 ps&#xff1a;本题挑难的背因为…

doOnNext() vs flatMap():区别与适用场景

在 Reactor&#xff08;Flux / Mono&#xff09;中&#xff0c;doOnNext() 和 flatMap() 都可以用来处理流中的元素&#xff0c;但它们有不同的作用和适用场景。 1. doOnNext() ✅ 作用 用于执行副作用&#xff08;side effects&#xff09;&#xff0c;但不会改变数据流。适…

解决Docker拉取镜像超时错误,docker: Error response from daemon:

当使用docker pull或docker run时遇到net/http: request canceled while waiting for connection的报错&#xff0c;说明Docker客户端在访问Docker Hub时出现网络连接问题。可以不用挂加速器也能解决&#xff0c;linux不好用clash。以下是经过验证的方法&#xff08;感谢轩辕镜…

Word快速替换修改学术论文所有中的中括号引用未上标格式

问题 如图是平时使用Word写完论文时候交叉引用的引用序号&#xff0c;由中括号和引用序号构成&#xff0c;如果不想手动修改使其上标&#xff0c;那么可以使用正则表达式来进行快速匹配替换使其上标&#xff0c;从而减少时间浪费&#xff0c;且能够保持交叉引用的跳转功能&…