面向對象設計
1.繼承,通過繼承方式,子類能夠改寫父類方法,同時保留部分父類方法。繼承在靜態編譯時就定義了,所以無法在運行時刻改寫父類方法。如果子類沒有改寫父類方法,就相當於依賴了父類這個方法的實現細節,會認爲破壞封裝性。如果父類接口定義需要更改時,子類也需要更改響應接口。
2.組合。對象組合通過獲得其他對象引用而在運行時刻動態定義。對象只能通過接口來訪問,所以不會破壞封裝性。使用組合方式,我們可以將類層次限制在比較小的範圍內,不容易產生類的爆炸。
3.參數化類型方式基於接口的編程,在一定程度上消除了類型給程序設計語言帶來的限制。相對於組合方式來說,缺少的是動態修改能力。
4.對象組合技術允許你在運行時刻改變被組合的行爲,但是它存在間接性,相對來說比較低效;繼承允許你提供操作的缺省實現,通過子類來重定義這些操作,但是不能夠在運行時改變;參數化允許你改變所使用的類型,同樣不能夠在運行時改變。
5.設計模式:創建型、結構型和行爲型。
創建型:創建型模式與對象的創建相關。
單例模式:保證一個類僅僅有一個實例並且提供一個訪問它的全局訪問點。
工廠模式:抽象類需要創建一個對象時,讓子類決定實例化哪一個類。
結構型:結構型模式處理類或者是對象的組合;
適配器:將一個類的接口轉化爲客戶希望的另外一個接口。
行爲型:行爲型模式對類或者是對象怎樣交互和怎樣分配職責進行描述。
觀察者:定義對象之間的依賴關係,當一個對象狀態發生改變,所有依賴這個對象的對象都會被通知並且進行更新。
狀態:允許一個對象在其內部狀態改變時改變它的行爲。
遞歸和動態規劃(DP)
1.DP存儲子問題的結果,當子問題已經被計算過,直接返回結果。因此,當需要重複計算子問題時,DP的時間效率高很多,但需要額外的空間。
2.從系統層面上說,操作系統是利用函數棧來實現遞歸,每次的操作可視爲棧裏的一個對象,遞歸的時間成本隨遞歸深度n(單條路徑中遞歸調用的次數)呈指數增長,空間複雜度爲O(n)。
3.算法策略
分而治之(Divide & Conquer,D&C),將問題分成幾個部分,每一個部分相互獨立,互不重疊,假定每一個都可以得到解決來進行遞歸調用,合併每一部分的結果。
動態規劃:儘可能不重複計算每個子問題,而是將結果存儲下來,以確定後驅問題的解。
貪婪算法:只做出當下最優的判斷,並且以此爲基礎進行下一步計算。當前判斷最有時,不考慮對全局/未來的影響,所以從全局來說並不能保證總是最優。
demo1
//判斷第n個素數
int GetNthPrime(int n) {
List<int> primes(1,2); //init list:length 1, value 2(first prime)
int number = 3;
while (primes.size() != n){
bool isPrime = true;
for(auto it = primes.begin(); it != primes.end() && (*it)*(*it) <= number; i++){
if (number % (*it) == 0)
isPrime = false;
}
if (isPrime){
primes.push_back(number);
}
number += 2;
}
return *(primes.rbegin());
}
demo2:
//假設一個機器人只能夠向下和向右移動,它從(0,0)移動到(x,y)有多少條路徑
int uniquePaths(int m, int n){
int ways [n] = 0;
ways[n-1] = 1;
for (int i=m-1; i>=0; --i)
for (int j=n-2; j>=0; --j)
ways[j] += ways[j+1]
return ways[0];
}
demo3:
//在一個整數數組中,找到最長的遞增子序列
int longestIncreasingSubsequence(int arr[], int n){
vector<int> maxLength(n,1);
int global_max = 0;
for (int i=0; i<n; i++)
for (int j=0; j<i; j++)
if(arr[i]>arr[j] && maxLength[j]+1 > maxLength[i])
maxLength[i] = maxLength[j]+1;
for (int i=0; i<n; i++)
if (global_max < maxLength[i])
global_max = maxLength[i];
return global_max;
}
demo4:
// eight queens
bool checkValid( int row1, int coll, int *rowCol){
for (int row2 = row1 - 1; row2 >= 0; row2--){
if(rowCol[row2]==coll)
return false;
if(abs(row1-row2) == abs(rowCol[row2]-col))
return false'
}
}
void placeQ(int row, int rowCol[], vector<int *> & res){
if (row == GRID_SIZE){
//winning
int p[GRID_SIZE];
for(int i=0; i<GRID_SIZE; i++)
p[i]=rowCol[i];
res.push_back(p);
return;
}
int col=0;
for (col=0; col<GRID_SIZE; col++){
if(checkValid(row,col,rowCol)){
rowCol[row]=col;
placeQ(row+1, rowCol, res);
}
}
}