递归算法

知识点二十:分治算法

我们两清 提交于 2020-01-24 17:47:34
前言 MapReduce 是 Google 大数据处理的三驾马车之一,另外两个是 GFS 和 Bigtable。MapReduce在倒排索引、PageRank 计算、网页分析等搜索引擎相关的技术中都有大量的应用。尽管开发一个 MapReduce 看起来很高深,感觉跟我们遥不可及。实际上,万变不离其宗,它的本质就是 分治算法 。 如何理解分治算法? 分治算法(divide and conquer)的核心思想其实就四个字: 分而治之 ,也就是 将原问题划分成 n 个规模较小,并且结构与原问题相似的子问题,递归地解决这些子问题,然后再合并其结果,就得到原问题的解 。这个定义看起来有点类似递归的定义。关于分治和递归的区别,我们只要记住一点, 分治算法是一种处理问题的思想,而递归是一种编程技巧 。实际上,分治算法一般都比较适合用递归来实现。分治算法的递归实现中,每一层递归都会涉及这样三个操作: 分解:将原问题分解成一系列子问题; 解决:递归地求解各个子问题,若子问题足够小,则直接求解; 合并:将子问题的结果合并成原问题。 分治算法能解决的问题,一般需要满足下面这几个条件: 原问题与分解成的小问题具有相同的模式; 原问题分解成的子问题可以独立求解, 子问题之间没有相关性 ,这一点是分治算法跟动态规划的明显区别; 具有分解终止条件,也就是说,当问题足够小时,可以直接求解;

【排序】归并类排序—归并排序(逆序数问题)

血红的双手。 提交于 2020-01-23 23:21:13
文章目录 前言 归并排序(merge sort) 逆序数 结语 微信公众号: bigsai 数据结构与算法专栏 前言 在排序中,我们可能大部分更熟悉冒泡排序、快排之类。对归并排序可能比较陌生。然而事实上归并排序也是一种稳定的排序,时间复杂度为O(nlogn). 归并排序是基于分治进行归并的,有 二路归并 和多路归并.我们这里只讲二路归并并且日常用的基本是二路归并。并且 归并排序的实现方式 有 递归形式 和 非递归形式 。要注意其中的区分(思想上没有大的区别,只是划分上会有区分后面会对比)。 并且归并排序很重要的一个应用是求序列中的逆序数个数。当然 逆序数也可以用树状数组 完成,这里就不介绍了。 归并排序(merge sort) 归并和快排都是 基于分治算法 的。分治算法其实应用挺多的,很多分治会用到递归,也有很多递归实现的算法是分治,但事实上 分治和递归是两把事 。分治就是分而治之。因为面对排序,如果不采用合理策略。每多一个数就会对整个整体带来巨大的影响。而分治就是将整个问题可以分解成相似的子问题。子问题的解决要远远高效于整个问题的解决,并且子问题的合并并不占用太大资源。 至于归并的思想是这样的: 第一次:整串先进行划分成1个一个单独,第一次是一一( 12 34 56--- )归并成若干对,分成若干2个区间.归并完( xx xx xx xx---- )这样局部有序的序列。

递归算法学习系列之八皇后问题

孤街醉人 提交于 2020-01-23 15:36:07
1.引子 中国有一句古话,叫做“不撞南墙不回头",生动的说明了一个人的固执,有点贬义,但是在软件编程中,这种思路确是一种解决问题最简单的算法,它通过一种类似于蛮干的思路,一步一步地往前走,每走一步都更靠近目标结果一些,直到遇到障碍物,我们才考虑往回走。然后再继续尝试向前。通过这样的波浪式前进方法,最终达到目的地。当然整个过程需要很多往返,这样的前进方式,效率比较低下。 2.适用范围 适用于那些不存在简明的数学模型以阐明问题的本质,或者存在数学模型,但是难于实现的问题。 3.应用场景 在8*8国际象棋棋盘上,要求在每一行放置一个皇后,且能做到在竖方向,斜方向都没有冲突。国际象棋的棋盘如下图所示: 4.分析 基本思路如上面分析一致,我们采用逐步试探的方式,先从一个方向往前走,能进则进,不能进则退,尝试另外的路径。首先我们来分析一下国际象棋的规则,这些规则能够限制我们的前进,也就是我们前进途中的障碍物。一个皇后q(x,y)能被满足以下条件的皇后q(row,col)吃掉 1)x=row(在纵向不能有两个皇后) 2) y=col(横向) 3)col + row = y+x;(斜向正方向) 4) col - row = y-x;(斜向反方向) 遇到上述问题之一的时候,说明我们已经遇到了障碍,不能继续向前了。我们需要退回来,尝试其他路径。 我们将棋盘看作是一个8*8的数组

