《数据结构、算法与应用 —— C++语言描述》学习笔记 — 栈 —— 应用(一)
一、括号匹配
括号匹配是一个典型的用栈这种数据结构解决的问题。其基本原理是每一个右括号都应该与前面最后一个出现的左括号匹配。因此,我们只要以栈结构保存所有出现的左括号,然后每当遇到一个右括号就把栈顶的左括号取出,即可知道有哪些左括号或右括号没有匹配。
LeetCode有一道题为此类问题的变形:
这个问题本身并不复杂。我们只要抓住什么样的括号子串是有效的:可能是两个或多个匹配的括号对续接为一个合理的括号子串(如“((()(())()”中的“()(())()”);也可能是一个括号子串(如“(((())”中的“(())”)。因此,不难发现以下规则:
1、只有当我们遇到一个右括号时,才可能有一个新的有效子串;
2、当且仅当每个右括号按照括号匹配规则与一个左括号匹配,左右括号中间的部分才是有效括号;
3、多个匹配的括号对可以续接的条件是前一个括号对的右括号与后一个括号对的左括号紧邻。
因此,我们可以得到下面的算法:
1、使用一个栈保存遇到的左括号的位置上,使用一个数组保存每个右括号对应有效括号子串的长度(初始值为0);
2、遍历数组:
(1)每当遇到一个左括号,将其index放入栈中;
(2)每当遇到一个右括号,如果栈不为空,则认为该右括号对应于一个有效括号串;
(3)确定该有效串所属的最长有效括号子串的长度:计算当前有效串的长度(根据index之差)与左括号 index - 1 所对应的有效括号子串长度之和。根据其结果确定是否需要更新最长有效子串的长度。
实现如下:
#include "arrayStack.h"
#include "../linearList/arrayList.h"
int longestValidParentheses(string s) {
arrayStack<int> st;
arrayList<int> arrPos(s.length());
int maxLength = 0;
for (int i = 0; i < s.length(); i++)
{
if (s.at(i) == '(')
{
st.push(i);
}
if (s.at(i) == ')')
{
if (!st.empty())
{
int iPos = st.top();
st.pop();
int lastLength = iPos - 1 >= 0 ? arrPos[iPos - 1] : 0;
int length = i - iPos + 1 + lastLength;
arrPos[i] = length;
maxLength = maxLength > length ? maxLength : length;
}
}
}
return maxLength;
}
二、汉诺塔问题
汉诺塔问题来自大梵天创世的一个古老传说。在创世之日,有一座钻石宝塔(塔1),其上有64个金碟,所有碟子从大到小从塔底堆到塔顶,旁边还有另外两座钻石宝塔(塔2和塔3)。从创世之日起,婆罗门一直试图把塔1上的碟子移动到塔2去,不过要借助塔3。由于碟子非常重,所以一次只能移动一个碟子。另外,任何时候大碟子都不能压在小碟子上面。根据这个传说,等到婆罗门把盘子搬完了,世界末日就到了。
在汉诺塔问题中,假设有n个碟子和3座塔。初始时所有碟子从大到小堆在塔1上,我们要把碟子都移动到塔2上,每次移动一个,而且任何时候都不能把打碟子压在小碟子上面。
汉诺塔的经典解法是使用递归。我们这里借助栈结构显示每次移动之后三座塔的数据。
1、扩展stack的拷贝赋值
template<class T>
inline arrayStack<T>::arrayStack(const arrayStack& other