#P2966. 第1题-栈元素排序
          
                        
                                    
                      
        
              - 
          
          
                      1000ms
            
          
                      Tried: 35
            Accepted: 6
            Difficulty: 3
            
          
          
          
                       所属公司 : 
                              阿里
                                
            
                        
              时间 :2025年5月18日-菜鸟(算法岗)
                              
                      
          
 
- 
                        算法标签>模拟          
 
第1题-栈元素排序
题解
题面描述
有一个栈中有 n 个元素,这 n 个元素就是 1 到 n。现在共有 2n 条指令,有两种指令:
- 指令一: 
push val,往栈压入元素 val; - 指令二: 
pop,弹出栈顶元素。 
你想依次从栈中 pop 出 1 到 n,你可以在每一次 push 操作执行完毕后,对栈里的元素进行重新排序(从栈顶到栈底,按从小到大的顺序)。
为了顺利 pop 出 1 到 n,最少需要进行多少次重新排序?
思路
我们需要模拟栈的操作并尽可能减少排序次数。具体的思路如下:
- 栈的模拟:使用栈存储压入的元素,栈的元素会按照 
push和pop的顺序进行变化。 - 弹出顺序的控制:我们需要按照从 1 到 n 的顺序依次弹出栈顶的元素。如果栈顶元素不是当前期望弹出的元素,那么就需要对栈进行排序。
 - 排序操作:每当 
pop的时候,若栈顶元素不符合要求,就进行排序,确保栈顶元素是当前应该弹出的最小元素。 - 最少排序次数:每当进行一次排序时,我们增加排序次数的计数。
 
通过模拟栈的操作,保持每次期望弹出最小元素,我们可以记录最少的排序次数。
C++
#include <iostream>
#include <stack>
#include <vector>
#include <algorithm>  // 添加这一行
using namespace std;
int main() {
    int n;
    cin >> n;  // 输入栈元素数量
    
    stack<int> st;  // 使用栈来模拟操作
    int next_pop = 1;  // 当前期望弹出的元素
    int sort_count = 0;  // 记录排序的次数
    
    for (int i = 0; i < 2 * n; ++i) {
        string op;
        cin >> op;
        
        if (op == "push") {
            int val;
            cin >> val;
            st.push(val);  // 执行压栈操作
        } else if (op == "pop") {
            if (st.top() == next_pop) {  // 栈顶元素是期望的元素
                st.pop();  // 弹出栈顶元素
                next_pop++;  // 更新期望的下一个元素
            } else {
                sort_count++;  // 需要进行排序
                vector<int> temp;
                
                // 将栈中的元素弹出并放入临时容器
                while (!st.empty()) {
                    temp.push_back(st.top());
                    st.pop();
                }
                
                // 对临时容器排序
                sort(temp.begin(), temp.end());  // 这里就可以使用sort了
                
                // 将排序后的元素重新压入栈
                for (int i = temp.size() - 1; i >= 0; --i) {
                    st.push(temp[i]);
                }
                
                // 弹出期望的元素
                st.pop();
                next_pop++;  // 更新期望的下一个元素
            }
        }
    }
    
    cout << sort_count << endl;  // 输出最少排序次数
    return 0;
}
Python
def main():
    n = int(input())  # 输入元素数量
    st = []  # 使用列表模拟栈
    next_pop = 1  # 记录下一个应该 pop 的元素
    sort_count = 0  # 记录排序次数
    
    for _ in range(2 * n):
        op = input().split()  # 读取指令
        if op[0] == 'push':
            val = int(op[1])  # 获取压入栈的值
            st.append(val)  # 将 val 压入栈
        elif op[0] == 'pop':
            if st[-1] == next_pop:  # 如果栈顶元素是我们期望的元素
                st.pop()  # 弹出栈顶元素
                next_pop += 1  # 更新期望的下一个元素
            else:
                sort_count += 1  # 需要排序
                # 对栈进行排序
                st.sort(reverse=True)  # 从栈顶到栈底排序
                # 弹出栈顶元素
                st.pop()
                next_pop += 1  # 更新期望的下一个元素
    print(sort_count)
if __name__ == "__main__":
    main()
Java
import java.util.*;
public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();  // 输入栈元素数量
        sc.nextLine();  // 消耗掉换行符
        
        Stack<Integer> st = new Stack<>();
        int nextPop = 1;  // 当前期望弹出的元素
        int sortCount = 0;  // 记录排序次数
        
        for (int i = 0; i < 2 * n; ++i) {
            String op = sc.nextLine();  // 读取指令
            if (op.startsWith("push")) {
                int val = Integer.parseInt(op.split(" ")[1]);
                st.push(val);  // 执行压栈操作
            } else if (op.equals("pop")) {
                if (st.peek() == nextPop) {  // 栈顶元素是期望的元素
                    st.pop();  // 弹出栈顶元素
                    nextPop++;  // 更新期望的下一个元素
                } else {
                    sortCount++;  // 需要进行排序
                    // 使用 List 临时存储栈中的元素
                    List<Integer> temp = new ArrayList<>();
                    while (!st.isEmpty()) {
                        temp.add(st.pop());
                    }
                    // 对临时容器排序
                    Collections.sort(temp);
                    // 将排序后的元素重新压入栈
                    for (int i = temp.size() - 1; i >= 0; --i) {
                        st.push(temp.get(i));
                    }
                    // 弹出期望的元素
                    st.pop();
                    nextPop++;  // 更新期望的下一个元素
                }
            }
        }
        
        System.out.println(sortCount);  // 输出最少排序次数
    }
}
        题目内容
有一个栈中有n个元素,这n个元素就是1到n。现在共有2∗n条指令,有两种指令:
- 指令一: push val,往栈压入元素 val ;
 - 指令二: pop,弹出栈顶元素;
 
你想依次从栈中 pop出1~n,你可以在每一次指令一执行完毕后,对栈里的元素进行重新排序(从栈顶到栈底、从小到大排序)。
为了顺利 pop出1~n,最少需要进行多少次重新排序。
保证执行 pop操作的时候,栈非空,且一定存在一组可行解
输入描述
第一行输入一个整数n(1≤n≤105)代表元素数量。
此后2×n行,每行先输入一个字符串s:
如果s=push,在同一行上输入一个整数val(1≤val≤n)代表一次指令一;
如果s=pop,代表一次指令二。
输出描述
在一行上输出一个整数,代表最少需要进行的重新排序次数。
样例1
输入
3
push 1
pop
push 2
push 3
pop
pop
输出
1
说明
我们要按照顺序拿到1~n。push 1,此时栈顶为1。pop,我们可以拿到1,符合要求。push 2和push 3,栈里面的元素为2,3。3在栈顶。pop,如果直接pop会拿到3,此时我们应该要拿2,所以要进行一次排序操作。排序后元素变成3,2。2在栈顶。此时可以拿到2。pop,此时可以拿到3。进行1次排序就按照顺序拿到了1~n。
样例2
输入
5
push 1
push 2
push 3
pop
pop
push 4
push 5
pop
POP
PoP
输出
2
说明
push1,push2,push3后,栈内元素为{1,2,3},栈顶为3。要按照顺序拿到1~n。下一个操作是pop。这时候就需要排序了,排序后变成{3,2,1}栈顶为1。pop,拿到1。pop拿到2。push 4,push 5栈内元素变成{3,4,5}栈顶是5,又进行排序,后变成{5,4,3}栈顶是3。pop拿到3,pop拿到4,pop拿到5。进行2次排序就按照顺序拿到了1~n。