- 算法設計與分析之入門篇
- 跟着視頻學習,感覺這里面的主要算法很重要!
- 對很多經典的問題理解不夠。
復雜度分析
-
低階函數
-
同階函數
-
高階函數
-
master定理求解階數/迭代法求解具體的
遞歸方程
- 整數划分問題
將正整數n表示成一系列正整數之和,n=n1+n2+n3+......nk(其中,n1>=n2>=......nk>=1,k>=1),正整數n的這種表示稱為正整數n的划分。正整數n的不同划分個數稱為正整數n的划分數,記作p(n)。例如:正整數6有11總不同的划分
6;
5+1;
4+2,4+1+1;
3+3,3+2+1,3+1+1+1;
2+2+2,2+2+1+1,2+1+1+1+1;
1+1+1+1+1+1;
記q(n,m)為正整數n的所有不同划分中,最大加數n1不大於m的划分個數。可以建立如下遞推關系:
前面三個遞推式比較好理解,關鍵是第四個遞推式。當n>m>1時,n的划分由兩部分組成。以整數q(6,3)為例,q(n,m-1)內容是第5排和第6排內容,不大於2的6的划分;q(n-m,m)內容是第4排,不大於3的(6-3=3)的划分。
//2-4 整數划分問題
#include "stdafx.h"
#include <iostream>
using namespace std;
int q(int n,int m);
int main(){
cout<<q(6,6)<<endl;
return 0;
}
int q(int n,int m)
{
if( n<1 || m<1)
{
return 0;
}
else if(n==1 || m==1)
{
return 1;
}
else if(n<m)
{
return q(n,n);
}
else if(n==m)
{
return q(n,m-1) + 1;
}
else
{
return q(n,m-1) + q(n-m,m);
}
}
- 漢諾塔問題
- 古代有一個梵塔,塔內有三個座A、B、C,A座上有64個盤子,盤子大小不等,大的在下,小的在上。有一個和尚想把這64個盤子從A座移到B座,但每次只能允許移動一個盤子,並且在移動過程中,3個座上的盤子始終保持大盤在下,小盤在上。在移動過程中可以利用B座,要求輸出移動的步驟。
#include <iostream>
using namespace std;
void hanoi(int n, char a, char b, char c);
int main(){
char a = 'A', b = 'B', c = 'C';
hanoi(3, a, b, c);
return 0;
}
//借助c,將n個盤子從a移到b
void hanoi(int n, char a, char b, char c)
{
if (n > 0) //n等於1直接輸出
{
hanoi(n - 1, a, c, b);//借助b,將n-1個盤子從a移到c
cout << "將" << a << "中最大的盤子從" << a << "移到" << b << endl;
hanoi(n - 1, c, b, a);//借助a,將n-1個盤子從c移到b
}
}
分治法
- 設計過程分三階段:划分,求解,合並
- 自頂向下
- 大整數(二進制)乘法
- 最大值最小值問題(類似歸並算法)
- 中位數問題
- 從n個不同的數中選第i大的元素(線性時間)
- 快速傅里葉變換
動態規划
-
子問題相互獨立,若不是相互獨立,分治方法將重復計算公共子問題,效率低
-
自底向上
-
一類優化問題
-
使用動態規划的條件:優化子結構,重疊子問題
-
矩陣的乘法
-
0-1背包問題
-
動態規划方法可用的條件
- 優化子結構
- 子問題重疊性
- 子問題空間小
貪心法
-
求解最優化問題
-
每一步都有一組選擇,作出在當前看來最好的選擇
-
希望通過作出局部優化選擇達到全局優化選擇
-
貪心算法不一定總產生優化解
-
貪心算法是否產生優化解,需要嚴格證明
-
貪心算法產生優化解的條件是:
- 貪心選擇性
- 優化子結構(嚴格) -
任務安排問題
-
哈夫曼編碼問題(前綴碼-最優二叉樹)
搜索策略
-
暴力美學
- 轉換為樹搜索問題
-
深度優先和廣度優先
- 廣度優先-隊列實現
- 深度優先-棧實現
-
搜索的優化
- 爬山法(使用貪心方法確定搜索的方向)-局部優化
- Best-First搜索策略-全局優化-用堆實現
- 分支界限(可以有效地求解組合優化問題)(剪枝)-縮小解空間,加速搜索
-
八數碼難題(8 puzzle)(廣度優先)
-
求解子集和問題(深度優先)
-
哈密頓(Hamiltonian)環問題(深度優先)
字符串搜索
-
字符串匹配問題
- 計算匹配算法的復雜度
O(m*(n-m))
- 計算匹配算法的復雜度
-
Rabin-Karp
算法,指紋思路。如果兩個字符串hash后的值不相同,則它們肯定不相同;如果它們hash后的值相同,它們不一定相同。 -
RK算法的基本思想就是:將模式串P的hash值跟主串S中的每一個長度為|P|的子串的hash值比較。如果不同,則它們肯定不相等;如果相同,則再諸位比較之。
-
補充Horner算法
KMP算法
-
利用已有部分匹配中的信息
-
需要尋找overlap
-
基於自動機的算法;
-
前綴表,由於sigma有可能比較大,所欲忘記未匹配的字符(alfa)
-
這樣可能導致再次匹配失敗,但是也只是多匹配了一次,這樣換取了時間和空間的優化
-
P的前綴和P的前q位的后綴求最大的overlap,q+1位匹配失敗
-
核心就是求前綴表
- KMP算法流程
BMH算法
- 用逆向簡單算法中增加了啟發式規則
- P從前往后走,但模式P匹配時從后往前匹配
- 真實應用中,不匹配的概率大,最壞也可能是O(n*m)
- 對P去掉最后一位的每個字符計算偏移表,其他字符直接移動整個字符串長度
- 算法描述