字符:全排列

最后都变了- 提交于 2020-01-23 13:04:51
全排列 一丶递归算法 每次固定以为,递归寻找后面的全排列 如何解决重复问题 我们只使用重复出现的最后一位,每次检查数字后面有没有再次出现过,出现就continue,没有了就可以进行递归操作,这里的比较是O(n)的。假如需要更快的我们可以直接用空间来标记是否访问过,这就是O(1),但是这个算法到最后还是阶乘级别的。 二丶非递归算法 从小到大依次生成序列,比如 123 ,132 ,213, 231,312,321 问题就是关键找到紧邻的下一个排列,方法如下 C++STL已经在Algorithm中集成了 next_permutation 如果相等就再滑动下一位 来源: CSDN 作者: 晴雪儿 链接: https://blog.csdn.net/qq_42146775/article/details/103753266

算法浅谈——递归算法与海盗分金问题

左心房为你撑大大i 提交于 2020-01-23 10:37:06
本文始发于个人公众号: TechFlow 最近看到一道很有意思的问题,分享给大家。 还是老规矩,在我们聊算法问题之前,先来看一个故事。 传说中,有 5个海盗 组成了一支无敌的海盗舰队,他们在最后一次的寻宝当中找寻到了 100枚价值连城 的金币。于是,很自然的,这群海盗面临分赃的问题。为了防止海盗内讧,残忍的海盗们制定了一个奇怪的规则: 他们决定按照功劳大小对五个人进行编号,由编号小的海盗先提出分配方案。 如果方案能够得到大多数人的同意,那么就按照他提出的方案进行分配 。如果不能通过,说明他已经失去了威望,海盗们会残忍地将他投入海中 喂鲨鱼 。 在一个朦胧的早上你一觉醒来,突然发现自己成了一号海盗,那么你应该如何分配才能获得最多的金币,又不会被喂鲨鱼呢? 在我们思考之前,我们先完善一下题意, 增加几个条件 。 首先,每一个海盗都非常残忍。这意味着,在不影响收益的情况下,他们会更倾向于杀人。 其次,每一个海盗都极其聪明,都能想到最佳答案。 这两个条件一出来,问题就比较明显了,这是 博弈论 题目才有的架势。 既然这是一道博弈论的问题,那么我们通过常规的思路是无法找到答案的,我们需要 另辟蹊径 才行。 那么,怎么另辟蹊径呢? 一个比较常规的做法是先不考虑原问题,先 假设一个和原问题差不多,但是规模小很多的子问题 。通过对子问题的求解来摸索原问题的解法。 举个例子,在这题当中

Java数据结构与算法精讲

被刻印的时光 ゝ 提交于 2020-01-23 03:19:40
课程简介 本系列视频教程为数据结构与算法基础,使用java语言描述,适合没有学过C/C++有一定Java基础的同学。没有Java基础的同学可以先行学习Java基础。 课程目录 ├─线性表 ├─栈和队列 ├─HashMap和LinkedHashMap ├─树 ├─二叉树 ├─图 ├─图的遍历与最小生成树 ├─图的最短路径与拓扑排序 ├─算法简介 ├─算法排序 ├─排序与归并 ├─递归与穷举 ├─贪心和分治 ├─动态规划和回溯 来源: CSDN 作者: di_pingxian 链接: https://blog.csdn.net/di_pingxian/article/details/103897423

全排列算法的递归思想及实现

安稳与你 提交于 2020-01-23 01:19:37
题意: 给定1~n n个正整数,写出它们的所有排列顺序。 思路 :根据高中的知识,我们知道不重复的条件下结果是n!个排列顺序,在程序中我们先看看如何用递归来实现。 例如数组{1,2,3}的全排列为123,132,213,231.312.321。 可以看出一点规律来,我们依次交换了第一个数字,分别从1到3,后面是剩下数字的全排列,这里就能看出应该使用递归来实现了。 算法: 首先依次交换第一个数字和每一位数字,再递归调用,最后将交换后的数组复原,以进行下一次的交换。 我自己的疑惑: 在最开始看到这个题目和解法的时候,虽然能理解思路,但是看到代码还是不能完全弄懂,自己也尝试去模拟递归中的每一个步骤,但是发现其中太复杂了,最后还是看了好多人的博客对全排列的解释,才从根本思路上理解了代码的含义。 代码: void perm(int a[],int n, int m) { if(n == m) { for(int i=0;i<m;i++) cout<<a[i]<<" "; cout<<"\n"; } else { for(int j = n;j<m;j++) { swap(a[n], a[j]); perm(a,n+1,m); swap(a[j],a[n]); } } } 来源: https://www.cnblogs.com/puyangsky/p/4697146.html

