題目描述

給定一個擁有奇數數量元素的陣列,你能夠在陣列整個排序好之前就找出它的中位數(中間值)嗎?



原題網址

https://www.hackerrank.com/challenges/find-the-median/

輸入格式

輸入第一行為一個整數n,且為奇數,範圍在1到1000001之間(包含1和1000001)。

第二行為n個用空格分隔的整數,範圍在-10000到10000之間(包含-10000和10000),不會重複。

輸出格式

輸出只會有一個整數,那就是這個陣列的中位數。

範例輸入

7
0 1 2 4 6 5 3

範例輸出

3

解題概念

參考這篇文章,學習快速選擇法:

https://magiclen.org/quickselect/

由於輸入的陣列元素皆不重複,因此中位數的元素索引位置即為陣列長度的一半。也就是說,利用快速選擇演算法,找出第「陣列長度一半」小的元素,就是題目要的輸出結果了。

參考答案

import java.io.*;
import java.math.*;
import java.security.*;
import java.text.*;
import java.util.*;
import java.util.concurrent.*;
import java.util.regex.*;

public class Solution {

    // Complete the findMedian function below.
    static int findMedian(int[] arr) {
        int index = arr.length / 2;
        int s = 0;
        int e = arr.length - 1;
        while (true) {
            if (s == e) {
                return arr[s];
            }
            final int x = arr[s]; // pivot
            int l = s + 1;
            int r = e;
            while (true) {
                while (r > s && arr[r] >= x) {
                    --r;
                }
                while (l <= r && arr[l] <= x) {
                    ++l;
                }
                if (l < r) {
                    final int buffer = arr[l];
                    arr[l] = arr[r];
                    arr[r] = buffer;
                } else {
                    if (r > s) {
                        final int buffer = arr[r];
                        arr[r] = arr[s];
                        arr[s] = buffer;
                    }
                    break;
                }
            }

            if (index == r) {
                return arr[index];
            } else if (index < r) {
                e = r - 1;
            } else {
                s = r + 1;
            }
        }
    }

    private static final Scanner scanner = new Scanner(System.in);

    public static void main(String[] args) throws IOException {
        BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(System.getenv("OUTPUT_PATH")));

        int n = scanner.nextInt();
        scanner.skip("(\r\n|[\n\r\u2028\u2029\u0085])?");
        System.out.println(n);

        int[] arr = new int[n];

        String[] arrItems = scanner.nextLine().split(" ");
        scanner.skip("(\r\n|[\n\r\u2028\u2029\u0085])?");

        for (int i = 0; i < n; i++) {
            int arrItem = Integer.parseInt(arrItems[i]);
            arr[i] = arrItem;
            System.out.println(i);
        }

        int result = findMedian(arr);

        bufferedWriter.write(String.valueOf(result));
        bufferedWriter.newLine();

        bufferedWriter.close();
        scanner.close();
    }
}