当前位置: 首页 > news >正文

递归与分治算法(1)--经典递归、分治问题

目录

一、递归问题

1、斐波那契数列

2、汉诺塔问题

3、全排列问题

4、整数划分问题

二、递归式求解

1、代入法

2、递归树法

3、主定理法

三、 分治问题

1、二分搜索

2、大整数乘法


一、递归问题

1、斐波那契数列

        斐波那契数列不用过多介绍,斐波那契提出的繁殖兔子问题。

        斐波那契递推式如下:

F(n)=\begin{Bmatrix} 1\qquad \qquad \qquad \qquad \quad \ n=0\\ 1 \qquad \qquad \qquad \qquad \quad \ n=1\\ F(n-1)+F(n-2) \quad n>1 \end{Bmatrix} 

        斐波那契代码:

//斐波那契数列
import java.util.Scanner;
public class Fibonacci {public static void main(String [] args){int input=new Scanner(System.in).nextInt();System.out.println(factorial(input));}public static int factorial(int n){if(n==0||n==1)return 1;else{return factorial(n-1)+factorial(n-2);}}
}

2、汉诺塔问题

        汉诺塔问题,也是一个经典问题。一般分为三个步骤:

(1)把n-1个盘子从A柱移到B柱

(2)把最底层1个盘子从A柱移到C柱

(3)把B柱n-1个盘子移到C柱。

        完整代码: 

package RecursionAndDivide;
import java.util.Scanner;
public class Hanoi {public static void main(String[] args){int input=new Scanner(System.in).nextInt();move(input,'A','B','C');} public static void move(int n,char a,char b,char c){if(n==1)System.out.println(a+"->"+c);   //else {move(n-1,a,c,b);    //n-1个从a移到bmove(1,a,b,c);      //底层1个从a移到cmove(n-1,b,a,c);    //n-1个从b移到c}}
}

3、全排列问题

        使用递归的方式输出数组中的全排列,步骤如下:

(0)判定是否数组中仅有一个数,那么输出该排列形式。(请注意,k作为固定头,在每一层进行修改排列顺序的头部)

(1)首先将第一个数与后面的每一个数进行交换(这是一个k到m的循环)。得到:

        1,2,3,4,...,n

        2,1,3,4,...,n

        3,1,2,4,...,n

(2)计算除第一个数以外后面的全排列。

(3)交换第一个数与刚刚那个数,使数组恢复。

        k作为固定头,m作为尾,一直不改变,i作为固定头与循环中交换的数的索引。固定头依赖于第几层递归,不同的递归只会改变数组排列的方式,不会改变长度,而尾不动,所以每次输出只需要输出0到m索引的数组数,也就是所有数组的数。

完整代码:

//全排列问题
public class Permutations {public static void main(String [] args){int []list={1,2,3,4,5};int k=0;int m=list.length-1;Perm(list,k,m);} //产生全排列public static void Perm(int []list,int k,int m){if(k==m)      {for(int i=0;i<=m;i++)System.out.print(list[i]);System.out.println();}else{for(int i=k;i<=m;i++){swap(list,i,k);        Perm(list,k+1,m);swap(list,i,k);}}}//交换数组中两个元素public static void swap(int []list,int i,int k){int temp=list[i];list[i]=list[k];list[k]=temp;}
}

4、整数划分问题

        整数划分问题就是把一个正整数拆分成若干个正整数相加的所有方式,也可以使用递归来求解。定义p(n)为正整数n的划分总个数,q(n,m)为正整数n划分为最大值为m的划分总个数。

        有以下递归式成立:

q(n,m)=\begin{Bmatrix} 1 \qquad \quad \qquad \qquad \qquad \qquad n=1,m=1 \\ q(n,n) \qquad \qquad \qquad \qquad \qquad \quad n<m\\ 1+q(n,n-1) \quad \qquad \qquad \ \ \qquad n=m\\ q(n,m-1)+q(n-m,m) \quad n>m>1 \end{Bmatrix}

