偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

拜托,面試別再問(wèn)我時(shí)間復(fù)雜度了?。?!

開(kāi)發(fā) 開(kāi)發(fā)工具
最煩面試官問(wèn),“為什么XX算法的時(shí)間復(fù)雜度是OO”,看完這篇文章,今后,不再懼怕這類問(wèn)題。

最煩面試官問(wèn),“為什么XX算法的時(shí)間復(fù)雜度是OO”,今后,不再懼怕這類問(wèn)題。

[[248676]]

快速排序分為這么幾步:

***步,先做一次partition;

partition使用***個(gè)元素t=arr[low]為哨兵,把數(shù)組分成了兩個(gè)半?yún)^(qū):

  • 左半?yún)^(qū)比t大
  • 右半?yún)^(qū)比t小

第二步,左半?yún)^(qū)遞歸;

第三步,右半?yún)^(qū)遞歸;

偽代碼為:

  1. void quick_sort(int[]arr, int low, int high){ 
  2.          if(low== high) return; 
  3.          int i = partition(arr, low, high); 
  4.          quick_sort(arr, low, i-1); 
  5.          quick_sort(arr, i+1, high); 

為啥,快速排序,時(shí)間復(fù)雜度是O(n*lg(n))呢?

今天和大家聊聊時(shí)間復(fù)雜度。

畫(huà)外音:往下看,第三類方法很牛逼。

***大類,簡(jiǎn)單規(guī)則

為方便記憶,先總結(jié)幾條簡(jiǎn)單規(guī)則,熱熱身。

(1) 規(guī)則一:“有限次操作”的時(shí)間復(fù)雜度往往是O(1)。

例子:交換兩個(gè)數(shù)a和b的值。

  1. void swap(int& a, int& b){ 
  2.          int t=a
  3.          a=b
  4.          b=t

分析:通過(guò)了一個(gè)中間變量t,進(jìn)行了3次操作,交換了a和b的值,swap的時(shí)間復(fù)雜度是O(1)。

畫(huà)外音:這里的有限次操作,是指不隨數(shù)據(jù)量的增加,操作次數(shù)增加。

(2) 規(guī)則二:“for循環(huán)”的時(shí)間復(fù)雜度往往是O(n)。

例子:n個(gè)數(shù)中找到***值。

  1. int max(int[] arr, int n){ 
  2.          int temp = -MAX; 
  3.          for(int i=0;i<n;++i) 
  4.                    if(arr[i]>temp) temp=arr[i]; 
  5.          return temp; 
  6.   

分析:通過(guò)一個(gè)for循環(huán),將數(shù)據(jù)集遍歷,每次遍歷,都只執(zhí)行“有限次操作”,計(jì)算的總次數(shù),和輸入數(shù)據(jù)量n呈線性關(guān)系。

(3) 規(guī)則三:“樹(shù)的高度”的時(shí)間復(fù)雜度往往是O(lg(n))。

分析:樹(shù)的總節(jié)點(diǎn)個(gè)數(shù)是n,則樹(shù)的高度是lg(n)。

在一棵包含n個(gè)元素二分查找樹(shù)上進(jìn)行二分查找,其時(shí)間復(fù)雜度是O(lg(n))。

對(duì)一個(gè)包含n個(gè)元素的堆頂元素彈出后,調(diào)整成一個(gè)新的堆,其時(shí)間復(fù)雜度也是O(lg(n))。

第二大類:組合規(guī)則

通過(guò)簡(jiǎn)單規(guī)則的時(shí)間復(fù)雜度,來(lái)求解組合規(guī)則的時(shí)間復(fù)雜度。

例如:n個(gè)數(shù)冒泡排序。

  1. void bubble_sort(int[] arr, int n){ 
  2.    for(int i=0;i<n;i++) 
  3.        for(int j=0;j<n-i-1;j++) 
  4.            if(arr[j]>arr[j+1]) 
  5.                 swap(arr[j], arr[j+1]); 

分析:冒泡排序,可以看成三個(gè)規(guī)則的組合:

  • 外層for循環(huán)
  • 內(nèi)層for循環(huán)
  • 最內(nèi)層的swap

故,冒泡排序的時(shí)間復(fù)雜度為:

  1. O(n) * O(n) * O(1) = O(n^2) 

又例如:TopK問(wèn)題,通過(guò)建立k元素的堆,來(lái)從n個(gè)數(shù)中求解***的k個(gè)數(shù)。

先用前k個(gè)元素生成一個(gè)小頂堆,這個(gè)小頂堆用于存儲(chǔ),當(dāng)前***的k個(gè)元素。

接著,從第k+1個(gè)元素開(kāi)始掃描,和堆頂(堆中最小的元素)比較,如果被掃描的元素大于堆頂,則替換堆頂?shù)脑?,并調(diào)整堆,以保證堆內(nèi)的k個(gè)元素,總是當(dāng)前***的k個(gè)元素。

直到,掃描完所有n-k個(gè)元素,最終堆中的k個(gè)元素,就是為所求的TopK。

偽代碼:

  1. heap[k] = make_heap(arr[1, k]); 
  2. for(i=k+1 to n){ 
  3.          adjust_heap(heep[k],arr[i]); 
  4. return heap[k]; 

分析:可以看成三個(gè)規(guī)則的組合:

  • 新建堆
  • for循環(huán)
  • 調(diào)整堆

故,用堆求解TopK,時(shí)間復(fù)雜度為:

  1. O(k) + O(n) * O(lg(k)) = O(n*lg(k)) 

畫(huà)外音:注意哪些地方用加,哪些地方用乘;哪些地方是n,哪些地方是k。

第三大類,遞歸求解

簡(jiǎn)單規(guī)則和組合規(guī)則可以用來(lái)求解非遞歸的算法的時(shí)間復(fù)雜度。對(duì)于遞歸的算法,該怎么分析呢?

接下來(lái),通過(guò)幾個(gè)案例,來(lái)說(shuō)明如何通分析遞歸式,來(lái)分析遞歸算法的時(shí)間復(fù)雜度。

(1) 案例一:計(jì)算 1到n的和,時(shí)間復(fù)雜度分析。

如果用非遞歸的算法:

  1. int sum(int n){ 
  2.          int result=0
  3.          for(int i=0;i<n;i++) 
  4.                    result += i; 
  5.          return result; 

根據(jù)簡(jiǎn)單規(guī)則,for循環(huán),sum的時(shí)間復(fù)雜度是O(n)。

但如果是遞歸算法,就沒(méi)有這么直觀了:

  1. int sum(int n){ 
  2.          if (n==1) return 1; 
  3.          return n+sum(n-1); 

如何來(lái)進(jìn)行時(shí)間復(fù)雜度分析呢?

用f(n)來(lái)表示數(shù)據(jù)量為n時(shí),算法的計(jì)算次數(shù),很容易知道:

  • 當(dāng)n=1時(shí),sum函數(shù)只計(jì)算1次

畫(huà)外音:if (n==1) return 1;

即:

  1. f(1)=1【式子A】 
  • 不難發(fā)現(xiàn),當(dāng)n不等于1時(shí):

f(n)的計(jì)算次數(shù),等于f(n-1)的計(jì)算次數(shù),再加1次計(jì)算

畫(huà)外音:return n+sum(n-1);

即:

  1. f(n)=f(n-1)+1【式子B】 

【式子B】不斷的展開(kāi),再配合【式子A】:

畫(huà)外音:這一句話,是分析這個(gè)算法的關(guān)鍵。

  1. f(n)=f(n-1)+1 
  2. f(n-1)=f(n-2)+1 
  3. … 
  4. f(2)=f(1)+1 
  5. f(1)=1 

上面共n個(gè)等式,左側(cè)和右側(cè)分別相加:

  1. f(n)+f(n-1)+…+f(2)+f(1) 
  2. [f(n-1)+1]+[f(n-2)+1]+…+[f(1)+1]+[1] 

即得到:

  1. f(n)=n 

已經(jīng)有那么點(diǎn)意思了哈,再來(lái)個(gè)復(fù)雜點(diǎn)的算法。

(2) 案例二:二分查找binary_search,時(shí)間復(fù)雜度分析。

  1. int BS(int[] arr, int low, int high, int target){ 
  2.          if (low>high) return -1; 
  3.          mid = (low+high)/2; 
  4.          if (arr[mid]== target) return mid; 
  5.          if (arr[mid]> target) 
  6.                   return BS(arr, low, mid-1, target); 
  7.          else 
  8.                   return BS(arr, mid+1, high, target); 

二分查找,單純從遞歸算法來(lái)分析,怎能知道其時(shí)間復(fù)雜度是O(lg(n))呢?

仍用f(n)來(lái)表示數(shù)據(jù)量為n時(shí),算法的計(jì)算次數(shù),很容易知道:

  • 當(dāng)n=1時(shí),bs函數(shù)只計(jì)算1次

畫(huà)外音:不用糾結(jié)是1次還是1.5次,還是2.7次,是一個(gè)常數(shù)次。

即:

  1. f(1)=1【式子A】 

在n很大時(shí),二分會(huì)進(jìn)行一次比較,然后進(jìn)行左側(cè)或者右側(cè)的遞歸,以減少一半的數(shù)據(jù)量:

  • f(n)的計(jì)算次數(shù),等于f(n/2)的計(jì)算次數(shù),再加1次計(jì)算

畫(huà)外音:計(jì)算arr[mid]>target,再減少一半數(shù)據(jù)量迭代

即:

  1. f(n)=f(n/2)+1【式子B】 

【式子B】不斷的展開(kāi),

  1. f(n)=f(n/2)+1 
  2. f(n/2)=f(n/4)+1 
  3. f(n/4)=f(n/8)+1 
  4. … 
  5. f(n/2^(m-1))=f(n/2^m)+1 

上面共m個(gè)等式,左側(cè)和右側(cè)分別相加:

  1. f(n)+f(n/2)+…+f(n/2^(m-1)) 
  2. [f(n/2)+1]+[f(n/4)+1]+…+[f(n/2^m)]+[1] 

即得到:

  1. f(n)=f(n/2^m)+m 

再配合【式子A】:

  1. f(1)=1 

即,n/2^m=1時(shí), f(n/2^m)=1, 此時(shí)m=lg(n), 這一步,這是分析這個(gè)算法的關(guān)鍵。

將m=lg(n)帶入,得到:

  1. f(n)=1+lg(n) 

神奇不神奇?

***,大boss,快速排序遞歸算法,時(shí)間復(fù)雜度的分析過(guò)程。

(3) 案例三:快速排序quick_sort,時(shí)間復(fù)雜度分析。

  1. void quick_sort(int[]arr, int low, inthigh){ 
  2.          if (low==high) return; 
  3.          int i = partition(arr, low, high); 
  4.          quick_sort(arr, low, i-1); 
  5.          quick_sort(arr, i+1, high); 

仍用f(n)來(lái)表示數(shù)據(jù)量為n時(shí),算法的計(jì)算次數(shù),很容易知道:

  • 當(dāng)n=1時(shí),quick_sort函數(shù)只計(jì)算1次

f(1)=1【式子A】

在n很大時(shí):

  • ***步,先做一次partition;
  • 第二步,左半?yún)^(qū)遞歸;
  • 第三步,右半?yún)^(qū)遞歸;

即:

  1. f(n)=n+f(n/2)+f(n/2)=n+2*f(n/2)【式子B】 

畫(huà)外音:

  • partition本質(zhì)是一個(gè)for,計(jì)算次數(shù)是n;
  • 二分查找只需要遞歸一個(gè)半?yún)^(qū),而快速排序左半?yún)^(qū)和右半?yún)^(qū)都要遞歸,這一點(diǎn)在分治法與減治法一章節(jié)已經(jīng)詳細(xì)講述過(guò);

【式子B】不斷的展開(kāi),

  1. f(n)=n+2*f(n/2) 
  2. f(n/2)=n/2+2*f(n/4) 
  3. f(n/4)=n/4+2*f(n/8) 
  4. … 
  5. f(n/2^(m-1))=n/2^(m-1)+2f(n/2^m) 

上面共m個(gè)等式,逐步帶入,于是得到:

  1. f(n)=n+2*f(n/2) 
  2. =n+2*[n/2+2*f(n/4)]=2n+4*f(n/4) 
  3. =2n+4*[n/4+2*f(n/8)]=3n+8f(n/8) 
  4. =… 
  5. =m*n+2^m*f(n/2^m) 

再配合【式子A】:

  1. f(1)=1 

即,n/2^m=1時(shí), f(n/2^m)=1, 此時(shí)m=lg(n), 這一步,這是分析這個(gè)算法的關(guān)鍵。

將m=lg(n)帶入,得到:

  1. f(n)=lg(n)*n+2^(lg(n))*f(1)=n*lg(n)+n 

故,快速排序的時(shí)間復(fù)雜度是n*lg(n)。

wacalei,有點(diǎn)意思哈!

畫(huà)外音:額,估計(jì)83%的同學(xué)沒(méi)有細(xì)究看,花5分鐘細(xì)思上述過(guò)程,一定有收獲。

總結(jié)

  • for循環(huán)的時(shí)間復(fù)雜度往往是O(n)
  • 樹(shù)的高度的時(shí)間復(fù)雜度往往是O(lg(n))
  • 二分查找的時(shí)間復(fù)雜度是O(lg(n)),快速排序的時(shí)間復(fù)雜度n*(lg(n))
  • 遞歸求解,未來(lái)再問(wèn)時(shí)間復(fù)雜度,通殺

知其然,知其所以然。

思路比結(jié)論重要。

【本文為51CTO專欄作者“58沈劍”原創(chuàng)稿件,轉(zhuǎn)載請(qǐng)聯(lián)系原作者】

戳這里,看該作者更多好文

責(zé)任編輯:趙寧寧 來(lái)源: 51CTO專欄
相關(guān)推薦

2018-09-28 05:25:53

TopK算法代碼

2018-11-01 13:49:23

桶排序排序面試

2018-10-28 22:37:00

計(jì)數(shù)排序排序面試

2019-04-16 13:30:05

表達(dá)式求值數(shù)據(jù)結(jié)構(gòu)算法

2020-04-22 11:19:07

貪心算法動(dòng)態(tài)規(guī)劃

2019-01-08 15:11:50

最大值最小值算法

2021-01-22 10:09:23

簡(jiǎn)歷求職者面試

2020-09-02 08:04:59

多線程互聯(lián)網(wǎng)高并發(fā)

2020-03-30 17:20:54

B+樹(shù)SQL索引

2022-03-14 10:14:43

底層系統(tǒng)Nacos

2018-11-09 09:34:05

面試Spring Clou底層

2020-04-16 08:22:11

HTTPS加解密協(xié)議

2020-12-11 09:24:19

Elasticsear存儲(chǔ)數(shù)據(jù)

2020-09-24 14:40:55

Python 開(kāi)發(fā)編程語(yǔ)言

2019-08-29 09:49:50

2015-02-13 10:42:31

前端工具Dreamweaver

2019-07-10 10:06:24

面試官三次握手四次揮手

2019-12-17 09:29:02

數(shù)據(jù)庫(kù)架構(gòu)分庫(kù)分表

2021-09-17 10:44:50

算法復(fù)雜度空間

2024-04-25 08:33:25

算法時(shí)間復(fù)雜度空間復(fù)雜度
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)