• HJ77 火车进站 ●●


    HJ77 火车进站 ●●

    描述

    给定一个正整数N代表火车数量,0 要求输出所有火车出站的方案,以字典序排序输出。

    数据范围: 1 ≤ n ≤ 10 1\le n\le 10 1n10

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

    输入描述:

    第一行输入一个正整数N(0 < N <= 10),第二行包括N个正整数,范围为1到10。

    输出描述:

    输出以字典序从小到大排序的火车出站序列号,每个编号以空格隔开,每个输出序列换行,具体见sample。

    示例

    输入:
    3
    1 2 3
    输出:
    1 2 3
    1 3 2
    2 1 3
    2 3 1
    3 2 1
    说明:
    第一种方案:1进、1出、2进、2出、3进、3出
    第二种方案:1进、1出、2进、3进、3出、2出
    第三种方案:1进、2进、2出、1出、3进、3出
    第四种方案:1进、2进、2出、3进、3出、1出
    第五种方案:1进、2进、3进、3出、2出、1出
    请注意,[3,1,2]这个序列是不可能实现的。

    题解

    1. 全排列 + 验证出栈序列

    用 used 数组标记使用情况,回溯,对数组进行全排列,同时检查排列组合是否符合出栈序列,记录符合的结果,然后用 sort 进行排序。

    • 时间复杂度: O ( n ∗ n ! ) O(n∗n!) O(nn!),全排列的复杂度为 O ( n ! ) O(n!) O(n!),每次验证的时间是 O ( n ) O(n) O(n)
    • 空间复杂度: O ( n ∗ n ! ) O(n∗n!) O(nn!)
    #include 
    #include 
    #include 
    #include 
    using namespace std;
    
    vector<vector<int>> ans;
    vector<int> path;
    
    bool check(vector<int>& list, vector<int>& path){    // 验证出栈序列
        stack<int> st;
        int idx = 0;
        for(int num : list){
            st.push(num);
            while(!st.empty() && st.top() == path[idx]){
                st.pop();
                ++idx;
            }
        }
        return st.empty();
    }
    
    void backtrack(vector<int>& list, vector<bool>& used){
        if(path.size() == list.size()){
            if(check(list, path)) ans.emplace_back(path);
            return;
        }
        for(int i = 0; i < list.size(); ++i){        // used数组标记、进行全排列
            if(used[i] == 0){
                path.emplace_back(list[i]);
                used[i] = 1;
                backtrack(list, used);
                used[i] = 0;
                path.pop_back();
            }
        }
    }
    
    int main(){
        int n;
        while(cin >> n){
            vector<int> list(n, 0);
            for(int i = 0; i < n; ++i){
                cin >> list[i];
            }
            vector<bool> used(n, 0);
            backtrack(list, used);
            sort(ans.begin(), ans.end());
            for(auto nums : ans){
                for(int num : nums){
                    cout << num << " ";
                }
                cout << endl;
            } 
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    2. dfs 回溯

    每次 dfs 递归,存在两种操作:
    1、从 list 数组中取一个数压入栈中;
    2、取出栈顶元素。

    因此,我们用回溯得到出栈序列的全排列,最后进行排序。

    • 时间复杂度: O ( n ! l o g ( n ! ) ) O(n!log(n!)) O(n!log(n!)),回溯 + 排序。
    • 空间复杂度: O ( n ∗ n ! ) O(n∗n!) O(nn!)
    #include 
    #include 
    #include 
    #include 
    using namespace std;
    
    vector<vector<int>> ans;
    vector<int> path;
    
    void backtrack(vector<int>& list, int idx, stack<int>& st){
        if(path.size() == list.size()){				// 排列完成
            ans.emplace_back(path);
            return;
        }
        for(int i = 1; i <= 2; ++i){				// 递归的两种选择
            if(i == 1){    					// 入栈
                if(idx < list.size()){
                    st.push(list[idx]);				// 入栈
                    backtrack(list, idx+1, st);		// list元素入栈,递归、指针右移
                    st.pop();						// 回溯
                }
            }else{        					// 出栈
                if(!st.empty()){
                    int temp = st.top();
                    path.emplace_back(temp);		// 出栈
                    st.pop();
                    backtrack(list, idx, st);		// 未操作list数组,递归、指针不变
                    st.push(temp);					// 回溯
                    path.pop_back();
                }
            }
        } 
    }
    
    int main(){
        int n;
        while(cin >> n){
            vector<int> list(n, 0);
            for(int i = 0; i < n; ++i){
                cin >> list[i];
            }
            stack<int> st;
            backtrack(list, 0, st);
            sort(ans.begin(), ans.end());		// 排序
            for(auto nums : ans){
                for(int num : nums){
                    cout << num << " ";
                }
                cout << endl;
            } 
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
  • 相关阅读:
    React设计思路
    专注区块链底层技术突破,“复杂美”用技术开源推动产业未来
    MASA Framework的分布式锁设计
    Electron在Linux下打包那些事
    超详细Redis入门教程三
    【计算机毕业设计】基于JSP的网上购物系统的设计与实现
    @Autowired与@Resource区别
    详解WMS——定义与功能
    nginx端口转发?
    商空间的理解(Quotient space)
  • 原文地址:https://blog.csdn.net/qq_19887221/article/details/126641135