面向对象设计
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);
}
}
}