[DS+Algo] 001 先簡單說說算法


1. 通俗地講

  • 算法是解決計算問題的方法

2. 算法的五大特性

  1. 輸入總數 >= 0
  2. 輸出數量 >= 1
  3. 有窮性
  4. 確定性
  5. 可行性

3. 眾所周知的“公式”

程序 = 數據結構 + 算法

4. 舉個例子

例 1. 百錢買百雞

公雞,五錢一只;母雞,三錢一只;小雞,一錢三只。
一百錢買一百只雞,如何買?

1. 數學解法

解:設購買公雞 x 只,母雞 y 只,小雞 z 只

\[\left\{ \begin{aligned} x + y + z = 100 \\ 5x + 3y + \frac z3 = 100 \end{aligned} \right. \]

2. C 的解法

#include <stdio.h>

void buy_chicken();

int main() {
    buy_chicken();
    
    return 0;
}

void buy_chicken() {
    int cocks = -1, hens, chicks;
    while (cocks < 20) {
        cocks++;
        hens = -1;
        while (hens < 33) {
            hens++;
            chicks = 100 - cocks - hens;
            if (chicks % 3) {
                continue;
            }
            if (5*cocks + 3*hens + chicks/3 == 100) {
                printf("百錢可買公雞 %2d 只,母雞 %2d 只,小雞 %d 只\n", cocks, hens, chicks);
            }
        }
    }
}

3. Python 的解法

# coding:utf-8

def buy_chicken():
    for cocks in range(20):
        for hens in range(33):
            chicks = 100 - cocks - hens
            if chicks % 3 == 0 and 5*cocks + 3*hens + chicks//3 == 100:
                print(f"百錢可買公雞 {cocks:>2} 只,母雞 {hens:>2} 只,小雞 {chicks} 只")
    return None


if __name__ == "__main__":
    buy_chicken()

4. Java 解法

public class BaiJiwenti {
    public static void main(String[] args) {
        buy_chicken();
    }

    public static void buy_chicken() {
        for (int x=0; x<20; x++) {
            for (int y=0; y<33; y++) {
                int z = 100 - x - y;
                if (z % 3 == 0 && (5*x + 3*y + z/3 == 100 )) {
                    System.out.printf("百錢可買公雞 %2d 只,母雞 %2d 只,小雞 %d 只\n", x, y, z);
                }
            }
        }
    }
}

5. 小結

  • 對於“百雞問題”這一類甚至更多的問題,雖然不同語言的語法不盡相同,但解起來思路一致,關鍵幾句更是如出一轍

5. 算法衡量

  • 衡量算法應該剔除機器配置,運算數量等無關因素

5.1 有這樣兩個指標

  • 時間復雜度 T(n)
  • 空間復雜度 S(n)

5.2 大 O 記法

  • 對於單調的整數函數,如果存在一個整數函數 g 和實常數 c (c>0),使得對於充分大的 n 總有

    f(n) <= c * g(n)

    即函數 g 是 f 的一個漸進函數(忽略常數),記為 f(n) = O(g(n))
    即在趨向無窮的極限意義下,函數的增長速度受到函數 g 的約束
    即函數 f y與函數 g 的特征相似

5.3 時間復雜度及其他

5.3.1 定義

  • 假設存在函數 g,使得算法 A 處理規模為 n 的問題示例所用時間為 T(n) = O(g(n)),則稱 O(g(n)) 為算法 A 的漸進時間復雜度,簡稱時間復雜度,記為 T(n)

5.3.2 此外,還有

  1. 最優時間復雜度
  2. 最壞時間復雜度
  3. 平均時間復雜度
  • 一般關注最壞時間復雜度

5.3.3 時間復雜度計量規則

  • 基本操作,如只有常數項, 時間復雜度是 1
  • 順序結構,時間復雜度按加法計算
  • 循環結構,按乘法計算
  • 分支結構, 取最大值
  • 得到一個方程式,然后在做化簡,取方程的階

5.3.4 判斷一個算法的效率

  • 關注操作數量的最高次項,其余可忽略
  • 若沒特殊說明,我們所分析的算法時間復雜度一般指最壞的復雜度

5.3.5 其他

  • “大樣本統計方法”、“漸進等價”、“漸進展開”等數學概念我就略過了
  • 題外話:大家都知道“復”應該讀第四聲,但在這個短語中“復”讀第三聲超順;類似的還有“標志符”、“char”等

6. 舉例分析

# coding:utf-8

import sys
from time import perf_counter_ns


def cal_time(func):
    def in_():
        start = perf_counter_ns()
        name = func()
        stop = perf_counter_ns()
        print(f">>> {name}'s cost times: {stop - start}\n")
    return in_


@cal_time
def solve1():
    for cocks in range(101):
        for hens in range(101):
            for chicks in range(301):
                if cocks + hens + chicks == 100 \
                        and 5*cocks + 3*hens + chicks/3 == 100:
                    print(f"公雞 {cocks:>2} 只,母雞 {hens:>2} 只,小雞 {chicks} 只")
    return sys._getframe().f_code.co_name


@cal_time
def solve2():
    for cocks in range(20):
        for hens in range(33):
            chicks = 100 - cocks - hens
            if chicks % 3 == 0 and 5*cocks + 3*hens + chicks//3 == 100:
                print(f"公雞 {cocks:>2} 只,母雞 {hens:>2} 只,小雞 {chicks} 只")
    return sys._getframe().f_code.co_name


if __name__ == "__main__":
    solve1()
    solve2()
  • 不同的機子運算速度不同,但可以肯定的是 solve2() 比 solve1() 快,而且快挺多
  • 簡單地說,solve1() 的循環嵌套比 solve2() 的多一層,這就決定了它的時間復雜度要多一個冪次
    • solve1() 的 T(n) = O(mnk)
    • solve2() 的 T(n) = O(mn)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM