0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

AOJ PG応用(列の操作)

Posted at

最小値、最大値

与えられた3つの整数a,b,cの最小値と最大値を出力してください

ex.java
import java.io.*;

public class Main {
    public static void main(String[] args) throws IOException {
        // 標準入力から1行読み取り
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String[] parts = br.readLine().split(" ");

        // String → int に変換するのを忘れないように!
        int[] input = new int[3];
        for (int i = 0; i < 3; i++) {
            input[i] = Integer.parseInt(parts[i]);
        }

        // 最小値と最大値を計算して出力
        int min = min(input);
        int max = max(input);
        System.out.println(min + " " + max);
    }

    // 最小値を求めるメソッド
    static int min(int[] input) {
        int min = input[0];
        for (int i = 1; i < input.length; i++) {
            if (input[i] < min) {
                min = input[i];
            }
        }
        return min;
    }

    // 最大値を求めるメソッド
    static int max(int[] input) {
        int max = input[0];
        for (int i = 1; i < input.length; i++) {
            if (input[i] > max) {
                max = input[i];
            }
        }
        return max;
    }
}

配列を昇順にソートして最初と最後の要素を表示するだけでもOK

最小最大要素

与えられた数列
A={a0,a1,...,an−1}に対して、以下のクエリを処理してください。
min(b,e): 区間[b,e)の要素ab,ab+1,...,ae−1の最小値を報告する
max(b,e): 区間[b,e)の要素ab,ab+1,...,ae−1の最大値を報告する
※[b, e) は 「b 以上 e 未満」

ex.java
import java.io.*;
import java.util.*;

public class Main {
    static int[] A; // グローバルに定義

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

        // nの読み取り
        int n = Integer.parseInt(br.readLine());

        // A配列の読み取り
        String[] aStr = br.readLine().split(" ");
        A = new int[n];
        for (int i = 0; i < n; i++) {
            A[i] = Integer.parseInt(aStr[i]);
        }

        // クエリ数
        int q = Integer.parseInt(br.readLine());

        for (int i = 0; i < q; i++) {
            String[] query = br.readLine().split(" ");
            int op = Integer.parseInt(query[0]);
            int b = Integer.parseInt(query[1]);
            int e = Integer.parseInt(query[2]);

            if (op == 0) {
                System.out.println(In_min(b, e)); //System.out.println内でメソッド呼び出し
            } else {
                System.out.println(In_max(b, e));
            }
        }
    }

    // 最小値取得
    static int In_min(int b, int e) {
        int min = A[b];
        for (int i = b + 1; i < e; i++) {
            if (A[i] < min) min = A[i];
        }
        return min;
    }

    // 最大値取得
    static int In_max(int b, int e) {
        int max = A[b];
        for (int i = b + 1; i < e; i++) {
            if (A[i] > max) max = A[i];
        }
        return max;
    }
}

変数のスコープについて

  • mainメソッド内だけで使いたい変数
    → mainメソッド内で定義
  • mainメソッドだけでなく、mainから呼び出す他のstaticメソッドでも使いたい
    → 本門の配列AのようにMainクラスのstatic変数として宣言(グローバル変数)
  • mainメソッドの外の静的メソッドだけで使いたい(main内では使わない)
    → mainメソッド内だけの場合と同様に、そのメソッド内にだけ変数を書くのが基本
    (ただし、複数メソッド間で共有したいならstatic変数にする

★前処理&インデックスによるカウント

整数を保持する数列
A={a0,a1,...,an−1}に対して、以下のクエリを処理してください。
count(b,e,k): ab,ab+1,...,ae−1の中に含まれるkの数を出力する

AOJ.java
import java.util.*;

public class Main {
    static Map<Integer, List<Integer>> valToIndices = new HashMap<>();

//数列 A を処理して、上記の Map を作っていく関数
//各値がどのインデックスで出るかまとめる
    public static void preprocess(int[] A) {
        for (int i = 0; i < A.length; i++) {
            valToIndices.computeIfAbsent(A[i], k -> new ArrayList<>()).add(i);
        }
    }
    //クエリ (b, e, k) を受け取り、「A[b]〜A[e-1] に k が何回あるか」を返す
    public static int count(int b, int e, int k) {
    //数 k の出現位置リストを取得,もし k が A に一度も出てこなければ、空リストを返す
        List<Integer> indices = valToIndices.getOrDefault(k, new ArrayList<>());
        // lowerBound: b以上の最初の位置
        int left = lowerBound(indices, b);
        // lowerBound: e以上の最初の位置(eは範囲外なので含まない)
        int right = lowerBound(indices, e);
        return right - left;
    }

    // 二分探索→リストの中から、値がtarget 以上の最初のインデックスを探す
    public static int lowerBound(List<Integer> list, int target) {
        int left = 0, right = list.size();
        while (left < right) {
            int mid = (left + right) / 2;
            if (list.get(mid) < target) {
                left = mid + 1;
            } else {
                right = mid;
            }
        }
        return left;
    }

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);

        int n = sc.nextInt();
        int[] A = new int[n];
        for (int i = 0; i < n; i++) {
            A[i] = sc.nextInt();
        }

        preprocess(A);

        int q = sc.nextInt();
        for (int i = 0; i < q; i++) {
            int b = sc.nextInt();
            int e = sc.nextInt();
            int k = sc.nextInt();
            System.out.println(count(b, e, k));
        }
    }
}
  • この手の問題は線形探索法かと思ったけど入力サイズが大きいとTLEしてしまうので今回は不採用
  • 線形探索法がだめな場合、集合や二分探索など代替案の中から今回は「前処理でインデックスを作る」を選択
  • 「インデックスを作る」→たとえば、配列 A = [50, 10, 30, 10] があるとき、
    「10はどこにある?」と聞かれたら、普通は1つずつ見ていって探すが(線形探索)いちいちやってたら時間がかかる
  • よく使う値にすぐアクセスしたいなら、こういう「メモ帳」みたいなものを最初に作っておく
