【华为OJ】【072-火车进站】

105 篇文章 155 订阅

【华为OJ】【算法总篇章】


【华为OJ】【072-火车进站】

【工程下载】


题目描述

给定一个正整数N代表火车数量,0<N<10,接下来输入火车入站的序列,一共N辆火车,
每辆火车以数字1-9编号。要求以字典序排序输出火车出站的序列号

思路:
    此处所谓字典序排序的意思是这n辆火车有多少种出站的可能顺序(也就是数据结构中的栈有多少种出栈顺序)。
思路为用三个变量分别存储待进站火车,站中火车和已出站火车,其中待进站火车用Queue(队列)存储和站中
火车采用stack(栈)存储,已出站火车采用StringBuilder来存储,具体实现是采用递归的方法,递归函数
的参数为当前待进站火车、站中火车、已出站火车的值所组成的三元组,递归结束条件是,未进站火车和站中火
车均为空,此时输出已出站火车即为所有出站的一种可能,递推关系为对于当前情况有让下一辆火车进站或让站
中的一辆火车出站两种可能,对于两种可能分别调用递归函数,即可得出问题的解。

输入描述

有多组测试用例,每一组第一行输入一个正整数N(0<N<10),第二行包括N个正整数,范围为1到9。

输出描述

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

输入例子

3
1 2 3

输出例子

1 2 3
1 3 2
2 1 3
2 3 1
3 2 1

算法实现

import java.util.*;

/**
 * Author: 王俊超
 * Date: 2016-01-04 16:41
 * All Rights Reserved !!!
 */
public class Main {
    public static void main(String[] args) {
//        Scanner scanner = new Scanner(System.in);
        Scanner scanner = new Scanner(Main.class.getClassLoader().getResourceAsStream("data.txt"));
        while (scanner.hasNext()) {
            int n = scanner.nextInt();
            String[] ss = new String[n];
            for (int i = 0; i < n; i++) {
                ss[i] = scanner.next();
            }

            System.out.println(trainOut(ss));
        }

        scanner.close();
    }

    /**
     * 此处所谓字典序排序的意思是这n辆火车有多少种出站的可能顺序(也就是数据结构中的栈有多少种出栈顺序)。
     * 思路为用三个变量分别存储待进站火车,站中火车和已出站火车,其中待进站火车用Queue(队列)存储和站中
     * 火车采用stack(栈)存储,已出站火车采用StringBuilder来存储,具体实现是采用递归的方法,递归函数
     * 的参数为当前待进站火车、站中火车、已出站火车的值所组成的三元组,递归结束条件是,未进站火车和站中火
     * 车均为空,此时输出已出站火车即为所有出站的一种可能,递推关系为对于当前情况有让下一辆火车进站或让站
     * 中的一辆火车出站两种可能,对于两种可能分别调用递归函数,即可得出问题的解。
     *
     * @param ss
     * @return
     */
    private static String trainOut(String[] ss) {

//        Arrays.sort(ss);

        List<List<String>> result = new ArrayList<>();
        List<String> out = new ArrayList<>(ss.length);
        List<String> unout = new ArrayList<>(ss.length);
        trainOut(0, ss, out, unout, result);

        Collections.sort(result, new Comparator<List<String>>() {

            @Override
            public int compare(List<String> a, List<String> b) {

                int min = a.size() < b.size() ? a.size() : b.size();


                for (int i = 0; i < min; i++) {
                    String as = a.get(i);
                    String bs = b.get(i);
                    if (as.compareTo(bs) != 0) {
                        return as.compareTo(bs);
                    }
                }
                return a.size() - b.size();
            }
        });

        StringBuilder builder = new StringBuilder(256);
        for (List<String> list : result) {
            StringBuilder b = new StringBuilder(64);
            for (String s : list) {
                b.append(s).append(' ');
            }
            b.setCharAt(b.length() - 1, '\n');

            builder.append(b);
        }

        return builder.toString();
    }

