學習算法第一天:算法初步

一、學習算法必要性why:

應用:機器學習、數據挖掘、自然語言處理、密碼學、計算機圖形學等

找工作:貪心、分治、動態規劃、樹、圖等.

二、怎麼做how?

  • 窮舉法(萬能算法)

求N個數的全排列

8皇后問題

  • 分而治之(減而治之)

二分查找——減而治之

歸併排序——分而治之

  • 貪心

最小生成樹 Prim, Kruskal

單源最短路 Dijkstra

  • 動態規劃

揹包

士兵路徑

三、時間、空間複雜度

常見時間複雜度分析方法

  • 數循環次數
  • 均攤分析
  • 遞歸式——主定理

• O(1)   基本運算,+,-,*,/,%,尋址

• O(logn)   二分查找

• O(n1/2)   枚舉約數

• O(n)    線性查找

• O(n^{2})    樸素最近點對

• O(n3)    Floyd最短路、普通矩陣乘法

• O(nlogn)    歸併排序、快速排序的期望複雜度、基於比較排序的算法下界

• O(2n)   枚舉全部的子集

• O(n!)    枚舉全排列

• 總結:

優秀 O(1) < O(logn) < O(n1/2) < O(n) < O(nlogn)

可能可以優化 O(n^{2}) < O(n^{3}) < O(2^{n}) < O(n!)

證明:O(nlogn)是基於比較的算法時間複雜度的下限

因爲排序就是排列組合中的一種,總的組合次數是n!種,每一次比較如i<j即可排除一半的組合,

所以當比較了k次,即2^{k}>n! 所以k>ln(n!)     ln(n!) < ln(n^{n})  所以k> nln(n) 所以O(nlogn)是下限

四、時間複雜度的均攤分析

  • 多個操作,一起算時間複雜度,MULTIPOP的隊列,可以一次性出隊k個元素,每個元素只出入隊列一次
  • 動態數組尾部插入操作(vector)一旦元素超過容量限制,則擴大一倍,再複製原來的數組,再釋放原數組空間

所以vector當插入n個元素時,可能發生複製的次數是1+2+4+8+.....+2^{logn} 次 = 2*2^{logn}-1次=O(2n)   所以插入n個數時間複雜度是 O(n);所以插入一個元素的時間複雜度是O(1),所以vector特別快,值得學習。

五、例題1:

• 給定數組a[1…n],求最大子數組和,即找出1<=i<=j<=n,使a[i]+a[i+1]+…+a[ j]最大,LeetCode第53題,最大子序和

• 介紹三個算法

  1. 暴力枚舉 O(n3)
  2. 優化枚舉 O(n2)
  3. 貪心法 O(n)

要求:手寫暴力枚舉算法必須會;暴力枚舉:三重循環,時間複雜度 O(n3) 附加空間複雜度 O(1)

for i = 1 to n

     for j = i to n

         sum = a[i]+..+a[j]

         ans =max(ans, sum)


class Solution {
    public int maxSubArray(int[] nums) {
        int n = nums.length;
        int ans = nums[0];
        for(int i = 0; i < n; ++i){
            for(int j = i; j < n; ++j){
                int sum = 0;
                for(int k = i; k <= j; ++k){
                    sum += nums[k];
                    if(sum > ans){
                        ans = sum;
                    }
                }
            }
        }
        return ans;
    }
}

重點:優化過程就是解決重複計算的過程上述存在i...j的求和與i....j,j+1的求和,存在i...j求和的重複,所以i....j,j+1 = sum(i....j) + nums[j]即可,提前記錄sum(i....j)和,優化如下

優化枚舉:兩重循環

for i = 1 to n

    sum = 0

    for j = i to n

        sum = sum + a[i]

        ans = max(ans, sum)

時間複雜度 O(n2) 附加空間複雜度 O(1) 

class Solution {
    public int maxSubArray(int[] nums) {
        int n = nums.length;
        int ans = nums[0];
        for(int i = 0; i < n; ++i){
            int sum = 0;
            for(int j = i; j < n; ++j){
                sum += nums[j];
                if(sum >= ans){
                    ans = sum;
                }
            }
        }
        return ans;
    }
}

貪心法:一重循環

sum = 0 ans = 0

for i = 1 to n

    sum = sum + a[i]

    ans = max(sum, ans)

    if (sum < 0) sum = 0

時間複雜度 O(n) 附加空間複雜度 O(1)

class Solution {
    public int maxSubArray(int[] nums) {
        int ans = nums[0];
        int sum = 0;
        int n=nums.length;
        for(int i=0; i< n; i++){
            sum += nums[i];
            if(sum > ans){
                ans = sum;
            }
            if(sum < 0){
                sum = 0;
            }
        }
        return ans;
    }
}

例題2:設計一個隊列;支持:出隊,入隊,求最大元素;要求O(1);均攤分析

例題3:給定一個正整數組a,是否能以3個數爲邊長構成三角形?即是否存在不同的i,j,k,

• 滿足 a[i] < a[ j] + a[k]

• 並且 a[ j] < a[i] + a[k]

• 並且 a[k] < a[i] + a[ j]

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章