ex.java
valToIndices = {
    //値(k):配列Aにおける出現位置(インデックス)
    1: [0, 2, 5],
    4: [1, 3],
    2: [4],
    3: [6],
    5: [7],
    6: [8]
}
  • Map(値)> を使って、各値kがどのインデックスに出現するかを前処理で記録
  • computeIfAbsent(key, k -> new ArrayList<>())→key が存在すればその値を返し、存在しなければ k -> new ArrayList<>() が呼ばれて値を作り、map.put(key, 値) して返す
  • k -> new ArrayList<>はラムダ式→「k」を引数に取って、新しい空のArrayListを返す
  • computeIfAbsentが内部で自動的にkeyをkに渡し、それを引数としてラムダ式の処理部分を実行
ex.java
valToIndices.computeIfAbsent(1, k -> new ArrayList<>()).add(0);
//「1というキーがなければ、空のリストを作ってそこに 0 を追加する」
  • getOrDefault(key, defaultValue)→キーがあればその値を返し、なければ new ArrayList<>() を返す(でもMapには追加しない!)
    →値を登録したいときはcomputeIfAbsentでいいけど単に読みたいだけなら getOrDefault
  • 例えばcount(1,4,3)でindices = [0, 1, 2, 4] (Aにおける3の出現位置)だとする
  • インデックス 1, 2, 3 の中に 3 が何回あるか数える→lowerBoundを使う
  • lowerBound→list の中で、「target以上」の値が最初に現れるインデックスを返す
  • binarysearchはインデックスがある位置を返すための二分探索なのでここでlowerboundを定義

辞書順比較

2つの数列A={a0,a1,...,an−1}とB={b0,b1,...,bm−1}を辞書式順で比較してください。

aoj.java
//数列問題だし数値を直接利用したいので標準入力をScannerでうけとる
//Aの要素数nとAの要素を受け取る
//Bの要素数mとBの要素を受け取る
//線形探索していく。要素をループで順に比較し、A[i] != B[i]になったときその大小を判定→A[i]<B[i]なら1,それ以外なら0を出力
import java.util.Scanner;
public class Main{
    public static void main(String[]args){
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int[]A = new int[n];
        for(int i=0;i<n;i++){
            A[i] = sc.nextInt();
        }
        int m = sc.nextInt();
        int[]B = new int[m];
        for(int i=0;i<m;i++){
            B[i] = sc.nextInt();
        }
        int minLen = Math.min(n,m);
        for(int i=0;i<minLen;i++){
            if(A[i] < B[i]){
                System.out.println(1);
                sc.close();
                return;
            }else if(A[i] > B[i]){
               System.out.println(0);
                sc.close();
                return; 
            }
        }
        if(n<m){
            System.out.println(1);
        }else{
            System.out.println(0);
        }
        sc.close();
    }
}
  • ループ回数を短い方の数列にあわせる→Math.minで要素数の小さいほうをループ回数に設定
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?