递归

什么是尾递归

安稳与你 提交于 2020-02-26 14:35:13
递归算法想必大家都已经很熟悉了。递归算法虽然简单,但是容易导致一些性能问题,于是就有了尾递归这种优化算法。 首先我们先看看递归算法的性能问题是在哪里? 比如我们有一个常见的算法,叫做阶乘算法。 f ( x ) = 1 ⋅ 2 ⋅ 3 ⋯  ⁣ x f(x)=1\cdot2\cdot3\cdots\!x f ( x ) = 1 ⋅ 2 ⋅ 3 ⋯ x 他的递归实现是这样子的 KaTeX parse error: Unknown column alignment: 1 at position 15: \begin{array}{1̲}f(x)=x f(x-1)\… 实现代码如下 //C#实现 int Foo ( int x ) { if ( x == 1 ) { return 1 ; } return x * Foo ( x - 1 ) ; } #python 实现 def foo ( x ) : if ( x == 1 ) : return 1 return x * foo ( x - 1 ) 我们看到每次调用foo方法的时候,又会执行一次foo方法。 此时程序会将当前上下文压栈,计算出下一个foo的值,然后再出栈和x进行相乘 所以对于foo(3)的调用,整个栈的情况是这样的 KaTeX parse error: Unknown column alignment: 1 at

【PAT A1068】Find More Coins

不打扰是莪最后的温柔 提交于 2020-02-26 11:03:17
解法一(递归,最后一个样例超时) 递归的方法基于以下思考:大问题分解为小问题–总额为m,从n个硬币中选,现在判断第n个硬币是否在最后符合条件的组合中,只需将问题分解成总额为m-coins[i],从n-1个硬币中选的子问题,子问题返回bool,若为true则说明选当前硬币,否则说明子问题无解,自然也不会选当前硬币。但有点不清楚为什么最后一个会超时,递归实例貌似没有重复的才对啊,希望有大佬能帮忙答疑解惑。 #include <cstdio> #include <algorithm> #include <stack> using namespace std; int N, M, coins[10010]; stack<int> ans; bool chooseCoin(int total, int i) { if(total == 0) return true; if(total < 0 || (total > 0 && i >= N)) return false; if(chooseCoin(total - coins[i], i + 1)){ ans.push(coins[i]); return true; } else return chooseCoin(total, i + 1); } int main(){ scanf("%d%d", &N, &M); for(int i =

Uncaught RangeError: Maximum call stack size exceeded.

帅比萌擦擦* 提交于 2020-02-26 11:00:18
堆栈溢出的产生是由于过多的函数调用,导致调用堆栈无法容纳这些调用的返回地址,一般容易在递归中产生。所以这种错误一般是在递归函数当中出现,结合报错提示中提到的 returnNodeParameter方法,查看 returnNodeParameter方法自身以及 returnNodeParameter内其他调用方法中是否存在递归函数调用。自己写的代码,那些是递归函数那些不是,心里都有数,既然明确了是递归函数的锅,那就从调用的递归函数中找原因就是。 产生错误原因:问题原因很简单,在 if (temp[i].pid !== ‘0’) 中将本该写成 this.selectedNodePid 的误写成了 this.selectedNode,导致 this.selectedNodePid 在后续递归执行中一直得不到更新,永远是最开始调用的值,从而递归循环一直转不出来,导致无限循环,造成堆栈溢出。 归根结底是参数和参数条件判断的错误导致递归函数一直循环递归调用,无法停止,从而只有在超出浏览器最大堆栈量(内存溢出)时,浏览器抛出错误才能停止。 可以理解为,项目里有死循环! 来源: CSDN 作者: css3html5csdn 链接: https://blog.csdn.net/qq_38402659/article/details/104511088

递归生成平衡二叉树

