劍指offer40_最小的k個數-(java) 多解法

面試題40. 最小的k個數

注意leetcode和牛客網的區別!!!! 返回值的類型不一致;

題目

輸入n個整數,找出其中最小的K個數。例如輸入4,5,1,6,2,7,3,8這8個數字,則最小的4個數字是1,2,3,4,。

思路1 — 直接調用排序算法!!!

Array.sort(int[] a);其實現也是快速排序~

import java.util.ArrayList;
import java.util.Arrays;
public class Solution {
    // 注意 牛客網中該題是返回AyyayList類,leetcode中返回的是數組int[];
    public ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) {
        ArrayList<Integer> list = new ArrayList<>();
        if(k > input.length) {
            return list;  // 注意邊界,此題k大於數組長度時,返回空的ArrayList<Integer>
        }else{
            Arrays.sort(input);// O(nlogn);
            for(int i = 0; i < k; i++){
                list.add(input[i]);
            }
            return list;
        }
    }
}

Array.sort()使用注意:
若是基本類型,需要轉化爲對應的對象類型(如:int轉化爲Integer)Arrays.sort()可以排序基本對象類型,但是不可以使用基本數據類型。
Arrays.sort()默認的是升序排序,降序排序可採用Collection.sort()匿名內部類。
數組與list一樣,需要遍歷出來

思路2 — 優化 快速排序~~

  • 空間複雜度 O(1),不需要額外空間。
  • 時間複雜度:和快速排序類似。由於快速選擇只需要遞歸一邊的數組,時間複雜度小於快速排序,期望時間複雜度爲 O(n),最壞情況下的時間複雜度爲 O(n^2)
import java.util.ArrayList;
import java.util.Arrays;
public class Solution {
    // 注意 牛客網中該題是返回AyyayList類,leetcode中返回的是數組int[];
    public ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) {
        ArrayList<Integer> li = new ArrayList<Integer>();
        //哭暈系列!!! 注意邊界條件~~~~~
        if(input.length == 0 || k > input.length || k == 0 || input == null ){
            return li;
        }else{
            int[] sort =  quickSelected(input, 0, input.length-1, k-1);
            for(int i = 0; i < k; i++){
                li.add(sort[i]);
            }
            return li; 
        }
        
    }
    

    public int[] quickSelected(int[] arr, int low, int high, int k){
        int j = quickSort(arr, low, high);
        // 只要切分位置剛好等於k,則切分位置左邊的就是滿足條件的最小的k個數
        if(j == k){
            return arr;
        }    
        // 如果切分位置大於k值,代表需要減小左邊的切分區間,繼續從左邊找最小的k個數。
        if(j > k){
            return quickSelected(arr, low, j-1, k);
        }
        // 如果切分位置小於k,說明右邊還要繼續從小到大的排序。
        return quickSelected(arr, j+1, high, k);
    }
        
    // 快排切分, 每次切分都把比基數大的放在基數的右邊,比基數小的放在技術左邊。返回基數的切分位置。
    public int quickSort(int[] arr, int low, int high){
        int key = arr[low];
        int i = low;
        int j = high;
        while(i < j){
            while(key <= arr[j] && i < j){
                j--;
            }
            while(key >= arr[i] && i < j){
                i++;
            }
            if(i < j){
                int temp = arr[i];
                arr[i] = arr[j];
                arr[j] = temp;
            }
        }
        arr[low] = arr[j];
        arr[j] = key;
        return j;
    }
}

思路3 —大根堆~~

注意: 需要掌握queue數據結構, 以及PriorityQueue優先隊列(通過二叉小頂堆實現),優先隊列的作用是能保證每次取出的元素都是隊列中權值最小的(Java的優先隊列每次取最小元素,C++的優先隊列每次取最大元素)


import java.util.ArrayList;
import java.util.Arrays;
import java.util.Queue;
import java.util.PriorityQueue;
public class Solution {
    // 注意 牛客網中該題是返回AyyayList類,leetcode中返回的是數組int[];
    public ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) {
        ArrayList<Integer> li = new ArrayList<Integer>();
        if(input.length < k || k == 0){
            return li;
        }
        
        Queue<Integer> heap = new PriorityQueue<>(k, (v1, v2) -> Integer.compare(v2, v1));
        
        for(int num: input){
            if(heap.isEmpty() || heap.size() < k || num < heap.peek()){
                heap.offer(num);
            }
            if(heap.size() > k){
                heap.poll();
            }
        }
        
        for(int e: heap){
            li.add(e);
        }
        return li;
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章