递归算法(二)-分治法

分治法

分治算法的基本思想是将一个规模为N的问题分解为K个规模较小的子问题,这些子问题相互独立且与原问题性质相同。求出子问题的解,就可得到原问题的解。即一种分目标完成程序算法,简单问题可用二分法完成。

分治法解题的一般步骤:

  1. 分解,将要解决的问题划分成若干规模较小的同类问题;
  2. 求解,当子问题划分得足够小时,用较简单的方法解决;
  3. 合并,按原问题的要求,将子问题的解逐层合并构成原问题的解。

实现方法:分治法一般是通过递归调用实现的。例如排序算法(快速排序,归并排序),傅里叶变换(快速傅里叶变换)等。

分治法使用场景

  1. 该问题的规模缩小到一定的程度就可以容易的解决。
  2. 该问题可以分解为若干个规模较小的相同问题,即该问题具有最优子结构性质。
  3. 利用该问题分解出的子问题的解可以合并为该问题的解。
  4. 该问题所分解出的各个子问题是相互独立的,即子问题之间不包含公共的子问题。

第一条特征是绝大多数问题可以满足的,问题的复杂性一般是随着问题规模的增加而增加;第二条特征是应用分治法的前提。它是大多数问题可以满足的,此特征反映了递归思想的应用。第三条特征是关键,能否利用分治法完全取决于问题是否具有第三条特征,如果具备了第一条和第二条,而不具备第三条特征,则可以考虑使用贪心法或者动态规划法。第四条关系到分治法的效率,如果各个子问题是不独立的则分治法要做寻多不必要的工作,重复的解决公共的子问题,此时虽然可用分治法,但一般使用动态规划法较好。

归并排序

归并排序是采用分治法的一个非常典型的应用。归并排序的思想就是先递归分解数组,再合并数组。

将数组分解最小之后,然后合并两个有序数组,基本思路是比较两个数组的最前面的数,谁小就先取谁,取了后相应的指针就往后移一位。然后再比较,直至一个数组为空,最后把另一个数组的剩余部分复制过来即可。
在这里插入图片描述

def merge_sort(alist):# 终止条件if len(alist) <= 1:return alist# 二分分解num = len(alist)//2left = merge_sort(alist[:num])right = merge_sort(alist[num:])# 合并return merge(left,right)def merge(left, right):'''合并操作,将两个有序数组left[]和right[]合并成一个大的有序数组'''#left与right的下标指针l, r = 0, 0result = []while l<len(left) and r<len(right):if left[l] < right[r]:result.append(left[l])l += 1else:result.append(right[r])r += 1result += left[l:]result += right[r:]return resultalist = [54,26,93,17,77,31,44,55,20]
sorted_alist = merge_sort(alist)
print(sorted_alist)#时间复杂度O(nlogn)

运行结果:
[17, 20, 26, 31, 44, 54, 55, 77, 93]

快速排序

快速排序(英语:Quicksort),又称划分交换排序(partition-exchange sort),通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。

步骤为:

  1. 从数列中挑出一个元素,称为"基准"(pivot),
  2. 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区结束之后,该基准就处于数列的中间位置。这个称为分区(partition)操作。
  3. 递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序。

递归的最底部情形,是数列的大小是零或一,也就是永远都已经被排序好了。虽然一直递归下去,但是这个算法总会结束,因为在每次的迭代(iteration)中,它至少会把一个元素摆到它最后的位置去。

在这里插入图片描述

# 快速排序
# 思路:寻抓元素的正确位置,左边的元素都小于该元素,右边的都大于该元素
# 移动游标low,high不动则交换直到相遇(可同时交换,也可异步交换)
def quick_sort(alist,first,end):# 终止条件if first >= end:returnn = len(alist)mid_value = alist[first]low = firsthigh = endwhile low <high:# 注意处理特殊情况,遇到相等的元素放在一边处理while low < high and alist[high] >= mid_value:high -= 1alist[low] =alist[high]# low += 1while low < high and alist[low] < mid_value:low += 1alist[high] = alist[low]# high -= 1# 代码执行到此,alist[0]找到正确位置,解析来把划分出来的两段新列表递归执行alist[low] = mid_value# 递归部分# 对基准元素左边的子序列进行快速排序quick_sort(alist,first,low-1)# 对基准元素右边的子序列进行快速排序quick_sort(alist,low+1,end)alist = [54,26,93,17,77,31,44,55,20]
quick_sort(alist,0,len(alist)-1)
print(alist)

运行结果:[17, 20, 26, 31, 44, 54, 55, 77, 93]

多数元素

给定一个大小为 n 的数组,找到其中的多数元素。多数元素是指在数组中出现次数 大于 ⌊ n/2 ⌋ 的元素。

你可以假设数组是非空的,并且给定的数组总是存在多数元素。

在这里插入图片描述