我的未来我决定 提交于 2020-02-26 10:36:11
生成平衡二叉树, 只需要知道节点的数目即可 生成方式采用中序遍历生成, 所以对应的中序遍历结果也是一个递增序列 基本算法思想为对于一个序列 [1, ...., n]对应的二叉树的根节点一定是棋中间节点, 而[1,...mid] mid [mid+1, ... n] 便是最基本的递归单元 class BNode { constructor(id, left, right) { this.id = id this.left = left this.right = right } get child() { return [this.left, this.right].filter(i => i) || [] } } function getBinTree(count) { // 从[st, ed) 构建二叉树 function buildTree(st, ed) { if(st===ed) return null let mid = Math.floor((st + ed + 1) / 2) if (st === ed - 1) { return new BNode(st) } let left = buildTree(st, mid ) // 注意这里需要mid + 1, 当前节点的id为mid let right = buildTree(mid + 1, ed) return

python刷LeetCode:21. 合并两个有序链表

♀尐吖头ヾ 提交于 2020-02-26 10:31:09
难度等级:简单 题目描述: 将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 示例: 输入:1->2->4, 1->3->4 输出:1->1->2->3->4->4 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/merge-two-sorted-lists 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 解题思路: 1、此题主要考察对链表的操作 2、解法有多种,此处采用递归 3、不断比较大小,更新链表的下一节点 解题代码: # Definition for singly-linked list. # class ListNode: # def __init__(self, x): # self.val = x # self.next = None class Solution: def mergeTwoLists(self, l1: ListNode, l2: ListNode) -> ListNode: if not l1: return l2 if not l2: return l1 if l1.val < l2.val: # 若当前l1数值小于l2,更新l1的下一节点,返回l1当前值 l1.next = self.mergeTwoLists(l1

python递归——汉诺塔

…衆ロ難τιáo~ 提交于 2020-02-26 05:28:58
汉诺塔的传说 法国数学家 爱德华·卢卡斯 曾编写过一个印度的古老传说:在世界中心贝拿勒斯(在印度北部)的圣庙里,一块黄铜板上插着三根宝石针。印度教的主神 梵天 在创造世界的时候,在其中一根针上从下到上地穿好了由大到小的64片金片,这就是所谓的汉诺塔。不论白天黑夜,总有一个僧侣在按照下面的法则移动这些金片:一次只移动一片,不管在哪根针上,小片必须在大片上面。僧侣们预言,当所有的金片都从梵天穿好的那根针上移到另外一根针上时,世界就将在一声霹雳中消灭,而 梵塔 、庙宇和众生也都将同归于尽。   不管这个传说的可信度有多大,如果考虑一下把64片金片,由一根针上移到另一根针上,并且 始终保持上小下大的顺序 。   这需要多少次移动呢?这里需要递归的方法。假设有n片,移动次数是f(n).显然f(1)=1,f(2)=3,f(3)=7,且f(k+1)=2*f(k)+1。此后不难证明 f(n)=2^n-1 。n=64时, 假如每秒钟一次,共需多长时间呢?一个平年365天有31536000 秒,闰年366天有31622400秒,平均每年31556952秒,计算一下:   18446744073709551615秒   这表明移完这些金片需要 5845.54亿年 以上,而地球存在至今不过45亿年,太阳系的预期寿命据说也就是数百亿年。真的过了5845.54亿年,不说太阳系和银河系,至少地球上的一切生命

1.递归问题之约瑟夫问题

↘锁芯ラ 提交于 2020-02-26 02:32:06
文章目录 约瑟夫问题 问题描述 解决思路 扩展思考 约瑟夫问题 问题描述 从围成标记有记号1到n的圆圈的n个人开始,每隔一个人删去一个人,知道只剩一个人。例如n=10的起始图形: 消去的顺序是2,4,6,8,10,3,7,1,9,于是5幸存了下来。问题:确定幸存的号码 J ( n ) J(n) J ( n ) 。 解决思路 从简单情形出发,找规律 n n n 1 2 3 4 5 6 J ( n ) J(n) J ( n ) 1 1 3 1 3 5 发现并没有明显规律。 发现 J ( 2 n ) J(2n) J ( 2 n ) 与 J ( n ) J(n) J ( n ) 的关系: J(20)时,删去2,4,6…2n后,剩下的情形和J(n)相似,个数与顺序相同就表明幸运号码在相同的地方,不同之处就是,每项的数字大小,容易得到: J ( 2 n ) = 2 J ( n ) − 1 J(2n)=2J(n)-1 J ( 2 n ) = 2 J ( n ) − 1 类似的发现 J ( 2 n + 1 ) = 2 J ( n ) + 1 J(2n+1)=2J(n)+1 J ( 2 n + 1 ) = 2 J ( n ) + 1 由以上递推式可以列表: n n n 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 … J ( n ) J(n) J ( n ) 1 1

递归-汉诺塔

雨燕双飞 提交于 2020-02-26 02:19:11
两个汉诺塔,一个是普通版的,另一个是加上必须经过中间柱子的。 # include <stdio.h> # include <iostream> # include <math.h> using namespace std ; int ans = 0 , n ; long long ans2 = 0 ; void hmove ( char a , char b , char c , int n ) { if ( n == 0 ) { return ; } hmove ( a , c , b , n - 1 ) ; //前n - 1块从a移动到b上 printf ( "%c -> %c\n" , a , c ) ; //我自己移动一块从a -> c ans ++ ; //我移动了几次? hmove ( b , a , c , n - 1 ) ; //最后把 n - 1块从b移动到c上 } //只能先移动到相邻的柱子上 void hmove2 ( char a , char b , char c , int n ) { if ( n == 0 ) { return ; } hmove2 ( a , b , c , n - 1 ) ; //把前n - 1块通过b移动到c上 ans2 ++ ; //把最后一块移动到b上 printf ( "%c -> %c\n" , a , b ) ;

递归求子集

筅森魡賤 提交于 2020-02-25 23:25:36
#include<iostream> #include<vector> using namespace std; void solution(int i,vector<int> &nums,vector<int> &item,vector<vector<int> > &result) //传引用 { if(i >= nums.size()) return ; item.push_back(nums[i]); result.push_back(item); solution(i+1,nums,item,result); item.pop_back(); solution(i+1,nums,item,result); } int main() { vector<int> nums; nums.push_back(1); nums.push_back(2); nums.push_back(3); vector<int> item; vector<vector<int> >result; int i = 0; result.push_back(item); //将空集push进result solution(i,nums,item,result); for(int i = 0; i < (1<< nums.size()); i++) { if(result[i].size() == 0)

用递归函数和栈逆序一个栈(C++)

风格不统一 提交于 2020-02-25 22:36:54
题目:一个栈依次压入1,2,3,4,5,那么从栈顶到栈底分别为5,4,3,2,1。将这个栈转置后,从栈顶到栈底为1,2,3,4,5,也就是实现栈中元素的逆序,但是只能用递归函数来实现,不能用其他数据结构。(并不是说代码中不能出现 栈 ) 输入描述: 输入数据第一行一个整数N为栈中元素的个数。 接下来一行N个整数表示从栈顶依次到栈底的每个元素。 输出描述: 输出一行表示栈中元素逆序后的每个元素 题目注意: 1.用递归函数和栈来实现,不要忘了栈 #include <iostream> #include <stack> using namespace std; void reverse(stack<int>& s) { if(s.empty()) { return; } int m=s.top(); s.pop(); reverse(s); s.push(m);//每一次的递归深入,m变量是不一样的 } int main() { int n; while(cin>>n) { stack<int> s; int a=0; for(int i=0;i<n;++i) { cin>>a; s.push(a); } reverse(s); for(int i=0;i<n;++i) { cout<<s.top()<<" "; s.pop(); } } return 0; } 来源: 51CTO 作者