        完整代码: 

public class IntegerDivide {public static void main(String[] args){System.out.println(q(6,6));}public static int q(int n, int m){if((n==1)||(m==1))   //且和或一样,或的话出现q(1,2)会执行条件2,返回q(1,1)return 1;if(n<m)return q(n,n);if(n==m)return 1+q(n,n-1);return q(n,m-1)+q(n-m,m);} 
}

二、递归式求解

1、代入法

        一般来说如果递归式成倍数下降,可以n取指数形式,平衡递归式的麻烦。换元求解就是不断回带递归式,最后得到T(1)项忽略,其他换元回变量n的项。

2、递归树法

        递归树法就是将常数项逐层展开成树叶子结点的形式,并将每一层的量相加的总和为递归式的解。如下面这个题,根节点就是递归式中的常数项n-1,每一层叶子点个数就是子递推式的系数为2,叶子结点的量只用n/2换元上一节点的量,得到n/2-1,以此类推,那么递推树如下。

         计算递推式每一层的和,注意最后一层以1为结束,当使用n=2^k替代时,请注意层数变化,最后一层是\frac{n}{2^{k-1}}-1=\frac{2^k}{2^{k-1}}-1=1。那么总和如下,记得要用n替换k:

        对于这一类递归树有偏重的题,可以参照下面这个做法,找到最慢下去的叶节点路线,就是大O的复杂度。

3、主定理法

        主定理方法有一定局限性,最没有局限性的是代入法,但是很麻烦。

三、 分治问题

1、二分搜索

        二分搜索原理:

(1)初始数组是已经排好序的,目的是某个数值是否存在,并找到他的索引,否则返回-1。

(2)大循环满足左值小于等于右值,每次取中间值,判断中间值是否为给定数值,若是返回索引。

(3)判断是否小于中间值,若是右值等于mid-1,判断是否大于中间值,若是左值等于mid+1。

(4)如果不满足循环条件,还没有找到给定值,那么返回-1。

        二分搜索算法的复杂度为O(logn),应该建立在已排好序的数组上,如果为了搜索而去排序,复杂度就大大提升了。

//二分搜索
public static int Search(int arr[],int x,int n){int left=0;int right=n-1;while(left<=right){int mid=(left+right)/2;if(x==arr[mid])return mid;if(x>arr[mid])left=mid+1;else right=mid-1;}return -1;} 

2、大整数乘法

        由于大整数本身就会出现精度丢失问题,另外乘积数过大也会出现数值溢出的问题。所以可以用数组存储大整数进行两个数组之间的乘法。

        另外高复杂度O(mn)也是不能忽视的问题,可以通过大整数拆成两段,将中间二次计算的环节存入内存,来减少复杂度。

        比如下图X和Y都为n为二进制整数,计算它们的乘积,可以拆分成两个相等的n/2位的结构。

        XY=(A*2^{n/2}+B)(C*2^{n/2}+D)=AC*2^n+(AD+BC)*2^{n/2}+BD\\ XY=AC*2^n+((A-B)(D-C)+AC+BD)*2^{n/2}+BD 

        根据上面的式子改变,BD这一项就重复计算了,乘法计算的次数整体不变,但是BD可以不用二次计算了,这样就可以减少一次乘法计算,6次乘法变为5次乘法。 复杂度相比于O(n^2)也有所降低。

