數據結構與算法_渡劫2

  • 正在學習的算法課程:極客時間的王爭老師的《數據結構與算法之美》
  • 傳送門: https://time.geekbang.org/column/126
  • 目前學到第三講,很良心,共56講,推薦想學數據結構的同學
  • 以下爲學習筆記,最近忙着寫論文,今天差不多完成了初稿了,爭取日更
  • 2019/09/22

一、時間複雜度影響因素

  1. 測試環境
  2. 數據級規模大小

二、時間複雜度概念 - 大O

帶着問題學習


Q1. 以下代碼的執行時間爲?

 int cal(int n) {
   int sum = 0;
   int i = 1;
   for (; i <= n; ++i) {
     sum = sum + i;
   }
   return sum;
 }

A: 總共:1 + 1 + n + n = 2n +2


Q2. 以下代碼的執行時間爲?

 int cal(int n) {
   int sum = 0;
   int i = 1;
   int j = 1;
   for (; i <= n; ++i) {
     j = 1;
     for (; j <= n; ++j) {
       sum = sum + i * j;
     }
   }
 }

A:1+1+1+n+n+n2+n2=2n2+2n+21 + 1 + 1 + n + n + n^2 + n^2 =2n^2 + 2n +2
結論: ** 所有代碼執行時間T(n)與每行代碼的執行次數成正比 **


1. 概念

T(n)=O(f(n)) T(n) = O(f(n))
大O: 其中,n是數據規模的大小。代碼的執行時間T(n)和每一行代碼的執行時間f(n)成正比,表示代碼執行時間隨着數據集數據規模增長的變化趨勢,全名叫做時間漸進複雜度,簡稱時間複雜度( 只保留最高階)

2. 時間複雜度技巧分析

  • 只關注循環次數做的一段代碼
 int cal(int n) {
   int sum = 0;
   int i = 1;
   for (; i <= n; ++i) {
     sum = sum + i;
   }
   return sum;
 }

時間複雜度:O(n)

  • 加法法則,只保留最大量級
int cal(int n) {
   int sum_1 = 0;
   int p = 1;
   for (; p < 100; ++p) {
     sum_1 = sum_1 + p;
   }

   int sum_2 = 0;
   int q = 1;
   for (; q < n; ++q) {
     sum_2 = sum_2 + q;
   }
 
   int sum_3 = 0;
   int i = 1;
   int j = 1;
   for (; i <= n; ++i) {
     j = 1; 
     for (; j <= n; ++j) {
       sum_3 = sum_3 + i * j;
     }
   }
 
   return sum_1 + sum_2 + sum_3;
 }

時間複雜度:O(1+n+n2)=O(n2)O(1+n+n^2)=O(n^2)

  • 乘法法則:嵌套代碼的複雜度爲嵌套內外代碼複雜度的乘積
int cal(int n) {
   int ret = 0; 
   int i = 1;
   for (; i < n; ++i) {
     ret = ret + f(i);
   } 
 } 
 
 int f(int n) {
  int sum = 0;
  int i = 1;
  for (; i < n; ++i) {
    sum = sum + i;
  } 
  return sum;
 }

時間複雜度:O(n2)O(n^2)

3. 幾種常見時間複雜度

  • O(1)
    代碼運算爲常量級的時間複雜度,與數據規模n無關,均爲O(1)
 int i = 8;
 int j = 6;
 int sum = i + j;
  • O(logn)、O(nlogn)
    通過代碼來解析O(logn),看如下代碼:
 i=1;
 while (i <= n) {
   i = i * 2;
 }

上述代碼的時間複雜度即爲第三行代碼計算所需的時間,第三行代碼計算時間所需如下:

轉換成了求x的值,x=log2(n)x = log_{2}(n) ,那麼O(nlogn)O(nlogn)即爲在複雜度x=log(n)x = log(n)外面嵌套一層時間複雜度爲n的代碼

Ps: 不管對數底爲幾,統記爲log(n)log(n),可以這麼記的原因是對數的相互轉換公式

  • O(m+n)、O(m*n)
    看代碼解析,代碼如下:
int cal(int m, int n) {
  int sum_1 = 0;
  int i = 1;
  for (; i < m; ++i) {
    sum_1 = sum_1 + i;
  }

  int sum_2 = 0;
  int j = 1;
  for (; j < n; ++j) {
    sum_2 = sum_2 + j;
  }

  return sum_1 + sum_2;
}

m和n是兩個數據集的規模大小,m和n的誰大誰小未知,因此時間複雜度爲O(m+n)

三、空間複雜度分析

1. 概念

時間複雜度的全稱是漸進時間複雜度,表示算法的執行時間與數據規模之間的增長關係;
空間複雜度的全稱是漸進空間複雜度,表示算法的存儲空間和數據規模之間的增長關係

2. 代碼分析 & 常用的空間複雜度

先上代碼:

void print(int n) {
  int i = 0;
  int[] a = new int[n];
  for (i; i <n; ++i) {
    a[i] = i * i;
  }

  for (i = n-1; i >= 0; --i) {
    print out a[i]
  }
}

看第三行代碼,申請了一個大小爲n的int型數據,之後的代碼都是在該數據中操作,並沒有改變大小,因此上述代碼的空間複雜度爲O(n)


  • 平時常用的空間複雜度:O(1)、O(n)、O(n2)O(n^2),很少用到對數的複雜度

四、小結

  1. 從低階到高階的複雜度:O(1)、O(logn)、O(n)、O(nlogn)、O(n2)O(n^2)
  2. 課後代碼實現題(2019年地平線浙大秋招現場編程題)

給定一個數組,一開始順序從小變大,接着到達某個值之後,順序從大變小,請設計一個複雜度爲O(logn)的算法,找到這個最大值

update:2019/09/23

# coding=utf-8
'''
@ Summary: 給定一個數組,一開始順序從小變大,接着到達某個值之後,順序從大變小,請設計一個複雜
           度爲O(logn)的算法,找到這個最大值
           思路: 判斷中點,舍掉左邊或者右邊,遞歸
@ Update:  

@ file:    O(nlogn).py
@ version: 1.0.0

@ Author:  [email protected]
@ Date:    19-9-23 下午6:05
'''

def local_maximum(l):
    if not l:
        return None

    if len(l) == 1:
        return l[0]
    else:
        mid = int(len(l)/2)
        l = l[:mid+1] if l[mid] >= l[mid+1] else l[mid+1:]
        return local_maximum(l)

if __name__ == "__main__":

    # import sys
    # _list = list(map(int, sys.stdin.readline().strip().split()))

    _list = [1, 2, 3, 4, 3, 2]
    result = local_maximum(_list)
    print(result)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章