NC115.栈和排序_C++题解
原题链接:链接;
代码:
class Solution {
private:
vector<int>ret;
int hash[50010] = {0};
stack<int>st;
public:
vector<int> solve(vector<int>& a) {
int aim = a.size();
for(auto x:a){
st.push(x);
hash[x] = true;
while(hash[aim]){
aim--;
}
while(st.size()&&st.top()>=aim){//while(st.size()&&st.top>aim)
ret.push_back(st.top());
st.pop();
}
}
return ret;
}
};
读完题之后,我们会发现,必须让vector<int> a中最大的元素先出栈,其他任何一个比它小的元素都不好使,同时我们发现题目中说明了vector<int> a是一个1-n的排列,所以a.size()就是我们苦苦寻找的最大值,我们只需要守株待兔,等它进栈,然后st.pop();即可;比如vector<int> a = {2,3,1,4,5};此时a.size()==5 , 同时max_val==5;我们在代码中用int aim = a.size();来初始化;
此外,我们用数组模拟哈希表来记录我们要的元素是否已经在栈中:int hash[] = {0};当val进栈,我们就hash[val] = true;
第一次我们见到aim也就是最大值进了栈【此时hash[aim]==true】,我们就知道了得把它弹出去,但是下一次弹谁呢?应该是4!也就是aim-1那个值,但是如果4也已经进栈了【hash[aim--]==true】呢?那么我们还需要把4给弹出去,假设4和5中间还是其他元素,比如3,没关系,我们写一个while循环,一次性直接把aim更新到已经进栈的元素中与aim能连续的元素即可。比如栈中有2 4 5,那么aim更新到3即可,我们发现hash[3]==false;那么就进入下一个循环,也就是弹出操作,弹出之前别忘了把元素push_back到一个ret数组中,题目要求返回一个vector<int>,所以我们用ret记录答案。
出栈的这一部分代码我们用另一个vector<int> a = {3,2,1,,5,4} ; 来模拟。aim初始化为5,3 2 1则顺利进栈,遇到5我们发现找到了aim,所以while循环中aim更新为4,我们发现hash[4]==false;所以进入下一个部分,我们把5弹出,然后上去继续取数,拿到了4,while(hash[aim])成立,进入循环,aim更新为3,我们发现3也在栈中,同样的2,1都在栈中,aim更新为0,进入下一个循环,按理来说,我们把3拿出来就行了,可惜了这是栈,我们得按照规则来,你想要的5 4 3 2 1确实是字典序最大,但这在本题中是不可能实现的!这是这道题的关键!我们比如把大于等于aim的值全部弹出来,没办法做到3 2 1的顺序出栈。但这已经是字典序最大了。我们等待到4的时候,我们就知道下一个拿出来3是最好的,但是3已经被压在了最下边,你如果想拿到3,你必须把2 1 先拿出来。