常用算法总结
来源:互联网 发布:淘宝产品短连接 编辑:程序博客网 时间:2024/06/18 08:43
一,算法基础
public static int search(int[] arr, int key) { int start = 0; int end = arr.length - 1; while (start <= end) { int middle = (start + end) / 2; if (key < arr[middle]) { end = middle - 1; } else if (key > arr[middle]) { start = middle + 1; } else { return middle; } } return -1; }}
最坏情况下的比较次数:那个答案(log2n+ 1)下取整 或者(log2 (n + 1) )上取整。
即使找不到结果,最后的middle值就在key的左或者右。
在Rotated Array中求最值的题目需要注意,此类题重点在于找规律,通过mid与其他值得比较对范围进行筛选。
0 1 2 4 5 6 7
might become 4 5 6 7 0 1 2
![常用算法总结 - Garfield - 张广辉的博客 常用算法总结 - Garfield - 张广辉的博客](http://img2.ph.126.net/g_9T3a99cZGyOS6YbEvgVw==/6630640055676678521.png)
2.2,分治策略时尽量将子问题等分,这样复杂度低。或者尽量将分开的比例保持不变。快排的最差情况就是等分点总是在数组两头。
![常用算法总结 - Garfield - 张广辉的博客 常用算法总结 - Garfield - 张广辉的博客](http://img0.ph.126.net/HF1SBGEJslA9pR4mwGsJ0Q==/6630261823675680573.jpg)
典型应用:
2.4 快速排序
![常用算法总结 - Garfield - 张广辉的博客 常用算法总结 - Garfield - 张广辉的博客](http://img0.ph.126.net/vGS1sdDA2PQtJwhmGnu5ow==/6630526805978016702.png)
![常用算法总结 - Garfield - 张广辉的博客 常用算法总结 - Garfield - 张广辉的博客](http://img1.ph.126.net/vTHR8_-V0XxfGwNrJnv-FA==/6630881948233929025.png)
![常用算法总结 - Garfield - 张广辉的博客 常用算法总结 - Garfield - 张广辉的博客](http://img0.ph.126.net/cyKzlzsv4oubts4ct08JhA==/6630261823676193978.png)
2.5 快排可以通过随机选取标准数进行优化。因为如果每次取得的首元素将数组分为大小非常不均匀的两数组,将导致复杂度增加。
![常用算法总结 - Garfield - 张广辉的博客 常用算法总结 - Garfield - 张广辉的博客](http://img1.ph.126.net/Uk-qc5c8FKOTVNah-plVMg==/6630397063605974986.png)
2.7,左中右计算最值问题
三,动态规划
动态规划是用空间换时间的一种方法的抽象。其关键是发现子问题和记录其结果。然后利用这些结果减轻运算量。常用于最优化问题的求解。
设计要点:寻找子问题,确定子问题到当前问题的递推关系,迭代记录中间最优结果。
优化原则:要看看子问题大小是否决定了主问题,并不是所有组合优化问题都适用,比如求模最小值。
与蛮力算法的不同:递归也好,枚举路径也好,在这里都算是蛮力算法,因为到达一个中间点并没有记录中间结果,这样就对中间点多次的计算,导致时间复杂度升高。动态规划记录中间结果,只保留最优的中间值,增加了空间复杂度,降低了时间复杂度。
动态规划实例
1)最短路径问题,m代表每层节点个数,n代表层数。如果枚举路径,需要O(m*2的n次方);而每一步都记录中间最有结果,需要O(mn);
2)矩阵连乘问题:xy矩阵*yz矩阵,需要进行xyz次计算。
给定n个矩阵{A1,A2,…,An},其中Ai与Ai+1是可乘的,i=1,2,…,n-1。考察这n个矩阵的连乘积A1A2…An。由于矩阵乘法满足结合律,故计算矩阵的连乘积可以有许多不同的计算次序,这种计算次序可以用加括号的方式来确定。若一个矩阵连乘积的计算次序完全确定,则可以依此次序反复调用2个矩阵相乘的标准算法(有改进的方法,这里不考虑)计算出矩阵连乘积。若A是一个p×q矩阵,B是一个q×r矩阵,则计算其乘积C=AB的标准算法中,需要进行pqr次数乘。
矩阵连乘积的计算次序不同,计算量也不同,举例如下:
先考察3个矩阵{A1,A2,A3}连乘,设这三个矩阵的维数分别为10×100,100×5,5×50。若按((A1A2)A3)方式需要的数乘次数为10×100×5+10×5×50=7500,若按(A1(A2A3))方式需要的数乘次数为100×5×50+10×100×50=75000。
下面使用动态规划法找出矩阵连乘积的最优计算次序。
1, 设矩阵连乘积AiAi+1…Aj简记为A[i:j],设最优计算次序在Ak和Ak+1之间断开,则加括号方式为:
((AiAi+1…Ak)(Ak+1…Aj))
则依照这个次序,先计算A[i:k]和A[K+1:j]然后再将计算结果相乘,计算量是:
A[i:k]的计算量加上A[K+1:j]的计算量再加上它们相乘的计算量。
问题的一个关键是:计算A[i:j]的最优次序所包含的两个子过程(计算A[i:k]和A[K+1:j])也是最优次序。
2, 设计算A[i:j]所需的最少数乘次数为m[i][j]。
i=j时为单一矩阵,则m[i][i]=0,
i<j时,设最优计算次序在Ak和Ak+1之间断开,则m[i][j]=m[i][k]+m[k+1][j]+pipk+1pj+1,其中p表示数组的维数,例如A0到A5共6个数组,他们表示如下:
//p[0]:第一个矩阵的行数
//p[1]:第一个矩阵的列数,第二个矩阵的行数
//p[2]:第二个矩阵的列数,第三个矩阵的行数
k此时并未确定,需要从i到j-1遍历以寻找一个最小的m[i][j]。我们把这个最小的k放在s[i][j]。以下是完整实现代码,以一个具体的例子实现,稍加修改即可通用。
http://yoyo08.iteye.com/blog/418547
3)0-1背包问题
用子问题定义状态:即f[i][v]表示前i件物品恰放入一个容量为v的背包可以获得的最大价值。则其状态转移方程便是:
f[i][v]=max{f[i-1][v],f[i-1][v-c[i]]+w[i]}
这个方程非常重要,据说基本上所有跟背包相关的问题的方程都是由它衍生出来的。所以详细的查了一下这个方程的含义:“将前i件物品放入容量为v的背包中”这个子问题,若只考虑第i件物品的策略(放或不放),那么就可以转化为一个只牵扯前i-1件物品的问题。如果不放第i件物品,那么问题就转化为“前i-1件物品放入容量为v的背包中”,价值为f[i-1][v];如果放第i件物品,那么问题就转化为“前i-1件物品放入剩下的容量为v-c[i]的背包中”,此时能获得的最大价值就是f[i-1][v-c[i]]再加上通过放入第i件物品获得的价值w[i]。
1. xi == yj, lcs(i,j) = lcs(i-1, j-1) + 1;
2. xi != yj , lcs(i, j) = max ( lcs( i-1, j) , lcs( i, j-1) );
1)概念:贪心算法(又称贪婪算法)是指,在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,他所做出的是在某种意义上的局部最优解。贪心算法不是对所有问题都能得到整体最优解,关键是贪心策略的选择,选择的贪心策略必须具备无后效性,即某个状态以前的过程不会影响以后的状态,只与当前状态有关。
2)贪心算法适用的问题
贪心策略适用的前提是:局部最优策略能导致产生全局最优解。
实际上,贪心算法适用的情况很少。一般,对一个问题分析是否适用于贪心算法,可以先选择该问题下的几个实际数据进行分析,就可做出判断。
![常用算法总结 - Garfield - 张广辉的博客 常用算法总结 - Garfield - 张广辉的博客](http://img2.ph.126.net/iljJN9UIEu0Hxv2-cIJNJg==/6597765757518986783.png)
其实此题也可以用标准dp来做,假如求1到3最短路径,可先求出1到2和1到4的最短路径,然后求出1到2到3和1到4到3的最短路径。
五,回溯策略
1,深度优先搜索和广度优先搜索概念(找出所有的可行解):http://blog.csdn.net/andyelvis/article/details/1728378
DFS:从根节点开始访问他的子节点,以树的深度优先,不断访问子节点。当某一节点不再有子节点了,那么他将返回访问仍没有被访问的祖先节点的子节点。前序中序后序都属于DFS。前序遍历是父节点先于子节点;中序是父节点在两子节点之间,后序是父节点在子节点之后。
public void DFS(TreeNode root){ if(root==null){ System.out.println("empty tree"); return; } ArrayDeque<TreeNode> stack=new ArrayDeque<TreeNode>();//定义栈 stack.push(root); while(stack.isEmpty()==false){ TreeNode node=stack.pop(); System.out.print(node.value+" "); //对节点的访问 if(node.right!=null){ stack.push(node.right);//先把右孩子压栈 } if(node.left!=null){ stack.push(node.left);//左孩子压栈,先访问 } } System.out.print("\n"); }
DFS递归写法
public void DFS(TreeNode root) {
if (root==null)
return;
else {
DFS(root.left); //至于是前序中序还是后序就把根节点的访问放在啥位置就好了。
DFS(root.right));
}
}
BFS(分层次搜索)
![常用算法总结 - Garfield - 张广辉的博客 常用算法总结 - Garfield - 张广辉的博客](http://img0.ph.126.net/MByxo4xyQfKWyrdvBtJNkw==/6630564189373870074.png)
1)8皇后问题:
![常用算法总结 - Garfield - 张广辉的博客 常用算法总结 - Garfield - 张广辉的博客](http://img1.ph.126.net/Mw6z6h-VvCq6nkqd0vQpcQ==/6630675240048133360.png)
8皇后之间需满足:1.不在同一行上;2.不在同一列上;3.不在同一斜线上; 4.不在同一反斜线上;
深度优先搜索遍历的思路,我们可以逐行或者逐列来进行可行摆放方案的遍历,每一行(或列)遍历出一个符合条件的位置,接着就到下一行或列遍历下一个棋子的合适位置,接下来,我们只要判断当前位置是否还符合其他条件,如果符合,就遍历下一行(或列)所有位置,看看是否继续有符合条件的位置,以此类推,如果某一个行(或列)的所有位置都不合适,就返回上一行(或列)继续该行(或列)的其他位置遍历,当我们顺利遍历到最后一行(或列),且有符合条件的位置时,就是一个可行的8皇后摆放方案,累加一次八皇后可行方案的个数,然后继续遍历该行其他位置是否有合适的,如果没有,则返回上一行,遍历该行其他位置,依此下去。这样一个过程下来,我们就可以得出所有符合条件的8皇后摆放方案了。这是一个深度优先遍历的过程,同时也是经典的递归思路。
用一个三层的八叉树表示此算法就更为形象。书中所讲。
![常用算法总结 - Garfield - 张广辉的博客 常用算法总结 - Garfield - 张广辉的博客](http://img1.ph.126.net/b_g-MIzc7nyNB9MVbTh4Yg==/6630610368862117516.png)
![常用算法总结 - Garfield - 张广辉的博客 常用算法总结 - Garfield - 张广辉的博客](http://img2.ph.126.net/o_o7GPeFHRsBqSNbyv3o9A==/6608845536190495475.png)
[ [2,4], [3,4], [2,3], [1,2], [1,3], [1,4],](像这种实际问题,都要先抽象成一棵多叉树来解决)
![常用算法总结 - Garfield - 张广辉的博客 常用算法总结 - Garfield - 张广辉的博客](http://img2.ph.126.net/1zSei9BqtIecoslrb_UsRA==/6630645553234325234.png)
1000万 0.75 1.22 1.77 3.57
5000万 3.78 6.29 9.48 26.54
1亿 7.65 13.06 18.79 61.31
![常用算法总结 - Garfield - 张广辉的博客 常用算法总结 - Garfield - 张广辉的博客](http://img1.ph.126.net/f6yjZOzmmorH0dWvbBqJNQ==/6619451425352205925.png)
![常用算法总结 - Garfield - 张广辉的博客 常用算法总结 - Garfield - 张广辉的博客](http://img2.ph.126.net/vaNoFVkj3pOHSAckZ97DAw==/6630769798048805912.png)
![常用算法总结 - Garfield - 张广辉的博客 常用算法总结 - Garfield - 张广辉的博客](http://img0.ph.126.net/ZXR260IgcWMIeJihtKnhAA==/6630554293769387442.png)
![常用算法总结 - Garfield - 张广辉的博客 常用算法总结 - Garfield - 张广辉的博客](http://img1.ph.126.net/urY-tjrh8FhGamlF9U_acA==/6619284299584786105.png)
![常用算法总结 - Garfield - 张广辉的博客 常用算法总结 - Garfield - 张广辉的博客](http://img0.ph.126.net/Ke_l5ANshT215tksRAzRGw==/6630250828560127329.png)
![常用算法总结 - Garfield - 张广辉的博客 常用算法总结 - Garfield - 张广辉的博客](http://img0.ph.126.net/lWoIENK-slYSAjzCIjhzhA==/6630151872513627738.png)
![常用算法总结 - Garfield - 张广辉的博客 常用算法总结 - Garfield - 张广辉的博客](http://img0.ph.126.net/BKtF08ODnSWNn51v1lmAQQ==/6630687334676719515.png)
![常用算法总结 - Garfield - 张广辉的博客 常用算法总结 - Garfield - 张广辉的博客](http://img2.ph.126.net/w6eJ5T7NjVT7EKFsqaojbQ==/6630589478141843060.png)
Java 位操作符一共有七个:&、|、^、~、<<、>>、>>>。
第一个是按位与;
第二个是按位或;
第三个是按位异或
第四个是按位非;
第五个是左移位;
第六个是右移位;
第七个是无符号右移位。<< : 左移运算符,num << 1,相当于num乘以2;
>> : 右移运算符,num >> 1,相当于num除以2,有符号右移,如果是负数,高位补1;
>>> : 无符号右移,忽略符号位,空位都以0补齐;
![常用算法总结 - Garfield - 张广辉的博客 常用算法总结 - Garfield - 张广辉的博客](http://img1.ph.126.net/viCUiXmV_H_zCvFeHGqbrw==/6630146374955229547.png)
![常用算法总结 - Garfield - 张广辉的博客 常用算法总结 - Garfield - 张广辉的博客](http://img2.ph.126.net/M1KXhYSZn6PWnjrxhGZR5w==/6608572857306817508.png)
![常用算法总结 - Garfield - 张广辉的博客 常用算法总结 - Garfield - 张广辉的博客](http://img2.ph.126.net/IU994Q2UY1ost_9tnRXyvA==/6630351983629646063.png)
![常用算法总结 - Garfield - 张广辉的博客 常用算法总结 - Garfield - 张广辉的博客](http://img0.ph.126.net/80IX4peTy8ir2G7N-tcI5A==/6619260110328973233.png)
![常用算法总结 - Garfield - 张广辉的博客 常用算法总结 - Garfield - 张广辉的博客](http://img2.ph.126.net/b9PZOoTXrAHUeJcRZ7F1Vg==/6630600473258105978.png)
- 常用排序算法总结
- 常用排序算法总结
- 常用排序算法总结
- php常用算法总结
- 常用排序算法总结
- 常用排序算法总结
- 常用算法总结
- 常用排序算法总结
- 常用排序算法总结
- 常用排序算法总结
- 常用排序算法总结
- F5常用算法总结
- JAVA 常用算法总结
- 常用排序算法 总结
- 常用排序算法总结
- 常用调度算法总结
- 常用排序算法总结
- 常用排序算法总结
- 通讯录 ios
- Hibernate and IBatis
- 百度2015春季实习生招聘附加题_今天要吃点好的!
- 并发编程学习
- jsp and servlet
- 常用算法总结
- Spring
- 操作系统
- 数据库&MYSQL&JDBC
- 华为上机题目
- 单元测试与Junit
- vim个人配置记录
- Hadoop基础学习
- IO和NIO