OJ刷题之栈和排序(中等)

NC115 栈和排序

中等

通过率:35.86%

时间限制:1秒

空间限制:256M

知识点:栈、排序

描述

给你一个 1 到 n 的排列和一个栈,并按照排列顺序入栈

你要在不打乱入栈顺序的情况下,仅利用入栈和出栈两种操作,输出字典序最大的出栈序列

排列:指 1 到 n 每个数字出现且仅出现一次

数据范围: 1≤n≤5×104,排列中的值都满足 1≤val≤n

进阶:空间复杂度 O(n) ,时间复杂度 O(n)

示例1

输入:

复制代码
[2,1,5,3,4]

返回值:

复制代码
[5,4,3,1,2]

说明:

复制代码
操作       栈     结果
2 入栈;[2]       []
1 入栈;[2\1]     []
5 入栈;[2\1\5]   []
5 出栈;[2\1]     [5]
3 入栈;[2\1\3]   [5]
4 入栈;[2\1\3\4] [5]
4 出栈;[2\1\3]   [5,4]
3 出栈;[2\1]     [5,4,3]
1 出栈;[2]       [5,4,3,1]
2 出栈;[]        [5,4,3,1,2]  

示例2

输入:

复制代码
[1,2,3,4,5]

返回值:

复制代码
[5,4,3,2,1]

思路一:(注释+打印细节版)

cpp 复制代码
#include <stack>
#include <vector>

class Solution 
{
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 栈排序
     * @param a int整型vector 描述入栈顺序
     * @return int整型vector
     */
    vector<int> solve(vector<int>& a) 
    {
        int *bit = new int[a.size()+1](); // 这里的默认值都是0吗???
        vector<int> v;
        stack<int> s;
        int max = a.size(); // 此时未出栈的最大值(已知数是1-n,并且每个数字出现且仅出现一次) // 1-n 有n个数,所以a里的所有值个数就是n
        for(const auto&e: a)
        {
            cout << "我要准备插入栈(还没有插入)" << e << endl;
            // 如果等于所有数的最大值,就连栈也不入,直接放到返回的vector里
            if(max == e) 
            {
                cout << "发现" << e <<"是最大值,不插入栈,直接放入队列"<< endl;
                v.push_back(e);
                cout << "往v里插入"<<e <<endl;
                max--;
                cout<< "最大值更新为" <<max<<endl;
                continue;
            }
            // 走到这里就说明此时准备插入的数据不是剩余数的最大值,
            // 但是先得判断此时栈顶元素是不是最大的,是最大的就哟先让最大的出栈
            // 这时还得考虑到出完栈的栈顶是不是还是最大的,也要判断
            // 栈内此时也可能没有元素,所以也需要判断一下
            if(s.size() != 0)
            {
                cout << e<<"不是最大值,要先判断栈顶是不是最大值"<< endl;
                while(s.size()!=0 &&s.top() == max) // 直到栈顶不是最大值,才结束循环
                {
                    cout << "栈顶是最大值"<<s.top()<< "进入队列并出栈"<< endl;
                    v.push_back(s.top()); // 如果此时栈顶是最大值,就放到vector里
                    cout << "往v里插入"<<s.top() <<endl;
                    bit[s.top()] = 0; // 出栈就置0
                    s.pop(); // 然后删除掉栈顶
                    max--; // 要记得最大值--
                    cout<< "最大值更新为" <<max<<endl;
                }
                // 可以出的最大 值都出完了,接下来看看此时的最大值在前面出现过没有,出现过,就出不了,只能优先出比他小一位的,如果小一位的还在前面,就在匹配更小的
                cout << "现在v里有的:";
                for(auto e:v)
                {
                    cout << e << " ";
                }
                cout <<endl;
                // cout << "为什么不进去"<< "因为不是超找a,而死栈里的" <<endl;
                while(bit[max]) // 这里判断能不能找到前面是否出现过此时的max,存在了就只能--
                {
                    max--;
                    cout << "max--"<< " -> "<< max<<endl;
                    // 在减的过程中,可能栈顶的值刚好相等,这是就要把栈顶的值出栈,出了栈必须置0,并且max--,逻辑要清晰,一步错就炸了
                    if(s.top()==max)
                    {
                        cout<< "可以出栈的最大值刚好又是栈顶"<<max<<endl;
                        v.push_back(s.top());
                        cout <<s.top() <<"出栈,入队列";
                        s.pop();
                        bit[max] = 0;
                        max--;
                        cout<< "最大值更新为" <<max<<endl;
                    }
                }
                // 如果减完刚好又是栈顶是max,下次循环会判断到的
            }    
            // 现在再思考一下,有没有可能删除完栈顶最大的元素,会不会现在要插入的正好就是最大值,理一下逻辑,假设此时的最大值插入了进去,下一次循环,是不是插入的肯定不是最大值,但是会先进行栈顶元素是不是最大值的判断,就完美实现逻辑,所以这里直接插入即可。
            // 插入
            cout  << e<< "插入栈(正式插入了)" << endl;
            bit[e] = 1; // 谁进入了栈就置1,到时候出栈也得置0
            s.push(e);
        }
        cout << "走到这里了"<<endl;
        while(s.size())
        {
            cout << s.top() << "入队列并出栈"<<endl;
            v.push_back(s.top());
            s.pop();
        }
        return v;
    }
};


