算法的性质
- 又穷性
- 能行性
- 确定性
- 终止性
- 输入输出
算法的描述
- 自然语言描述
- 自然语言加数学公式
- 编程语言描述
- 伪代码描述
常法设计模式
枚举法
根据具体问题枚举出各种可能,从中选出有用信息或者问题的解。这种方法利用计算机的速度优势,在解决问题时十分有效。
贪心发
根据问题的信息尽可能做出部分的解,并基于部分解逐步扩充得到完整的解。在解决复杂问题时,这种做法未必能得到最好的解。
分治法
把复杂问题分解为相对简单的子问题,分别求解,最后通过组合起子问题的解的方式得到原问题的解。
回溯法(搜索法)
专指通过探索的方式求解。如果问题很复杂,没有清晰的求解路径,可能就需要分步骤进行,而每一步骤又可能有多种选择。在这种情况下,只能采用试探的方式,根据实际情况选择一个可能方向,当后面的求解方向无法继续时,就需要退回前面的步骤,另外选择求解路径,这种动作成为回溯。
动态规划法
在一些复杂情况下,问题求解很难直截了当地进行,因此需要在前面的步骤中积累信息,在后续步骤中根据已知信息,动态选择已知的最好求解路径(同时可能进一步积累信息)。
- 分支限界法
可以看作搜索方法的一种改良形式,如果在搜索过程中可以得到一些信息,确定某些可能的选择实际上并不真正有用,就可以及早将其删除,以缩小求解空间,加速问题求解过程。
运算时间计算
一般法则
法则1 - for循环
一个for循环的运行时间至多是该for循环内部那些语句的运行时间乘以迭代的次数。
法则2 - 嵌套的for循环
从里向外分析这些循环。在一组嵌套循环内部的一些语句总的运行时间为该语句的运行时间乘以该组所有的for循环的大小的乘积
例如,下列程序片断为O(
n2
):
for(i = 0;i < n; i++){
for(j = 0;j < n; j++){
k++;
}
}
法则3 - 顺序语句
将各个语句的运行实际求和即可。
n和
n2
相加为
n2
法则4 - if/else语句
if(condition) s1
else s2
一个if/else语句的运行时间从不超过判断的运行时间再加上s1和s2中运行时间长者总的运行时间。
分析的基本策略是从内部向外部展开工作的。如果有方法调用,那么要首先分析这些调用。
最大子序列和问题
//第一层循环控制首数字位置
//第二层循环控制尾数字位置
//第三层循环在生成首尾后 把从首到尾的数字相加
//复杂度:n^3
public static int maxSubSum1(int[] a){
int maxSum = 0;
for(int i = 0; i < a.length; i++){
for (int j = i; j < a.length; j++){
int thisSum = 0;
for(int k = i; k <= j; k++) thisSum += a[k];
if (thisSum > maxSum) maxSum = thisSum;
}
}
return maxSum;
}
//第一层循环控制首数字位置
//第二层循环控制尾数字位置
//1,2两种方法不同点:
// 1.算法1每次的生成的子序列都要从首到尾计算
// 2.算法2在第一层循环固定的情况下,将上一次计算结果报存,加下一个尾数字即为新的子序列
//复杂度:n^2
public static int maxSubSum2(int[] a){
int maxSum = 0;
for(int i = 0; i < a.length; i++){
int thisSum = 0;
for (int j = i; j < a.length; j++){
thisSum += a[j];
if (thisSum > maxSum) maxSum = thisSum;
}
}
return maxSum;
}
//分治法 复杂度 nlogn
private static int maxSumRec(int[] a, int left, int right){
if (left == right){
if (a[left] > 0) return a[left];
else return 0;
}
int center = (left + right) / 2;
int maxLeftSum = maxSumRec(a, left, center);
int maxRightSum = maxSumRec(a, center + 1, right);
int maxLeftBorderSum = 0, leftBorderSum = 0;
for (int i = center; i>=left; i--){
leftBorderSum += a[i];
if (leftBorderSum > maxLeftBorderSum) maxLeftBorderSum = leftBorderSum;
}
int maxRightBorderSum = 0, rightBorderSum = 0;
for (int i = center + 1; i <= right; i++){
rightBorderSum += a[i];
if (rightBorderSum > maxRightBorderSum) maxRightBorderSum = rightBorderSum;
}
System.out.println(maxLeftBorderSum+","+maxRightBorderSum);
return max3(maxLeftBorderSum,maxRightBorderSum,maxLeftBorderSum+maxRightBorderSum);
}
private static int max3(int num1, int num2, int num3){
int max = num1 > num2 ? num1 : num2;
max = max >num3 ? max :num3;
return max;
}
//1,2算法的优化,关键任何负序列的末端子序列不能作前缀
public static int maxSubSum4(int[] a){
int maxSum = 0,thisSum = 0;
for(int j = 0; j < a.length; j++){
thisSum += a[j];
if (thisSum > maxSum){
maxSum = thisSum;
}
else if(thisSum < 0){
thisSum = 0;
}
}
return maxSum;
}