算法
- 排序算法
- 冒泡排序
- 插入排序
- 希尔排序
- 快速排序
- 选择排序
- 归并排序
- 基数排序
- 堆排序
- 桶排序
- 大数据排序
- 查找算法
- 二分查找
- 快排查找
- 树的遍历
- 二叉树的镜像遍历
- 二叉树的前中后序、层次遍历
- 最大子数组和算法
- 最长公共子序算法
- 最短路径算法
- 最小生成树算法
- 动态规划
- 贪心算法
- 分治算法
- 回溯算法
- KMP算法
- LRU算法
- Manacher算法
- BEPRT算法
一、递归
思路步骤:
- 分析问题,找出递归关系
- 找出停止条件
- 设计递归算法、确定参数,即构建递归体。
经典题目
- 斐波那契数列:
经典数学问题之一;斐波那契数列,又称黄金分割数列,指的是这样一个数列:0、1、1、2、3、5、8、13、21、……
递归关系:
f(0) = 1
f(1) = 1
f(n) = f(n-1)+f(n-2)
public class Solution {
public int Fibonacci(int n) {
if(n==0)
return 0;
if(n==1)
return 1;
else
return Fibonacci(n-2)+Fibonacci(n-1);
}
}
- 青蛙跳台阶
一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法(先后次序不同算不同的结果)。
递归关系:
f(1) = 1
f(2) = 2
f(n) = f(n-1)+f(n-2)
public class Solution {
public int JumpFloor(int target) {
if(target == 1)
return 1;
if(target == 2)
return 2;
else
return JumpFloor(target-1)+JumpFloor(target-2);
}
}
- 变态跳台阶
一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。
递归关系:
f(n)=f(n-1)+f(n-2)+…+f(1)
f(n-1)=f(n-2)+f(n-3)+…+f(1)
得出:
f(1)=1
f(n)=2*f(n-1) n>=2
public class Solution {
public int JumpFloorII(int target) {
if(target == 1)
return 1;
else
return 2*JumpFloorII(target-1);
}
}
动态规划
动态规划的核心思想:
动态规划其实质上是通过开辟记录表,记录已求解过的结果,当再次需要求解的时候,可以直接到那个记录表中去查找,从而避免重复计算子问题来达到降低时间复杂度的效果。算法的关键在于解决冗余,实际上是一个空间换时间的算法。
动态规划的求解步骤:
- 分析最优解的性质,并刻画其最优子结构特征;
- 递归地定义最优值
- 自底向上的方式计算出最优值,并记录相关信息
- 根据计算最优值时得到的信息,构造最优解
动态规划的基本要素:
- 最优子结构性质
- 子问题重叠性质
- 自底向上的求解方法
总结:建立记录表,自下而上,递归关系式;
最大连续子数组和(动态规划)
递归关系式:
| 0 i=0
d[i] = | array[i] d[i-1]<0
| d[i-1]+array[i] d[i-1]>0
class Solution {
public:
int FindGreatestSumOfSubArray(vector<int> array) {
vector<int> dp(array.size(),0);//记录表
dp[0]=array[0];
int max_dp=INT_MIN;
for (int i = 1; i <= array.size()-1; ++i)
{
if(dp[i-1]<=0) //判断上一个子问题的解是否小于0
dp[i]=array[i];
else
dp[i]=array[i]+dp[i-1];
if(dp[i]>max_dp)
max_dp=dp[i];
}
return max_dp;
}
};
斐波那契数列
import java.util.*;
public class Solution {
public int Fibonacci(int n) {
List<Integer> list = new ArrayList<Integer>();//记录表
return Fibonacci(n,list);
}
public int Fibonacci(int n,List<Integer> list){
if(n == 0){
if(list.size()==n)
list.add(0);
return 0;
}
if(n == 1 ){
if(list.size()==n)
list.add(1);
return 1;
}
if(list.size()>=n){ //记录添加条件
if(list.size()==n){
list.add(list.get(n-1)+list.get(n-2)); //将已经求得和记录进数组表中
}
return list.get(n);
}
else
return Fibonacci(n-1,list)+Fibonacci(n-2,list);
}
}
最长公共子序列
import java.lang.String;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
while(in.hasNext()) {
String str1 = in.nextLine();
String str2 = in.nextLine();
System.out.println(new Main().maxSubSequence(str1,str2).length() > 0 ? new Main().maxSubSequence(str1,str2):-1);
}
}
public StringBuilder maxSubSequence(String str1,String str2) {
int M = str1.length();
int N = str2.length();
//多添加一行一列便于初始化
int[][] dp = new int[M+1][N+1];//dp[i][j] 表示 str1[0~i-1] 与 str2[0~j-1] 的最长公共子序列的长度
int[][] re = new int[M+1][N+1];
StringBuilder maxSubSequence = new StringBuilder();
for(int i = 1;i < M+1;i++){
for(int j = 1;j < N+1;j++){
if(str1.charAt(i-1) == str2.charAt(j-1)){
dp[i][j] = dp[i-1][j-1] + 1;
re[i][j] = 1;
}else if(dp[i-1][j]>dp[i][j-1]){
dp[i][j] = dp[i-1][j];
re[i][j] = 2;
}else{
dp[i][j] = dp[i][j-1];
re[i][j] = 3;
}
}
}
lcs(M,N,str1,re,maxSubSequence);
return maxSubSequence;
}
public static void lcs(int i,int j,String str1,int[][] re,StringBuilder out){
if(i == 0||j == 0) return;
if(re[i][j] == 1){
lcs(i-1,j-1,str1,re,out);
out.append(str1.charAt(i-1));
}
else if(re[i][j] == 2){
lcs(i-1,j,str1,re,out);
}else
lcs(i,j-1,str1,re,out);
}
}
分治法
基本思想:
分治法的设计思想:将一个难以直接解决的规模较大的问题,分割成一些规模较小的相同问题,以便各个击破,分而治之。例如大规模的数据排序…
分治法所能解决的问题一般具有以下几个特征:
I. 该问题的规模缩小到一定的程度就可以容易地解决;
II. 该问题可以分解为若干个规模较小的相同问题,即该问题具有最优子结构性质
III. 该问题所分解出的各个子问题是相互独立的,即子问题之间不包含公共的子问题。
IV. 利用该问题分解出的子问题的解可以合并为该问题的解;
二分查找
快排
归并排序
贪心算法
基本思想:
贪心算法的基本思路是从问题的某一个初始解出发一步一步地进行,根据某个优化测度,每一步都要确保能获得局部最优解。每一步只考虑一个数据,他的选取应该满足局部优化的条件。若下一个数据和部分最优解连在一起不再是可行解时,就不把该数据添加到部分解中,直到把所有数据枚举完,或者不能再添加算法停止 。
求解步骤:
- 建立数学模型来描述问题;
- 把求解的问题分成若干个子问题;
- 对每一子问题求解,得到子问题的局部最优解;
- 把子问题的解局部最优解合成原来解问题的一个解。
基本要素:
- 最优子结构
- 贪心选择
贪心算法与动态规划算法的主要区别:
- 贪心算法是自上而下的求解,从初始解出发,逐渐减小问题的规模;动态规划则是自下而上的求解
- 动态规划有子问题重叠性质
- 都有最优子结构性质
总结:贪心算法,从初始解出发,根据贪心选择,每走一步,问题的规模就会减少。
最大连续子数组和(贪心算法)
public class Solution {
public int FindGreatestSumOfSubArray(int[] array) {
int largest=-1;
int sum=0;
for(int i=0;i<array.length;i++){
sum=sum+array[i];
if(sum>largest)
largest = sum;
if(sum<0)
sum=0;
}
return largest;
}
}