okinawa

IT勉強メモ

Mapで集計してからソートする系問題(AtCoder)

けっこうよく見るタイプなので、メモとして色々な解き方を書いておく。

・問題文

1~Nまでの数字が3回出現する。
2回目に出現するのが早い順に出力する問題。
例:1 3 3 3 2 2 1 1 2  ←1~3までの数字が3回ずつ出現。

atcoder.jp

解き方1:答えがわかった時点で出力

出現回数系はこういう解き方ができる。ソートしない。

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int[] a = new int[n * 3];

        // 2回目出現時点で答えを出力。ソートしない。一番シンプル。AC
        Map<Integer, Integer> map = new HashMap<>(); // 出現数字、出現回数

        for (int i = 0; i < 3 * n; i++) {
            a[i] = sc.nextInt() - 1;

            if (map.containsKey(a[i])) {

                if (map.get(a[i]) == 1) {
                    map.put(a[i], map.get(a[i]) + 1);
                    System.out.print(a[i] + 1 + " "); // 答え出力
                }

            } else {
                map.put(a[i], 1);
            }
        }

解き方2:Listに追加

答えとして出力したい順にListに追加。ソートしない。

上とやってることは同じ。

//         Listに追加バージョン。やってることは上と同じ。AC。
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int[] a = new int[n * 3];

                Map<Integer, Integer> map = new HashMap<>(); // 出現数字、出現回数
                List<Integer> list = new ArrayList<>(n);
        
                for (int i = 0; i < 3 * n; i++) {
                    a[i] = sc.nextInt() - 1;
        
                    if (map.containsKey(a[i])) {
        
                        if (map.get(a[i]) == 1) {
                            map.put(a[i], map.get(a[i]) + 1);
                            list.add(a[i]); //Listに追加
                        }
        
                    } else {
                        map.put(a[i], 1);
                    }
                }
        
                for (int ans : list) {
                    System.out.print(ans + 1 + " ");
                }

解き方3:HashMap→2次元配列に移し替え→2次元配列をソート

集計はMapでして、2次元配列に移し替えてからソート。

問題変わっても色々使えそう。

       // Map→2次元配列→2次元配列をソート。
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int[] a = new int[n * 3];

                Map<Integer, Integer> map = new HashMap<>(); // 出現数字、出現回数
                int[][] soeji = new int[n][2];// [n]{出現数字, 出現箇所}
         
                for (int i = 0; i < 3 * n; i++) {
                    a[i] = sc.nextInt() - 1;
         
                    if (map.containsKey(a[i])) {
         
                        if (map.get(a[i]) == 1) {
                            map.put(a[i], map.get(a[i])+1);
                            soeji[a[i]][0] = a[i];// 2次元配列に格納
                            soeji[a[i]][1] = i;
                        }
         
                    } else {
                        map.put(a[i], 1);
                    }
                }
                // 2個めの要素(出現箇所)でソート 
                Arrays.sort(soeji, (aa, bb) -> aa[1] - bb[1]);
         
                for (int i = 0; i < soeji.length; i++) {
                    System.out.print(soeji[i][0] + 1 + " ");
                }

解き方4:HashMap→TreeMapでソート

HashMapで集計→TreeMapに移し替えてソート。

ちょっと変な書き方。あんまり使わないかな。

       // HashMap→TreeMapでソートする。ACだがごちゃごちゃ。
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int[] a = new int[n * 3];

                Map<Integer, int[]> map = new HashMap<>();// key:出現数字、value:出現回数、出現箇所
                Map<Integer, Integer> tree = new TreeMap<>();//出現箇所、出現数字
                for (int i = 0; i < 3 * n; i++) {
                    a[i] = sc.nextInt() - 1;
        
                    if (map.containsKey(a[i])) {
        
                        if (map.get(a[i])[0] == 1) {
                            int[] b = new int[2];//出現回数、出現箇所
                            b[0] = 2;
                            b[1] = i;
                            map.put(a[i], b);
                        }
        
                    } else {
                        int[] b = new int[2];//出現回数、出現箇所
                        b[0] = 1;
                        b[1] = i;
        
                        map.put(a[i], b);
                    }
                }
        
                // TreeMapでソートする
                for (Map.Entry<Integer, int[]> entry : map.entrySet()) {
                    int key = entry.getKey() + 1;//出現数字
                    int val = entry.getValue()[1];//出現箇所
        
                    tree.put(val, key);
                }
        
                for (Map.Entry<Integer, Integer> entry : tree.entrySet()) {
        
                    System.out.print(entry.getValue() + " ");
                }