// 现在的问题 次大值在非常靠前,拿不出来,现在就得考虑把次次大值拿出来

无注释版:

cpp 复制代码
#include <stack>
#include <vector>

class Solution 
{
public:
    vector<int> solve(vector<int>& a) 
    {
        int *bit = new int[a.size()+1](); 
        vector<int> v;
        stack<int> s;
        int max = a.size(); 
        for(const auto&e: a)
        {
            if(max == e) 
            {
                v.push_back(e);
                max--;
                continue;
            }
            if(s.size() != 0)
            {
                while(s.size()!=0 &&s.top() == max) 
                {
                    v.push_back(s.top()); 
                    bit[s.top()] = 0;
                    s.pop(); 
                    max--; 
                }
                while(bit[max])
                {
                    max--;
                    if(s.top()==max)
                    {
                        v.push_back(s.top());
                        s.pop();
                        bit[max] = 0;
                        max--;
                    }
                }
            }
            bit[e] = 1;
            s.push(e);
        }
        while(s.size())
        {
            v.push_back(s.top());
            s.pop();
        }
        return v;
    }
};

突然想起,也能维护个大堆去同步维护栈里已有的元素,来代替bit数组。但是效率不如bit数组高。总之也是一种方案吧。


思路二(注释+打印细节版):

cpp 复制代码
#include <stack>
#include <vector>

class Solution 
{
public:
    vector<int> solve(vector<int>& a) 
    {
        bool hash[50010] = {false};
        vector<int> v;
        stack<int> s;
        int max = a.size();

        for(auto e : a)
        {
            // 入栈
            s.push(e); cout << e <<"入栈了"<<endl;
            hash[e] = true;

            // 先更新要出栈的最大值
            while(hash[max]) // 这里就是现在剩余元素的最大值,已经出现过了,就没必要往后再找了,优先让最大值出栈 最大值出栈越早,那么他所在的位置越靠前,值就越大
            {
                cout <<"更新最大值"<< max<<"->";
                max--;
                cout <<max<<endl;
            }

            cout << "出比"<<max<<"大等的值"<<endl;
            // 出栈 
            while(s.size() && s.top()>=max)
            {
                cout << s.top() <<"出栈"<<endl; 
                v.push_back(s.top());
                s.pop();
            }
        } 
        return v;
    }
};

无注释版:

cpp 复制代码
#include <stack>
#include <vector>

class Solution 
{
public:
    vector<int> solve(vector<int>& a) 
    {
        bool hash[50010] = {false};
        vector<int> v;
        stack<int> s;
        int max = a.size();

        for(auto e : a)
        {
            s.push(e);
            hash[e] = true;

            while(hash[max]) 
            {
                max--;
            }
            while(s.size() && s.top()>=max)
            {
                v.push_back(s.top());
                s.pop();
            }
        } 
        return v;
    }
};

结语:思路一可以锻炼代码逻辑控制能力,思路一做出来对思路二的理解也容易了许多,优先选思路二~

思路一编写过程中,通过每次错误示例去分析哪里没有思考全面,去思考哪里的逻辑有疏漏,对题的理解是否到位,逐渐完善得到最终代码。

相关推荐
沫璃染墨2 小时前
重生之我要手写 C++ list:从底层结构到 const 迭代器与迭代器失效全解
开发语言·c++
paeamecium2 小时前
【PAT甲级真题】- Favorite Color Stripe (30)
数据结构·c++·算法·pat
郭涤生2 小时前
C++ 线程同步复习
开发语言·c++
qeen872 小时前
【算法笔记】差分与经典例题解析
c语言·c++·笔记·学习·算法·差分
say_fall3 小时前
红黑树底层原理全解析:从 5 大性质到 STL 容器底层实现
开发语言·c++
6Hzlia3 小时前
【Hot 100 刷题计划】 LeetCode 416. 分割等和子集 | C++ 0-1背包 1D空间极致优化
c++·算法·leetcode
FL4m3Y4n3 小时前
分布式消息推送系统协议设计【C++ grpc kafka】
c++·分布式·kafka
无限进步_3 小时前
二叉树的前序遍历(非递归实现)
开发语言·数据结构·c++·windows·git·visual studio
ximu_polaris3 小时前
设计模式(C++)-结构型模式-组合模式
c++·设计模式·组合模式