class Solution:def majorityElement(self, nums: List[int]) -> int:# 该题分治法不是最优解,但是很好的练习return self.getmajrity(nums,0,len(nums)-1)def getmajrity(self,nums,left,right):# 终止条件if left == right:return nums[left]mid = left + (right - left) // 2leftmajrity = self.getmajrity(nums,left,mid)rightmajrity = self.getmajrity(nums,mid+1,right)#--------------- 此处为分界线上部分为分,下部分为并----------------------# 当左边的多数元素 与 右边的多数元素相等时:返回其中任一值,如左边if leftmajrity == rightmajrity:  # 算是一个小优化(可以不要)return leftmajrity# # 如果不相等,需要分别计算左右两边,然后比较leftcount,rightcount = 0,0for i in nums[left:right+1]:   ## 这里需要+1  否则nums[right]取不到if i == leftmajrity:leftcount += 1elif i == rightmajrity:rightcount += 1if leftcount >= rightcount:return leftmajrityelse:return rightmajrity 

最大子序列和

给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
在这里插入图片描述

class Solution:def maxSubArray(self, nums: List[int]) -> int:n = len(nums)#递归终止条件if n == 1:return nums[0]mid = len(nums) // 2#递归计算左半边最大子序和max_left = self.maxSubArray(nums[:mid])#递归计算右半边最大子序和max_right = self.maxSubArray(nums[mid:])# -----------分界线 上面为分  下面为并----------------------------#计算中间的最大子序和,从右到左计算左边的最大子序和,从左到右计算右边的最大子序和,再相加max_l = nums[mid - 1]tmp = 0for i in range(mid - 1, -1, -1):tmp += nums[i]max_l = max(tmp, max_l)max_r = nums[mid]tmp = 0for i in range(mid, len(nums)):tmp += nums[i]max_r = max(tmp, max_r)#返回三个中的最大值return max(max_right,max_left,max_l+max_r)

参考资料

leetcode 官网
https://zhuanlan.zhihu.com/p/72734354

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/311279.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

自适应滤波器在matlab仿真的程序_电气信息类专业课程之matlab系统仿真 第五章 BPSK通信系统(3)...

继续讲解&#xff01;上一篇文章提出了那么多问题&#xff0c;不知道大家是否能回答上来啊&#xff1f;如果回答不了&#xff0c;有没有去问问度娘呢&#xff1f;程序写完了&#xff0c;回想了一下辅导2017届学生毕业设计的过程&#xff0c;那是真累。我要求他们在现有程序基础…

阿捷外传之Git代码统计:DotNetCore + PowerBI 实现Git仓库日志分析

前言2020年3月初春&#xff0c;虽然春节已经过去一个多月&#xff0c;大街上还未恢复往年的热闹。由于春节前夕突然降临的冠状病毒&#xff0c;导致很多员工无法回到城市复工。春节之后&#xff0c;阿捷所在的公司考虑到复工带来的风险&#xff0c;通知所有员工以远程的方式在家…

递归算法(三)- 回溯法Backtracking

回溯法 回溯法Backtracking&#xff08;找所有的可能&#xff09;递归&#xff1a; 类似枚举&#xff0c;一层一层向下递归&#xff0c;尝试搜索答案。找到答案&#xff1a; > 返回答案&#xff0c;并尝试别的可能未找到答案&#xff1a; > 返回上一层递归&#xff0c;…

一个全栈式的应用集成平台,打破“信息孤岛”

源宝导读&#xff1a;随着企业数字化进程的逐渐深入&#xff0c;企业存在大量的异构系统&#xff0c;各个系统之间信息传输、资源利用困难。本文将介绍明源云ERP为了打破这种“信息孤岛”&#xff0c;而进行的思考与实践。一、前言随着企业信息化进程的逐步深入&#xff0c;互联…

【朝夕技术专刊】Core3.1WebApi_Filter多种注册方式支持依赖注入

欢迎大家阅读《朝夕Net社区技术专刊》第5期我们致力于.NetCore的推广和落地&#xff0c;为更好的帮助大家学习&#xff0c;方便分享干货&#xff0c;特创此刊&#xff01;很高兴你能成为忠实读者&#xff0c;文末福利不要错过哦&#xff01;01PARTCoreFilter多种注册方式在上一…

SQL(一)- 数据库介绍与基础操作

数据库介绍 一、常用的数据库分为两大类&#xff1a; 关系型数据库非关系型数据库&#xff08;NoSql&#xff09; 关系型数据库 概念&#xff1a;是建立在关系模型基础上的数据库&#xff0c;借助于集合代数等数学概念和方法来处理数据库中的数据。 关系型数据库的优势&am…

opencv +数字识别

现在很多场景需要使用的数字识别&#xff0c;比如银行卡识别&#xff0c;以及车牌识别等&#xff0c;在AI领域有很多图像识别算法&#xff0c;大多是居于opencv 或者谷歌开源的tesseract 识别.由于公司业务需要&#xff0c;需要开发一个客户端程序&#xff0c;同时需要在xp这种…

SQL(二)- 基础查询语句