        相类似的,矩阵乘法也可以用这种方式降低时间复杂度,成为Strassen矩阵乘法。

 

相关文章:

递归与分治算法(1)--经典递归、分治问题

目录 一、递归问题 1、斐波那契数列 2、汉诺塔问题 3、全排列问题 4、整数划分问题 二、递归式求解 1、代入法 2、递归树法 3、主定理法 三、 分治问题 1、二分搜索 2、大整数乘法 一、递归问题 1、斐波那契数列 斐波那契数列不用过多介绍&#xff0c;斐波那契提出…...

Java之SpringCloud Alibaba【六】【Alibaba微服务分布式事务组件—Seata】

一、事务简介 事务(Transaction)是访问并可能更新数据库中各种数据项的一个程序执行单元(unit)。 在关系数据库中&#xff0c;一个事务由一组SQL语句组成。 事务应该具有4个属性: 原子性、一致性、隔离性、持久性。这四个属性通常称为ACID特性。 原子性(atomicity) ∶个事务…...

Android逆向学习(五)app进行动态调试

Android逆向学习&#xff08;五&#xff09;app进行动态调试 一、写在前面 非常抱歉鸽了那么久&#xff0c;前一段时间一直在忙&#xff0c;现在终于结束了&#xff0c;可以继续更新android逆向系列的&#xff0c;这个系列我会尽力做下去&#xff0c;然后如果可以的话我看看能…...

音频编辑软件Steinberg SpectraLayers Pro mac中文软件介绍

Steinberg SpectraLayers Pro mac是一款专业的音频编辑软件&#xff0c;旨在帮助音频专业人士进行精细的音频编辑和声音处理。它提供了强大的频谱编辑功能&#xff0c;可以对音频文件进行深入的频谱分析和编辑。 Steinberg SpectraLayers Pro mac软件特点 1. 频谱编辑&#xff…...

基于.Net Core实现自定义皮肤WidForm窗口

前言 今天一起来实现基于.Net Core、Windows Form实现自定义窗口皮肤&#xff0c;并实现窗口移动功能。 素材 准备素材&#xff1a;边框、标题栏、关闭按钮图标。 窗体设计 1、创建Window窗体项目 2、窗体设计 拖拉4个Panel控件&#xff0c;分别用于&#xff1a;标题栏、关…...

【Rust】操作日期与时间

目录 介绍 一、计算耗时 二、时间加减法 三、时区转换 四、年月日时分秒 五、时间格式化 介绍 Rust的时间操作主要用到chrono库&#xff0c;接下来我将简单选一些常用的操作进行介绍&#xff0c;如果想了解更多细节&#xff0c;请查看官方文档。 官方文档&#xff1a;chr…...

blender快捷键

1&#xff0c; shift a 添加物体 2&#xff0c;ctrl alt q 切换四格视图 3, ~ 展示物体的各个视图按钮&#xff0c;&#xff08;~ 就是tab键上面的键&#xff09; 4&#xff0c;a 全选&#xff0c;全选后&#xff0c;点 ctrl 鼠标框选 减去已经选择的&#xff1b…...

java Spring Boot 自动启动热部署 (别再改点东西就要重启啦)

上文 java Spring Boot 手动启动热部署 我们实现了一个手动热部署的代码 但其实很多人会觉得 这叫说明热开发呀 这么捞 写完还要手动去点一下 很不友好 其实我们开发人员肯定是希望重启这种事不需要自己手动去做 那么 当然可以 我们就让它自己去做 Build Project 这个操作 我们…...

TouchGFX之后端通信

在大多数应用中&#xff0c;UI需以某种方式连接到系统的其余部分&#xff0c;并发送和接收数据。 它可能会与硬件外设&#xff08;传感器数据、模数转换和串行通信等&#xff09;或其他软件模块进行交互通讯。 Model类​ 所有TouchGFX应用都有Model类&#xff0c;Model类除了存…...

cesium gltf控制

gltf格式详解 glTF格式本质上是一个JSON文件。这一文件描述了整个3D场景的内容。它包含了对场景结构进行描述的场景图。场景中的3D对象通过场景结点引用网格进行定义。材质定义了3D对象的外观,动画定义了3D对象的变换操作(比如选择、平移操作)。蒙皮定义了3D对象如何进行骨骼…...

Spring的依赖注入(DI)以及优缺点

Spring的依赖注入&#xff08;DI&#xff09;&#xff1a;解释和优点 依赖注入&#xff08;Dependency Injection&#xff0c;简称DI&#xff09;是Spring框架的核心概念之一&#xff0c;也是现代Java应用程序开发的重要组成部分。本文将深入探讨DI是什么&#xff0c;以及它的…...

【强化学习】05 —— 基于无模型的强化学习(Prediction)

文章目录 简介蒙特卡洛算法时序差分方法Example1 MC和TD的对比偏差&#xff08;Bias&#xff09;/方差&#xff08;Variance&#xff09;的权衡Example2 Random WalkExample3 AB 反向传播(backup)Monte-Carlo BackupTemporal-Difference BackupDynamic Programming Backup Boot…...

【计算机组成原理】考研真题攻克与重点知识点剖析 - 第 1 篇:计算机系统概述

前言 本文基础知识部分来自于b站&#xff1a;分享笔记的好人儿的思维导图&#xff0c;感谢大佬的开源精神&#xff0c;习题来自老师划的重点以及考研真题。此前我尝试了完全使用Python或是结合大语言模型对考研真题进行数据清洗与可视化分析&#xff0c;本人技术有限&#xff…...

【Java-LangChain:面向开发者的提示工程-8】聊天机器人

第八章 聊天机器人 使用一个大型语言模型的一个令人兴奋的事情是&#xff0c;我们可以用它来构建一个定制的聊天机器人 (Chatbot) &#xff0c;只需要很少的工作量。在这一节中&#xff0c;我们将探索如何利用聊天的方式&#xff0c;与个性化&#xff08;或专门针对特定任务或…...

利用t.ppft.interval分别计算T分布置信区间[实例]

scipy.stats.t.interval用于计算t分布的置信区间&#xff0c;即给定置信水平时&#xff0c;计算对应的置信区间的下限和上限。 scipy.stats.t.ppf用于计算t分布的百分位点&#xff0c;即给定百分位数&#xff08;概率&#xff09;时&#xff0c;该函数返回给定百分位数对应的t…...

软件工程第三周

可行性研究 续 表达工作量的方式 LOC估算&#xff1a;Line of Code 估算公式S(Sopt4SmSpess)/6 FP&#xff1a;功能点 1. LOC (Line of Code) 估算 定义&#xff1a;LOC是指一个软件项目中的代码行数。 2. FP (Function Points) 估算 定义&#xff1a;FP是基于软件的功能性和…...

动态链接那些事

1、为什么要动态链接 1.1 空间浪费 对于静态链接来说&#xff0c;在程序运行之前&#xff0c;会将程序所需的所有模块编译、链接成一个可执行文件。这种情况下&#xff0c;如果 Program1 和 Program2 都需要用到 Lib.o 模块&#xff0c;那么&#xff0c;内存中和磁盘中实际上就…...

力扣:118. 杨辉三角(Python3)

题目&#xff1a; 给定一个非负整数 numRows&#xff0c;生成「杨辉三角」的前 numRows 行。 在「杨辉三角」中&#xff0c;每个数是它左上方和右上方的数的和。 来源&#xff1a;力扣&#xff08;LeetCode&#xff09; 链接&#xff1a;力扣&#xff08;LeetCode&#xff09;官…...

QGIS文章二——DEM高程裁剪和3D地形图

经常看到别人基于高程文件制作出精美的3D地图&#xff0c;笔者按照互联网几种制作方式进行尝试后&#xff0c;写的DEM高程裁剪和3D地形图教程&#xff0c;或许其中有一些错误的&#xff0c;也请指出。 本文基于海南省的shp文件和海南省DEM高程文件&#xff0c;制作海口地区的3D…...

【kubernetes】kubernetes中的StatefulSet使用

TOC 1 为什么需要StatefulSet 常规的应用通常使用Deployment&#xff0c;如果需要在所有机器上部署则使用DaemonSet&#xff0c;但是有这样一类应用&#xff0c;它们在运行时需要存储一些数据&#xff0c;并且当Pod在其它节点上重建时也希望这些数据能够在重建后的Pod上获取&…...

告别Keil!用VSCode+OpenOCD+STLink一键下载STM32程序(保姆级教程)

用VSCodeOpenOCDSTLink打造高效STM32开发环境 在嵌入式开发领域&#xff0c;Keil和IAR等传统IDE长期占据主导地位&#xff0c;但它们臃肿的安装包、昂贵的授权费用和略显陈旧的用户界面让许多开发者开始寻找更现代化的替代方案。Visual Studio Code&#xff08;VSCode&#xff…...

VS2019/2022插件安装指南:让CppCheck帮你揪出C++代码里那些编译器发现不了的‘幽灵Bug’

VS2019/2022插件安装指南&#xff1a;让CppCheck帮你揪出C代码里那些编译器发现不了的‘幽灵Bug’ 在C开发中&#xff0c;编译器能捕捉语法错误&#xff0c;但那些潜伏在逻辑深处的"幽灵Bug"——内存泄漏、未初始化变量、数组越界——往往要等到运行时才暴露。CppCh…...

3分钟快速上手:91160-cli医疗预约自动化助手完整指南

3分钟快速上手&#xff1a;91160-cli医疗预约自动化助手完整指南 【免费下载链接】91160-cli 健康160全自动挂号脚本&#xff0c;捡漏神器 项目地址: https://gitcode.com/gh_mirrors/91/91160-cli 还在为医院挂号难而烦恼吗&#xff1f;91160-cli是一款专为医疗预约设计…...

Windows升级Node版本指南

在 Windows 上升级 Node.js&#xff0c;主要有四种方法&#xff0c;各有侧重。对于大多数开发者&#xff0c;使用版本管理工具 nvm-windows 是最灵活高效的选择。 Windows安装Node.js&#xff1a; 步骤1&#xff1a;访问 Node.js 官方网站 官方网站&#xff0c;下载适用于 Wind…...

告别复杂配置:用MobaXterm+网线直连,5分钟让树莓派SSH并上网(Windows环境)

极简主义者的树莓派连接方案&#xff1a;MobaXterm全流程实战指南 树莓派作为一款功能强大的微型计算机&#xff0c;在嵌入式开发、物联网项目和教育领域广受欢迎。然而对于许多初学者甚至有一定经验的开发者来说&#xff0c;如何快速、稳定地连接树莓派始终是个令人头疼的问题…...

告别GUI!用RTKLIB的rnx2rtkp命令行工具批量处理GNSS数据(附VS2019编译避坑指南)

从GUI到命令行&#xff1a;RTKLIB高效数据处理全攻略 在GNSS数据处理领域&#xff0c;RTKLIB作为开源工具链的标杆&#xff0c;其图形界面rtkpost虽然直观易用&#xff0c;但在处理大批量数据时效率低下。本文将带您深入探索命令行工具rnx2rtkp的完整工作流&#xff0c;从编译避…...

内容创作团队如何通过多模型选型提升文案生成质量与效率

&#x1f680; 告别海外账号与网络限制&#xff01;稳定直连全球优质大模型&#xff0c;限时半价接入中。 &#x1f449; 点击领取海量免费额度 内容创作团队如何通过多模型选型提升文案生成质量与效率 对于新媒体运营和内容营销团队而言&#xff0c;持续产出高质量、风格多样…...

Super IO插件终极指南:5分钟掌握Blender文件处理革命

Super IO插件终极指南&#xff1a;5分钟掌握Blender文件处理革命 【免费下载链接】super_io blender addon for copy paste import / export 项目地址: https://gitcode.com/gh_mirrors/su/super_io Super IO是一款彻底改变Blender工作流程的革命性插件&#xff0c;它通…...

3款实用论文降重神器,帮你轻松解决重复率难题

对于正在撰写毕业论文或者期刊论文的创作者来说&#xff0c;重复率不达标绝对是最头疼的问题之一。自己手动改了三五遍&#xff0c;重复率还是卡在要求线以上&#xff0c;不仅耽误时间还影响心态&#xff0c;这时候一款好用的降重工具就能帮你省下不少精力。今天我们就以第三方…...

如何彻底解决Minecraft离线启动限制:PrismLauncher-Cracked完全指南

如何彻底解决Minecraft离线启动限制&#xff1a;PrismLauncher-Cracked完全指南 【免费下载链接】PrismLauncher-Cracked This project is a Fork of Prism Launcher, which aims to unblock the use of Offline Accounts, disabling the restriction of having a functional O…...