1.算法为体
1.1 各路算法体
递归是什么,递归就是吃,假如是10,就不断递归吃到结束,然后再往上走
也就是先递归到边界条件,然后再回溯
https://blog.csdn.net/m0_37907797/article/details/102767860?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522164404809216780265416190%2522%252C%2522scm%2522%253A%252220140713.130102334…%2522%257D&request_id=164404809216780265416190&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2alltop_positive~default-1-102767860.pc_search_result_control_group&utm_term=%E9%80%92%E5%BD%92&spm=1018.2226.3001.4187
在这里面可以得到递归算法的三个步骤
- 这个函数的功能是什么
- 边界条件:什么时候递归结束
- 执行代码
- 递归:开始递归
心法
递归就是一生二,二生三,三生万物,万物归一
问题可以拆分递归为子问题,子问题的解又返回,在写代码前可以先想象出图形才写代码(如归并,如肥波纳妾)
1.1帮助快速复习的题目
递归就是吃往回吃,吃到最后再回溯
反转打印链表
public void showReversed(MyNode head){
if(head==null|| head.next==null){ // 吃,吃到最后结束条件
return ;
}
showReversed(head.next); // 吃够了开始回溯操作
System.out.println(head.next.data);
}
1.2 动态规划
我的理解,动态规划就是一种优化,下一个子问题的解是基于上一个子问题的解,将返回值存储起来(类似缓存一样),在又一次计算该变量的时候,可以先查看缓存中时候有该返回值时,有,直接取,无,计算再存储。
如:
// 肥波纳妾
public static int[] memory = new int[20];
public final static double loaderFactor = 0.75;
public static int fib(int n){
if(n==1 || n==2){
return 1;
}
// 缓存中有
if(memory[n]!=0){
return memory[n];
}
// 如果不存在
int result = fib(n-1)+fib(n-2);
// 存储缓存
if(n>memory.length){
}
return 1;
}
private void resize(){
int newLength = memory.length>>1;
int []temp = new int[newLength];
for(int i=0;i<memory.length;i++){
temp[i] = memory[i];
}
memory = temp;
}
背包问题
重点:
表格为二维数组,f [ i ][ j ] ,存储子问题的解,表示前i个物品中,在当前j重量的背包中的最大价值。
先看视频理解步骤再看代码
重要步骤步骤:
if :当前物品的重量w[i] 是否能加入当前容量j的背包
yes:当前物品的价值val[ i ] +f[i-1][j-w[i]](剩余的重量所能加入的最大价值)是否大于f[i-1][j]
yes:加入f[i][j]
No:加入上一个子问题的解
int[] w = {1, 4, 3};//物品的重量
int[] val = {1500, 3000, 2000}; //物品的价值 这里val[i] 就是前面讲的v[i]
int m = 4; //背包的容量
int n = val.length; //物品的个数
int[][] v = new int[n + 1][m + 1]; // 前i个物品,当前容量
// 初始化
// 当只有0个容量时
for (int i = 0; i < n + 1; i++) {
v[i][0] = 0;
}
// 当前只有0个物品
for (int i = 0; i < m + 1; i++) {
v[0][i] = 0;
}
for (int i = 1; i < n + 1; i++) {
for (int j = 1; j < m + 1; j++) {
// 当前物品是否小于当前背包的容量
if (w[i-1] > j) {
// 如果大于
// 获取子问题的解
v[i][j] = v[i - 1][j];
} else {
// 如果小于
// 判断当前价值加上剩余容量价值是否大于子问题的价值
if ((val[i - 1] + v[i - 1][j - w[i - 1]]) > v[i - 1][j]) {
// 如果大于
v[i][j] = val[i - 1] + v[i - 1][j - w[i - 1]];
}else{
v[i][j] = v[i-1][j];
}
}
}
}
System.out.println(v[n][m]);
1.3 贪心算法
求解问题的时候,永远选择最优解,获取问题的最优解
子问题 ----》 当前最优解 —》子问题—》当前最优解
贪心算法场景:
可以拆解子问题,子问题的解需要选择最优解
提出贪心策略
如硬币找零,找最大面值
2.排序
2.1 插入算法
快速复习法:代码搭配动图看。
插入就是,一个有序列[0,i),[i,++]一个无序列,insertIndex=i-1,如果insertValue(nums[i]),小于nums[insertIndex],那么当前的数就往后面移一位,nums[insertIndex+1] = nums[insertIndex]。如果大于nums[insertIndex]的话,就插入到insertIndex+1.
public static void insertSort(int[] arr) {
int insertVal = false;
int insertIndex = false;
for(int i = 1; i < arr.length; ++i) {
int insertVal = arr[i];
int insertIndex;
for(insertIndex = i - 1; insertIndex >= 0 && insertVal < arr[insertIndex]; --insertIndex) {
arr[insertIndex + 1] = arr[insertIndex];
}
if (insertIndex + 1 != i) {
arr[insertIndex + 1] = insertVal;
}
}
}
}
2.2 归并排序
public static void sort(int nums[],int left,int right){
if(left<right){ //边界条件
int mid = (left + right)/2;
sort(nums,left,mid); // 左递归
sort(nums,mid+1,right);// 右递归
merge(nums,left,right);// merge
}
}
public static void merge(int []nums,int left,int right){
int mid = (left + right)/2;
int i = left; // 左边开始索引
int j = mid + 1; // 右边开始索引
while(i<=mid && j<=right){
if(nums[i]<nums[j]){
i++;
}else{ // 如果右边小于左边
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
j++;
i++;
}
}
}