ybt1207 最大公约数问题 递归经典例题

大憨熊 提交于 2020-01-23 00:16:23
ybt1207 最大公约数问题 递归典例 (选它只是因为太典型,不是因为懒得做难题故意放水) 【题目描述】 给定两个正整数,求它们的最大公约数。 【输入】 输入一行,包含两个正整数(<1,000,000,000)。 【输出】 输出一个正整数,即这两个正整数的最大公约数。 【输入样例】 6 9 【输出样例】 3 【题解】 求最大公约数明明可以两个数同时试除所有小于等于它们的算术平方根的质数,然后把整除的数累乘,得到结果,但是这种算法不光写起来很麻烦,而且的复杂度是: \[ O(\sqrt{n}) \] 很显然,辗转相除是一个更好的方案,辗转相除法,这种算法是用大的数除以小的数(舍掉余数),然后所得的商作为较小的数,之前较小的数作为较大的数,进行同样的运算,直到较小的数为0,这时较大的数便就是一开始两数的最大公约数。 这种算法的证明却没有算法一样简单(其实我不会),如果哪天我有想法(卡题了失去梦想),就对算法进行证明 这种算法的复杂度为: \[ O(log(n)) \] 非常的优秀,堪称递归界的一股清流。 接下来看看代码(故意加很多回车显得代码很长) #include<iostream> using namespace std; int a; int b; int f(int a,int b)//算法主体 { if(b==0) { return a; } return f(b,a%b)

归并排序 递归and非递归

◇◆丶佛笑我妖孽 提交于 2020-01-22 20:36:12
什么是归并排序 归并排序其实就做两件事: “分解”——将序列每次折半划分。 “合并”——将划分后的序列段两两合并后排序。 首先我们来看一下分解是怎样实现的呢? // 递归退出条件,及left》=right的时候 if ( left < right ) { // 找出中间索引 center = ( left + right ) / 2 ; // 对左边数组进行递归 mSort ( k , 0 , center ); // 对右边数组进行递归 mSort ( k , center + 1 , right ); // 合并 merging ( k , left , center , right ); } 接着合并是怎样实现的呢? 初始化一个数组,将左右数组的数进行比较,将较小的数存入中间数组 再将左右数组剩下的数存到中间数组 最后,将中间数组复制回原来的数组 private static void merging ( int [] k , int left , int center , int right ) { int tempArr [] = new int [ k . length ]; // 存放数据的数组 // third记录中间数组的索引 int mid = center + 1 ; int third = left ; int temp = left ; while (

Contest100000608 - 《算法笔记》8.1小节——搜索专题->深度优先搜索(DFS)

▼魔方 西西 提交于 2020-01-22 13:26:30
文章目录 Contest100000608 - 《算法笔记》8.1小节——搜索专题->深度优先搜索(DFS) 8.1 DFS处理 DFS的概念 DFS与递归的关系 递归实现DFS DFS递归例一:背包选物 例二:最优子序列 Codeup习题 5972-ProblemA-【递归入门】全排列 5973-ProblemB-【递归入门】组合的输出 5974-ProblemC-【递归入门】组合+判断素数 5976-ProblemD-【递归入门】n皇后问题(原始的8皇后问题) 5977-ProblemE-【递归入门】出栈序列统计 5978-ProblemF-【递归入门】走迷宫 DFS小结 Contest100000608 - 《算法笔记》8.1小节——搜索专题->深度优先搜索(DFS) 8.1 DFS处理 DFS的概念 DFS与递归的关系 递归实现DFS DFS递归例一:背包选物 //DFS递归例子:背包选物 /*测试数据: 5 8 3 5 1 2 2 4 5 2 1 3 10 */ #include < cstdio > #include < iostream > using namespace std ; const int maxn = 30 ; int n , V , maxValue = 0 ; //物品件数、背包容量、最大价值 int w [ maxn ] , c [ maxn ]