leetcode刷题-栈部分
2021.1.29
1、 #173、二叉搜索树迭代器
重点在于要求时间复杂度是O(1),使用内存为O(h)
一上来直接想到是 对二叉树中序遍历,然后储存在数组中,然后查询直接O(1),但内存O(n)不符合题意,O(h)一般需要O(logn)的复杂度。
class BSTIterator{
public:
BSTIterator(TreeNode* root) {
find(root);
}
void find(TreeNode* x)
{
while(x) {st.push(x); x=x->left;}
}
int next()
{
int tmp=st.top()->val;
TreeNode* ptr =st.top();
st.pop();
if(ptr->right)
find(ptr->right);
return tmp;
}
bool hasNext()
{
if(st.empty()) return false;
return true;
}
private:
stack<TreeNode*> st;
};
2、 #145Morris 后序遍历二叉树
只需要常数O(1)的空间复杂度
class Solution {
public:
void addPath(vector<int> &vec, TreeNode *node) {
int count = 0;
while (node != nullptr) {
++count;
vec.emplace_back(node->val);
node = node->right;
}
reverse(vec.end() - count, vec.end());
}
vector<int> postorderTraversal(TreeNode *root) {
vector<int> res;
if (root == nullptr) {
return res;
}
TreeNode *p1 = root, *p2 = nullptr;
while (p1 != nullptr) {
p2 = p1->left;
if (p2 != nullptr) {
while (p2->right != nullptr && p2->right != p1) {
p2 = p2->right;
}
if (p2->right == nullptr) {
p2->right = p1;
p1 = p1->left;
continue;
} else {
p2->right = nullptr;
addPath(res, p1->left);
}
}
p1 = p1->right;
}
addPath(res, root);
return res;
}
};
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/binary-tree-postorder-traversal/solution/er-cha-shu-de-hou-xu-bian-li-by-leetcode-solution/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
3、 #1047. 删除字符串中的所有相邻重复项
挺简单一个小题,但如果用栈解决会造成时间空间浪费。一个比较巧的方法:对于string的resize的使用。
class Solution {
public:
string removeDuplicates(string S)
{
int index=-1;
for(int i=0;i<S.size();i++)
{
if(index==-1)
S[++index]=S[i];
else if(S[i]==S[index])
index--;
else
S[++index]=S[i];
}
S.resize(index+1);
}
};
2021.1.30
4、 #1130 叶值的最小代价生成树
可以使用区间dp,O(n3)的复杂度。如果用单调递减栈,会有O(n)的复杂度。
使用单调递减栈寻找数组序列的极小值。找到极小值后,将左右两个数(下一个栈顶元素和待入栈元素)中较小者,配对作为两个叶子结点下沉。并且将当前节点入栈(作为上个节点,左/右子树的叶节点最大值)。
最后如果栈中还有元素,必为单调递减。可一次出栈并配对。
代码转载的leetcode最高浏览的答案。有几个好玩的点:
numeric_limits<int>::max() //当前编译器支持的int最大值
const auto& num : nums //只读
auto&& num : nums //修改
class Solution {
public:
int mctFromLeafValues(vector<int>& nums) {
if (nums.size() < 2) {
return 0;
}
int mct = 0;
stack<int> stk;
stk.push(numeric_limits<int>::max());
for (const auto& num : nums) {
while (!stk.empty() && num > stk.top()) {
auto cur = stk.top(); stk.pop();
int minVal = min(stk.top(), num);
mct += minVal * cur;
}
stk.push(num);
}
while (stk.size() > 2) {
auto cur = stk.top(); stk.pop();
mct += cur * stk.top();
}
return mct;
}
};
5、#856 括号的分数
很多时候,效率最高的算法往往转化成一个数学问题,而非借助数据结构。
我的解法:
class Solution {
public:
int scoreOfParentheses(string S)
{
return search((S));
};
int search(string S)
{
if(S.size()==2)
return 1;
stack<int> st;
st.push(1);
int i=1;
for(;i<S.size();i++)
{
if(S[i]=='(')
st.push(1);
else
st.pop();
if(st.empty())
break;
}
if(i>=S.size()-1)
{
string str(S.begin()+1,S.end()-1);
return 2*search(str);
} else
{
string str1(S.begin(),S.begin()+i+1);
string str2(S.begin()+i+1,S.end());
return search(str1)+search(str2);
}
}
};
其实空间时间复杂度都不是最高的。看完题解之后自行优化为以下版本:
然而内存消耗还是很大:
class Solution {
public:
int scoreOfParentheses(string S)
{
a[0]=1;
for(int i=1;i<S.size();i++)
{
if(S[i]=='(')
a[i]=a[i-1]+1;
else
a[i]=a[i-1]-1;
}
return search((S),0,S.size()-1);
};
int search(string S,int s,int e)
{
if(e-s==1)
return 1;
else
{
if(s==0)
{
for(int i=0;i<e;i++)
{
if(a[i]==0)
return search(S,s,i)+search(S,i+1,e);
}
return 2*search(S,s+1,e-1);
}
for(int i=s;i<e;i++)
{
if(a[i]-a[s-1]==0)
return search(S,s,i)+search(S,i+1,e);
}
return 2*search(S,s+1,e-1);
}
}
private:
int a[55];
};
题目标准解法:用栈来解决
栈是解决括号匹配问题非常好的数据结构
class Solution {
public:
int scoreOfParentheses(string S)
{
stack<int> st;
st.push(0);
for(int i=0;i<S.size();i++)
{
if(S[i]=='(')
st.push(0);
else
{
int tmp=st.top();
st.pop();
int tmp2=st.top();
st.pop();
st.push(tmp2+max(2*tmp,1));
}
}
return st.top();
}
};
6、 #1190. 反转每对括号间的子串
神奇的虫洞解法,真的是米奇吃着妙脆角进妙妙屋妙到家了
class Solution {
public:
string reverseParentheses(string s)
{
stack<int> st;
string str;
for(int i=0;i<s.size();i++)
{
if(s[i]=='(')
st.push(i);
else if(s[i]==')')
{
a[i]=st.top();
a[st.top()]=i;
st.pop();
}
}
for(int i=0,d=1;i>=0 && i<s.size();i+=d)
{
if(s[i]=='(' || s[i]==')')
{
d=-d;
i=a[i];
} else
str.push_back(s[i]);
}
return str;
}
private:
int a[2015];
};
用栈解决的版本
string reverseParentheses(string s) {
string res;
stack<string> stk;
for (char &c : s) {
if (c == '(') {
stk.push(res);
res = "";
} else if (c == ')') {
reverse(res.begin(), res.end());
res = stk.top() + res;
stk.pop();
} else {
res.push_back(c);
}
}
return res;
}
作者:crossing-2
链接:https://leetcode-cn.com/problems/reverse-substrings-between-each-pair-of-parentheses/solution/c-zhan-by-crossing-2/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
2021.1.31
7、 #402 移掉k位数字
主要是贪心思想+用string来模拟栈的使用(在数据结构一侧进行添加和删除操作)
class Solution {
public:
string removeKdigits(string num, int k)
{
string st;
int tmp=k;
for(int i=0;i<num.size();i++)
{
while(!st.empty() && tmp>0 && num[i]<st.back())
{
tmp--;
st.pop_back();
}
st.push_back(num[i]);
}
while(tmp>0)
{
st.pop_back();
tmp--;
}
while(st[0]=='0')
st.erase(st.begin(),st.begin()+1);
if(st.size()==0)
{
st+='0';
}
return st;
}
};