解题笔记(15)——几个栈和递归的问题
本文介绍了几个栈和递归的问题,当然递归的本质就是栈。这些问题网上都能找到解答,自己思考并实现了一下,供网友参考。
问题1:跳台阶问题。具体描述,一个台阶总共有n级,如果一次可以跳1级,也可以跳2级。求总共有多少总跳法,并分析算法的时间杂度。
思路:简单分析一下,这道题不难。假设f(n)为问题的解,从后往前推,最后一跳有两种情况,一是跳1级,二是跳2级,可以得出这个式子 f(n) = f(n-1) + f(n-2),其中f(1)=1,f(2)=2。递归实现如下,当然也可以用迭代。
参考代码:
//函数功能 : 跳台阶问题
//函数参数 : n为台阶个数
//返回值 : 总的跳法
unsigned JumpSteps_Solution1(unsigned n)
{if(n <= 2)return n;else return JumpSteps_Solution1(n - 1) + JumpSteps_Solution1(n - 2);
}unsigned JumpSteps_Solution2(unsigned n)
{if(n <= 2)return n;unsigned sum = 0;unsigned f1 = 1, f2 = 2;for(unsigned i =3; i <= n; i++){sum = f1 + f2; //f(n) = f(n-2) + f(n-1)f1 = f2; //f(n-2) = f(n-1)f2 = sum; //f(n-1) = f(n)}return sum;
}
问题2:栈的push、pop序列。具体描述,输入两个整数序列。其中一个序列表示栈的push顺序,判断另一个序列有没有可能是对应的pop顺序。为了简单起见,我们假设push序列的任意两个整数都是不相等的。
比如输入的push序列是1、2、3、4、5,那么4、5、3、2、1就有可能是一个pop系列。因为可以有如下的push和pop序列:
push 1,push 2,push 3,push 4,pop,push 5,pop,pop,pop,pop,这样得到的pop序列就是4、5、3、2、1。
但序列4、3、5、1、2就不可能是push序列1、2、3、4、5的pop序列。
思路:用一个辅助栈。依次检查push序列的每个元素,如果该元素不等于pop序列的当前元素,则将这个元素压栈;如果相等,则检查push序列的下一个元素,同时pop序列的当前元素往前移1个。最后将辅助栈中的元素退栈,并与pop序列进行比较。最后辅助栈的元素为空,并且pop序列的当前位置为最后元素的下一个位置,则这个序列是pop序列。
参考代码:
//函数功能 : 栈的push、pop序列
//函数参数 : pPush为push序列,pPop为pop序列,nLength为序列长度
//返回值 : 是否成立
bool IsPossiblePopOrder(const int* pPush, const int* pPop, int nLength)
{stack<int> helpStack; //定义一个辅助栈int i = 0, j = 0;//将push序列的元素压栈while(i < nLength){if(pPush[i] == pPop[j]) //相等,pop序列往前移动1j++;elsehelpStack.push(pPush[i]);i++;}//将栈中剩余元素退栈while(!helpStack.empty()){if(helpStack.top() == pPop[j]){helpStack.pop();j++;}elsebreak;}return helpStack.empty() ? true : false;
}
问题3:二元树的深度。输入一棵二元树的根结点,求该树的深度。从根结点到叶结点依次经过的结点(含根、叶结点)形成树的一条路径,最长路径的长度为树的深度。例如:输入二元树:
10
/ \
6 14
/ / \
4 12 16
输出该树的深度3。二元树的结点定义如下:
struct SBinaryTreeNode // a node of the binary tree
{
int m_nValue; // value of node
SBinaryTreeNode *m_pLeft; // left child of node
SBinaryTreeNode *m_pRight; // right child of node
};
思路:这是一道关于树的题目。很多树的问题都是用递归解决的。比如“解题笔记(4)——把二元查找树转变成排序的双向链表”、“解题笔记(6)——在二元树中找出和为某一值的所有路径(树)”、“解题笔记(7)——判断整数序列是不是二元查找树的后序遍历结果”等。这个问题也不例外,只要递归求结点的左右子树的深度,树的深度为 = 1 + max{ 根节点左子树深度,根结点右子树深度}。
参考代码:
//函数功能 : 二元树的深度
//函数参数 : pNode指向树的结点
//返回值 : 深度
int BinaryTreeDepth(BinaryTreeNode *pNode)
{if(pNode == NULL)return 0;else{int leftDepth = BinaryTreeDepth(pNode->m_pLeft);int rightDepth = BinaryTreeDepth(pNode->m_pRight);return (leftDepth > rightDepth) ? leftDepth+1 : rightDepth+1;}
}
问题4:颠倒栈。用递归颠倒一个栈。例如输入栈{1, 2, 3, 4, 5},1在栈顶。颠倒之后的栈为{5, 4, 3, 2, 1},5处在栈顶。
思路:这道题纯粹是为了加深递归的理解。用两个递归来做。
参考代码:
//函数功能 : 颠倒栈
//函数参数 : 要颠倒的栈
//返回值 : 无
template<typename T>
void ReverseStack(stack<T> &srcStack)
{if(!srcStack.empty()){T tmp = srcStack.top();srcStack.pop();ReverseStack(srcStack);AddtoStackBottom(srcStack, tmp); //放到栈底}
}
template<typename T>
void AddtoStackBottom(stack<T> &srcStack, T x)
{if(srcStack.empty()){srcStack.push(x);}else{T tmp = srcStack.top();srcStack.pop();AddtoStackBottom(srcStack, x);srcStack.push(tmp);}
}
问题5:设计包含min函数的栈。定义栈的数据结构,要求添加一个min函数,能够得到栈的最小元素。要求函数min、push以及pop的时间复杂度都是O(1)。
思路:利用双栈来做。一个栈用于正常的入栈退栈,称为Stack1,另外一个用于保存栈的最小元素,称为Stack2。Stack2入栈时,将入栈元素与Stack2的栈顶元素比较,如果小于栈顶元素,则两个栈同时执行入栈操作。Stack1退栈时,如果退栈元素与Stack2的栈顶元素相等,则两个栈同时执行出栈操作。下面是一个简单的实现。
参考代码:
template<class T>
class MinStack
{
public:MinStack();~MinStack();bool Empty() const; //判断栈是否为空void Push(T value); //压栈void Pop(); //退栈T& Top();const T& Top() const;const T& Min() const;
private:stack<T> m_comStack; //正常栈stack<T> m_minStack; //最小栈
};
template<class T>
MinStack<T>::MinStack()
{
}
template<class T>
MinStack<T>::~MinStack()
{
}
template<class T>
bool MinStack<T>::Empty() const
{return m_comStack.empty();
}
template<class T>
void MinStack<T>::Push(T value)
{if(m_minStack.empty() || value <= m_minStack.top())m_minStack.push(value);m_comStack.push(value);
}
template<class T>
void MinStack<T>::Pop()
{if(m_minStack.top() == m_comStack.top())m_minStack.pop();m_comStack.pop();
}
template<class T>
const T& MinStack<T>::Min() const
{return m_minStack.top();
}
template<class T>
T& MinStack<T>::Top()
{m_comStack.top();
}
template<class T>
const T& MinStack<T>::Top() const
{m_comStack.top();
}
本人享有博客文章的版权,转载请标明出处 http://blog.csdn.net/wuzhekai1985
解题笔记(15)——几个栈和递归的问题相关推荐
- LQ训练营(C++)学习笔记_栈与递归
栈与递归 二.栈与递归 1.栈的概念 2.代码实现栈的数据结构 3.栈stack< T >的方法总结 4.火车出入站问题 5.递归的概念 6.递归方法求n的阶乘 7.汉诺塔问题 二.栈与递 ...
- JavaScript学习笔记(四)---闭包、递归、柯里化函数、继承、深浅拷贝、设计模式
JavaScript学习笔记(四)---闭包.递归.柯里化函数.继承.深浅拷贝.设计模式 1. 匿名函数的使用场景 2.自运行 3.闭包 3.1前提: 3.2闭包 4.函数对象的三种定义方式 5.th ...
- 算法9---二叉树的遍历不用栈和递归
二叉树的遍历不用栈和递归 转自:ACM之家 http://www.acmerblog.com/inorder-tree-traversal-without-recursion-and-without- ...
- 【汇编语言与计算机系统结构笔记09】程序栈,(x86-32)过程调用,栈帧,寄存器使用惯例
本次笔记内容: 10.栈与过程调用的机器表示-1 11.栈与过程调用的机器表示-2 12.实验 文章目录 前言 x86-32的程序栈 压栈操作 出栈操作 过程调用 基于栈的编程语言 栈帧 x86-32 ...
- C语言递归(栈与递归)
为什么引入递归 一个比较浅显点的可能认为递归是无限循环而已,自己用循环完全可以代替.递归之所以现在还存在是因为递归可以产生无限循环体,它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问 ...
- 考研复习之数据结构笔记(五)栈和队列(上)(包含栈的相关内容)
目录 一.栈的定义 1.1相关概念与特点 (1)相关概念 (2)相关特点 (3)栈的运算 (4)顺序栈和链式栈的区别 二.栈的表示和实现 2.1顺序栈的表示和实现 (1)结构体定义 (2)建立空栈 ( ...
- 数据结构与算法:09 栈与递归
09 栈与递归 知识结构: 栈是我们经常使用的一种数据结构,比如,手枪发射子弹的顺序与子弹压入弹夹的顺序是相反,即后压入弹夹的子弹先发射出来.又比如,我们使用的Word.Excel.Photoshop ...
- Datawhale组队学习 Task03:栈与递归(2天)
Task03:栈与递归(2天) 栈是我们经常使用的一种数据结构,如下图所示,手枪发射子弹的顺序与子弹压入弹夹的顺序是相反,即后压入弹夹的子弹先发射出来. 比如我们使用的Word.Excel.Photo ...
- 第三章:3.栈和队列 -- 栈与递归的实现
前言: 栈还有一个总要应用是在程序设计语言中实现递归.一个直接调用自己或通过一系列的调用语句间接地调用自己的函数,称作递归函数. 目录: 1.栈 2.栈的应用举例 3.栈与递归的实现 4.队列 5.离 ...
最新文章
- 在CDS(Core Data Services)中使用DCL(Data Control Language)
- Android开发编码规范pdf文件下载
- 前端学习(2447):数据筛选处理
- UpdatePanel的妙用:Incremental Content
- HDU_1711 Number Sequence(KMP)
- OPENGL中的glViewport
- 布尔型Boolean+undefined+null(JS)
- 网络工程师和网络运维工程师的区别
- 计算机科学本质源自于数学思维,计算思维的特点、特征:形式化、程序化、机械化...
- caffe编译-CUDNN_STATUS错误解决方案
- 数字调制解调—2ASK
- puppeteer 生成pdf,绝对解决你的需求
- 电子招投标系统EBD
- 使用多线程时@Service工具类出现NullPoint错误解决
- 新手机为什么一注册陌陌就封解析硬改软改
- 《区块链技术与应用》北大肖臻老师——课程笔记【21-23】
- 干货分享 | 分子对接与分子动力学模拟在药物研发中的应用
- gddr6速率_美光发布GDDR6X显存,号称速度世界最快
- 5g无线图传信号测试软件,5G时代,移动无线图传网络构架和无线图传传输技术...
- java中刷新js函数,js常用刷新页面方法汇总