【一起刷LeetCode】在未排序的數組中找到第 k 個最大的元素


題目描述

在未排序的數組中找到第 k 個最大的元素。請注意,你需要找的是數組排序后的第 k 個最大的元素,而不是第 k 個不同的元素。

示例 1:

輸入: [3,2,1,5,6,4] 和 k = 2
輸出: 5

示例 2:

輸入: [3,2,3,1,2,4,5,5,6] 和 k = 4
輸出: 4

說明:

你可以假設 k 總是有效的,且 1 ≤ k ≤ 數組的長度。

題解

根據問題的描述其實我們很容易想到先排序再取第k個值, 這種方式也就是我們俗稱的暴力求解法。

暴力求解法

思路分析:

數組排序后的第k個最大元素,舉例說明一下:

數組一共有5個元素時,找第2大,索引值是3;找第4大,索引值是1;根據這個邏輯我們可以推導出,數組升序排序以后,結果元素的索引值是數組長度減去k的值

代碼示例:

public static int findKthLargest(int[] nums, int k) {
  int len = nums.length;
  Arrays.sort(nums);
  return nums[len - k];
}

復雜度分析:

  • 時間復雜度:O(N log N), 這里直接使用Arrays.sort(nums);將數據排序,大家都知道jdk默認使用的是快速排序,快速排序的平均時間復雜度是O(N log N)
  • 空間復雜度:O(1),因為是原地排序,沒有用到外部輔助空間。

暴力求解法(升級版)

思路分析:

根據暴力求解法中用的快排思路,其實我可以對快排做近一步升級,首先我們隨機選擇一個元素,並在線性時間內找到其對應在數組中的位置,這樣數組就被分成了兩部分,一部分是小於元素值的部分,一部分是大於元素值的部分,這時我們在比較這個元素與k的大小來決定我們在那一部分數組繼續做快速排序。這種思路其實就是快速排序中partition(切分)的操作。

每次partition操作總能排定一個元素,還能夠知道這個元素它在數組中的最終位置,然后我們在根據partition后的結果來減少范圍,這樣的思想叫做“減而治之”。

代碼示例:

public static int findKthLargest(int[] nums, int k) {
    int leng = nums.length;
    int left = 0;
    int right = leng - 1;
    int target = leng - k;
    return quickSelect(nums, left, right, target);
}

/**
  * 排序
  * @param nums
  * @param left
  * @param right
  * @param target
  * @return
  */
public static int quickSelect(int[] nums, int left, int right, int target) {
    if (left == right) {
      return nums[left];
    }
    //隨機選擇一個
    Random random = new Random();
    int pivot = left + random.nextInt(right - left);

    pivot = partition(nums, left, right, pivot);
    if (target == pivot) {
      return nums[target];
    }
    if (target < pivot) {
      return quickSelect(nums, left, pivot - 1, target);
    }
    return quickSelect(nums, pivot + 1, right, target);
}

/**
  * partition切分
  * @param nums
  * @param left
  * @param right
  * @param target
  * @return
  */
private static int partition(int[] nums, int left, int right, int target) {
    int pivot = nums[target];
    swap(nums, target, right);
    int j = left;
    for (int i = left; i <= right; i++) {
      if (nums[i] < pivot) {
        swap(nums, j, i);
        j++;
      }
    }
    swap(nums, j, right);
    return j;
}

/**
  * 交換
  * @param nums
  * @param a
  * @param b
  */
public static void swap(int[] nums, int a, int b) {
    int temp = nums[a];
    nums[a] = nums[b];
    nums[b] = temp;
}

復雜度分析:

  • 時間復雜度:平均情況O(N), 最壞情況O($N^2$).
  • 空間復雜度:O(1).

  • 寫作不易,轉載請注明出處,喜歡的小伙伴可以關注公眾號查看更多喜歡的文章。
  • 聯系方式:4272231@163.com
  • QQ:95472323
  • 微信:ffj2000


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM