日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【算法】线性时间选择——第k大(小)元素问题

發布時間:2023/12/9 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【算法】线性时间选择——第k大(小)元素问题 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

  • 前言
  • 分治算法之第k小元素
  • 分治算法之第k大元素


前言

  • 問題:給定線性序列中 n 個元素和一個整數 k ,1 ≤ k ≤ n,要求找出元素中的第 k 小的元素 或者 第 k 大元素,要求是線性時間算法,即時間復雜度為O( n )。
  • 需要用到快速排序的分區思想,有關分治法思想和快速排序文章:【算法】分治算法
  • 分治算法之第k小元素

  • 問題:給定線性序列中 n 個元素和一個整數 k ,1 ≤ k ≤ n,要求找出元素中的第 k 小的元素 ,要求是線性時間算法,即時間復雜度為O( n )。
  • 設計思想:
    (1)隨機選擇序列中第 i 個作為基準元素,統計比基準元素小的元素個數, 如果 個數 比 k 小,說明我們要找的第 k 小元素在基準后半部分,個數比 k 大,說明在前半部分。
    (2)對于無序序列a[s…t],在其中查找第k小元素的過程:
    • 若s=t,即其中只有一個元素,返回a[s]
    • 若s!=t,表示該序列中有兩個或兩個以上元素,以基準為中心將其劃分為a[s…i]和a[i+1…t],a[s…i]中所有元素均小于等于a[i],a[i+1…t]中所有元素均大于a[i]

    j = i-s+1,統計小于等于a[i]的元素個數
    j>=k,第k小元素在a[s…i]中,遞歸在a[s…i]中尋找第k小元素
    j < k,第k小元素在a[i+1…t]中,遞歸在a[i+1…t]中尋找第k-j小元素

    public class Demo {public static void main(String[] args) {int[] arr={3,1,5,7,8,2,9};System.out.println(randomizedSelect(arr, 0, arr.length - 1, 4));}public static int randomizedSelect(int[] a,int s,int t,int k){//a[s,t]//s == t ==>說明只有一個元素, 輸出if (s == t){return a[s];}//s < t 二個或二個元素以上//找到基準i 的位置int i = randomizedPartition(a,s,t);//小于等于 基準的個數int j = i - s + 1;//k <= j 說明第k小的元素在 前半部分a[s,i] 反之在后半部分a[i+1,t]if (j >= k){return randomizedSelect(a,s,i,k);}else {return randomizedSelect(a,i+1,t,k-j);}}//隨機產生一個基準的下標===》與第1個元素交換===》分區public static int randomizedPartition(int[] a,int p,int q){//a[p,q]int r = random(p,q);swap(a,r,p);int i = partition(a, p, q);return i;}/*** 以第一個元素為基準 分區* @param a 數組a* @param p a[p,q]* @param q a[p,q]* @return 分區后基準下標i a[p,i]和a[i+1,q]*/public static int partition(int[] a,int p,int q){int x = a[p];int i = p;for (int j = p; j <= q; j++) {if (a[j] < x){i++;swap(a,i,j);}}swap(a,p,i);return i;}/*** 數組交換函數* @param a 數組a* @param p 下標p* @param q 下標q*/public static void swap(int[] a,int p,int q){int t = a[p];a[p] = a[q];a[q] = t;}/*** 產生一個[p,q]的隨機數* @param p [p,q]* @param q [p,q]* @return [p,q]的隨機數*/public static int random(int p,int q){Random random = new Random();return Math.abs(random.nextInt())%(q-p+1) + p;}}
  • 時間復雜度分析
  • 一個無序數列隨機找到一個下標作為基準,每次分區,數列減少一部分,因為每次可以確定第 k 小元素是在基準的前半部分,還是后半部分,如果確定在前半部分,后半部分的數就不需要管了,
    T(n)=T(n/b)+O(n)=O(n)

    分治算法之第k大元素

    在前面那個算法改成比基準大的元素放在前半部分,小的放在后半部分即可。

    public class Demo {public static void main(String[] args) {int[] arr={3,1,5,7,8,2,9};System.out.println(randomizedSelect(arr, 0, arr.length - 1, 1));}public static int randomizedSelect(int[] a,int s,int t,int k){//a[s,t]//s == t ==>說明只有一個元素, 輸出if (s == t){return a[s];}//s < t 二個或二個元素以上//找到基準i 的位置int i = randomizedPartition(a,s,t);//大于等于 基準的個數int j = i - s + 1;//k <= j 說明第k大的元素在 前半部分a[s,i] 反之在后半部分a[i+1,t]if (j >= k){return randomizedSelect(a,s,i,k);}else {return randomizedSelect(a,i+1,t,k-j);}}//隨機產生一個基準的下標===》與第1個元素交換===》分區public static int randomizedPartition(int[] a,int p,int q){//a[p,q]int r = random(p,q);swap(a,r,p);int i = partition(a, p, q);return i;}/*** 以第一個元素為基準 分區* @param a 數組a* @param p a[p,q]* @param q a[p,q]* @return 分區后基準下標i a[p,i]和a[i+1,q]*/public static int partition(int[] a,int p,int q){int x = a[p];int i = p;for (int j = p; j <= q; j++) {if (a[j] > x){i++;swap(a,i,j);}}swap(a,p,i);return i;}/*** 數組交換函數* @param a 數組a* @param p 下標p* @param q 下標q*/public static void swap(int[] a,int p,int q){int t = a[p];a[p] = a[q];a[q] = t;}/*** 產生一個[p,q]的隨機數* @param p [p,q]* @param q [p,q]* @return [p,q]的隨機數*/public static int random(int p,int q){Random random = new Random();return Math.abs(random.nextInt())%(q-p+1) + p;}}

    總結

    以上是生活随笔為你收集整理的【算法】线性时间选择——第k大(小)元素问题的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。