简单的查询语句&#xff08;DQL&#xff09; 下面我们正式来学习查询语句&#xff0c;下面所有查询用到的表均为前面提到的三张表&#xff1a; 员工表中的数据&#xff1a; 部门表中的数据&#xff1a; 薪资表中的数据&#xff1a; 基本查询语句的语法&#xff1a; sele…

SQL(三)- 连接查询

连接查询概念 一、什么是连接查询&#xff1f; 在实际开发中&#xff0c;大部分的情况下都不是从单张表中查询数据&#xff0c;一般都是多张表联合查询最终取出最终结果。在实际再发中&#xff0c;一般一个业务都会对应多张表&#xff0c;比如学生和班级&#xff0c;最起码两…

远程办公也可以很高效

题图&#xff1a;我的站立办公环境因为疫情&#xff0c;全中国人民都过了一个难忘的春节&#xff0c;而身在武汉的我&#xff0c;更是没有出家门半步&#xff0c;坚决做到不过国家添乱。从开始的2月14到后来的2月20日&#xff0c;再到现在的3月10日&#xff0c;官方发布的复工日…

SQL(四) - 子查询和union以及limit分页

子查询概念 什么是子查询&#xff1f;子查询都可以出现在哪里&#xff1f; select语句当中嵌套select语句&#xff0c;被嵌套的select语句是子查询。 子查询可以出现在哪里&#xff1f; select..(select). from..(select). where..(select).1.where子句中使用子查询 案例&a…

ASP.NET Core中的Http缓存

ASP.NET Core中的Http缓存Http响应缓存可减少客户端或代理对 web服务器发出的请求数。响应缓存还减少了 web服务器生成响应所需的工作量。响应缓存由 Http请求中的 header控制。而 ASP.NETCore对其都有相应的实现&#xff0c;并不需要了解里面的工作细节&#xff0c;即可对其进…

SQL(五) - 表的创建以及操作

创建表 建表语句的语法格式&#xff1a; create table 表名(字段名1 数据类型,字段名2 数据类型,字段名3 数据类型,....);MySql常用数据类型 BLOB 二进制大对象&#xff08;存储图片、视频等流媒体信息&#xff09; Binary Large OBject &#xff08;对应java中的Object&…

Istio 2020 年 Roadmap——一切为了商用

原文地址&#xff1a;https://preliminary.istio.io/zh/blog/2020/tradewinds-2020/&#xff0c;由 ServiceMesher 社区翻译。Istio 解决了人们在运行微服务时遇到的实际问题。甚至早期的预发行版本就已经可以帮助用户诊断其体系架构中的延迟&#xff0c;提高服务的可靠性以及透…

SQL(七) - 事务、索引、视图

事务&#xff08;Transaction&#xff09; 3.1、什么是事务&#xff1f; 一个事务是一个完整的业务逻辑单元&#xff0c;不可再分。 比如&#xff1a;银行账户转账&#xff0c;从A账户向B账户转账10000.需要执行两条update语句&#xff1a; update t_act set balance balan…

如何编写高性能的C#代码(二)

使用Benchmark.NET对C# 代码进行基准测试的简介在我以前的文章中[10]&#xff0c;我介绍了该系列文章[11]&#xff0c;在其中我将分享我的经验&#xff0c;同时了解C&#xff03;和.NET Core&#xff08;corefx&#xff09;框架的新性能。在本文中&#xff0c;我想着重于对现有…

如何编写高性能的C#代码(一)

原文来自互联网&#xff0c;由长沙DotNET技术社区编译。如译文侵犯您的署名权或版权&#xff0c;请联系小编&#xff0c;小编将在24小时内删除。作者介绍&#xff1a;史蒂夫戈登&#xff08;Steve Gordon&#xff09;是Microsoft MVP&#xff0c;Pluralsight的作者&#xff0c;…

从Java转向.NET/C#,Are You OK?

最近由于项目变动&#xff0c;需要用.NET/C#做开发&#xff0c;经过一段时间的学习和培训&#xff0c;对这个技术栈有了一定的理解。大家可能都知道Java和.NET/C#很像&#xff0c;这里粗略的把两者做一个对比&#xff0c;希望对感兴趣的童鞋有所帮助。如果现在有人问我&#xf…

树的节点值之和

题目背景 墨家家主有棵树。 题目描述 给定一个保存树节点信息的数据结构&#xff0c;它包含了树节点唯一的 id &#xff0c;树节点值 和 直系子节点的 id 。 比如&#xff0c;树节点1是树节点2的父节点&#xff0c;树节点2是树节点3的父节点。他们相应的树节点值为 9 , 4 , …

.NET Core开发实战(第21课:中间件:掌控请求处理过程的关键)--学习笔记(上)...

21 | 中间件&#xff1a;掌控请求处理过程的关键这一节讲解一下如何通过中间件来管理请求处理过程中间件工作原理next 表示后面有一个委托&#xff0c;每一层每一层套下去可以在任意的中间件来决定在后面的中间件之前执行什么&#xff0c;或者说在所有中间件执行完之后执行什么…