分治法

分治算法的基本思想是将一个规模为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

递归算法(二)-分治法相关推荐

  1. 深大算法设计与分析实验二——分治法求最近点对问题

    源代码: 深大算法设计与分析实验二--分治法求最近点对问题代码-C/C++文档类资源-CSDN下载 目录 实验问题 一.实验目的: 二.内容: 三.算法思想提示 产生不重复的随机点算法: 蛮力算法: ...

  2. c语言分治法求众数重数_算法实验二 分治法 众数问题.pdf

    算法实验二 分治法 众数问题 算法分析与设计实验二 分治法 主要内容 • 实验目的 • 主要实验仪器设备和环境 • 实验内容 • 实验要求 • 注意点 实验目的 • 理解分治法的基本思想 • 针对特定 ...

  3. 算法设计与分析 实验二 分治法求解最近点对问题

    分治法求解最近点对问题 一.实验目的与要求 1.实验基本要求 2.实验亮点 二.实验内容与方法 三.实验步骤与过程 (一)一些准备工作 1.实验流程 2.数据生成与去除重复点 (二)暴力穷举法 1.算 ...

  4. Java常用算法二:分治法

    文章目录 一.分治算法的基本步骤 二.分治算法解决汉诺塔问题 2.1 汉诺塔的规则: 2.2 使用分治算法 笔记参考:尚硅谷 分治法就是把很复杂的问题分而治之,把一个很大的问题分成几个很小的问题,再把 ...

  5. 分治法详解二维最近点对问题

    目录 1 前言 2 问题描述 3 分治法 4 暴力求解 4.1 算法思路 4.2 时间复杂度分析 4.3 代码实现 5 分治法求解 5.1 算法思路 5.1.1 数据预处理 5.1.2 划分中轴线 5 ...

  6. Leetcode 240 Search a 2D Matrix II (二分法和分治法解决有序二维数组查找)

    1.问题描述 写一个高效的算法,从一个 m×n m\times n的整数矩阵中查找出给定的值,矩阵具有如下特点: 每一行从左到右递增. 每一列从上到下递增. 2. 方法与思路 2.1 二分查找法 根据 ...

  7. 算法总结系列(二):贪心法、分治法

    算法2--贪心法.分治法 贪心法 币种统计问题 分治法 快速排序 贪心法 关键词:局部最优.近似 算法描述: 1)定义初始点 2)从初始点出发,找当前点局部最优解 3)以局部最优解为初始点,找新的局部 ...

  8. 寻找中项和第k小元素c语言,分治法第k小元素poj2104.ppt

    分治法第k小元素poj2104 第六章 分 治 6.1 引言 分治法的设计思想是,将一个难以直接解决的大问题,分割成一些规模较小的相同问题,以便各个击破,分而治之. 战略 算法设计技术 划分--治理- ...

  9. java棋盘覆盖分治法,棋盘覆盖-分治法

    信 息 工 程 学 院 算法分析 实习报告 学院:信息工程学院 班级:软件工程083 姓名: 学号: 成绩: 一.实习题目 : 棋盘覆盖 二.实习过程 : 1.了解分治法的思想: 将一个难以解决的大问 ...

最新文章

  1. Deep Learning论文笔记之(三)单层非监督学习网络分析
  2. Linux下串口编程基础
  3. android透明activity,Android 简单实现透明Activity
  4. linux系统rc路由配置_详解CentOS 6.4 添加永久静态路由所有方法汇总
  5. 在B站更新BV标识后,如何查看视频原AV号?
  6. JEECG中datagrid方法自定义查询条件
  7. mysql全局读写怎么锁_MySQL全局锁和表锁
  8. 商厂里调货拿包包程序
  9. 六神不安,生死命悬一线
  10. 车联网就是车-路-云-图-网
  11. c语言实现文件名随时间变化,WizTree 最好用的磁盘文件分析工具
  12. ATFX:美联储会议纪要发布后,美元指数逼近105关口
  13. 草枯树荣,让生命活得云淡风轻
  14. web前端开发主要培训哪些内容
  15. Coin-row problem
  16. 前后端分离框架跨域问题解决
  17. varnish缓存_缓存帽子戏法:Varnish,Memcached和PHP库
  18. android mini系统升级,iPad mini 4系统是什么?能升级安卓4.2吗?
  19. 【Proteus仿真】数码管+4x4键盘矩阵按键简易计算器
  20. 100 行 Java 代码实现一个表情包生成器!

热门文章

  1. Android之严苛模式(StrictMode)
  2. 【iVX 初级工程师培训教程 10篇文拿证】02 数值绑定及自适应网站制作
  3. eos操作系统_EOS相机统一的用户界面
  4. python种颜色循环_Python 实现一个颜色色值转换的小工具
  5. 怎么找到项目中所有同名的类_26岁转行程序员的成长历程--Day03从内存层面理解类和对象...
  6. 神PS!老爸把儿子的画作P成现实,看完我笑哭了
  7. 竞赛发布|100万奖金寻DT时代“最强大脑”!
  8. 【直观理解】一文搞懂RNN(循环神经网络)基础篇
  9. C语言计算一个数的平方根立方根,怎样快速计算出一个数的平方根立方根?
  10. oracle挂证多少钱一个月_惊呆,一条sql竟然把Oracle搞挂了