    /**
     * 火车进站
     *
     * @param i      火车编号
     * @param ss     所有的火车
     * @param out    火车已经出站的序列
     * @param unout  火车还未出站的序列
     * @param result 保存所有可能的结果
     */
    private static void trainOut(int i, String[] ss, List<String> out, List<String> unout, List<List<String>> result) {

        // 所有的火车已经进站
        if (i >= ss.length) {
            List<String> list = new ArrayList<>();
            for (String s : out) {
                list.add(s);
            }

            // 先进后出
            for (int j = unout.size() - 1; j >= 0; j--) {
                list.add(unout.get(j));
            }

            result.add(list);

            return;
        }

        // 第i辆车进来就出去了
        out.add(ss[i]);
        trainOut(i + 1, ss, out, unout, result);
        // 还原
        out.remove(out.size() - 1);

        // 第i辆车进来没有出去
        unout.add(ss[i]);
        trainOut(i + 1, ss, out, unout, result);
        // 还原
        unout.remove(unout.size() - 1);
    }
}
一列货运列车共有 n 节车厢,每节车厢将停放在不同的车站。假定 n 个车站的编号分别 为 1~n,车厢的编号与它们的目的地相同。货运列车按照从第 n 站至第 1 站的次序经过这 些车站。为了便于从列车上卸掉相应的车厢,必须重新排列车厢,使各车厢从前至后按编号 1~n 的次序排列。当所有的车厢按照这种次序排列时,在每个车站只卸掉最后一节车厢 即可。可以在一个转轨站里完成车厢的重排工作,在转轨站中有一个入轨,一个出轨和k 个缓冲铁轨(位于入轨和出轨之间)。 图 3-1 给出了一个转轨站, 其中有 k=3 个缓冲铁轨 H1,H2 和 H3。开始时,n节车厢的货车从入轨处进入转轨站,车厢重排结束时各车厢按照编号1至编号n的次序从出轨处离开转轨站。在图 3-1(a)中,n=9,车厢从后至前的初始次序为 5,8,1,7,4,2,9,6,3。图 3-1(b)给出按所要求的次序重新排列后的结果。 为了重排车厢,从前至后依次检查入轨上的所有车厢。如果正在检查的车厢就是下一个满足排列的要求的车厢,可以直接把它放到出轨上。如果不是,则把它移动到缓冲铁轨上, 直到按输出次序要求轮到它时才将它放到出轨上。由于缓冲铁轨上车厢的进和出都是在其顶 部进行的,因此缓冲铁轨是按照 LIFO 的方式使用的。在重排车厢过程中,仅允许以下移动:  车厢可以从入轨移动到一个缓冲铁轨的顶部或者出轨上;  车厢可以从一个缓冲铁轨的顶部移动到的出轨上;
首先需要明确题目的要求。题目给出一个正整数n代表火车数量,接下来需要输入火车入站的序列,一共n辆火车。 我们可以使用递归的方式解决这个问题。首先需要明确递归的结束条件,即当只有一辆火车时,直接输出该火车序列即可。 对于n辆火车的情况,我们可以将其分为两部分来看待,一部分是火车序列的第一辆火车,另一部分是剩余火车的序列。对于剩余火车序列,可以通过递归调用来获取到所有可能的出站序列。 接下来,我们需要将第一辆火车与剩余火车序列的每一辆火车进行交换,得到一个新的出站序列,并将这个新的出站序列作为剩余火车序列进行递归调用。不断交换第一辆火车的位置,可以得到所有可能的出站序列。 通过以上的分析,可以得到递归算法的步骤: 1. 当火车数量为1时,直接输出该火车序列; 2. 对于火车数量大于等于2时,将第一辆火车与剩余火车序列的每一辆火车进行交换; 3. 对每一种交换情况,将剩余火车序列作为新的序列进行递归调用; 4. 输出所有可能的出站序列。 下面是一个示例代码: ```java import java.util.ArrayList; import java.util.Scanner; public class TrainSequence { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); int n = scanner.nextInt(); int[] trainSequence = new int[n]; for (int i = 0; i < n; i++) { trainSequence[i] = scanner.nextInt(); } ArrayList<String> result = new ArrayList<>(); permutation(trainSequence, 0, n - 1, result); for (String s : result) { System.out.println(s); } } private static void permutation(int[] sequence, int start, int end, ArrayList<String> result) { if (start == end) { StringBuilder sb = new StringBuilder(); for (int num : sequence) { sb.append(num).append(" "); } result.add(sb.toString().trim()); } else { for (int i = start; i <= end; i++) { swap(sequence, start, i); permutation(sequence, start + 1, end, result); swap(sequence, start, i); //还原序列 } } } private static void swap(int[] sequence, int i, int j) { int temp = sequence[i]; sequence[i] = sequence[j]; sequence[j] = temp; } } ``` 以上代码中,我们使用了一个ArrayList来保存所有可能的出站序列。在permutation函数中,通过递归调用不断交换第一辆火车的位置,并将剩余火车序列作为新的序列进行递归调用。最后再逆序交换第一辆火车的位置,将火车序列还原。这样通过递归调用,可以得到所有可能的出站序列。 以上就是使用递归算法解决给定火车数量和入站序列的问题
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值