有哪些常见的算法是Java开发中常用的呢?java教程

经典的应用:比如霍夫曼编码(HuffmanCoding)、Prim和Kruskal最小生成树算法、还有Dijkstra单源最短路径算法。

贪心算法解决问题的步骤

第一步,当我们看到这类问题的时候,首先要联想到贪心算法:针对一组数据,我们定义了限制值和期望值,希望从中选出几个数据,在满足限制值的情况下,期望值最大。

类比到刚刚的例子,限制值就是重量不能超过100kg,期望值就是物品的总价值。这组数据就是5种豆子。我们从中选出一部分,满足重量不超过100kg,并且总价值最大。

第二步,我们尝试看下这个问题是否可以用贪心算法解决:每次选择当前情况下,在对限制值同等贡献量的情况下,对期望值贡献最大的数据。

类比到刚刚的例子,我们每次都从剩下的豆子里面,选择单价最高的,也就是重量相同的情况下,对价值贡献最大的豆子。

第三步,我们举几个例子看下贪心算法产生的结果是否是最优的。大部分情况下,举几个例子验证一下就可以了。严格地证明贪心算法的正确性,是非常复杂的,需要涉及比较多的数学推理。

贪心算法不工作的主要原因是,前面的选择,会影响后面的选择。

贪心算法实战分析

1.分糖果

我们有m个糖果和n个孩子。我们现在要把糖果分给这些孩子吃,但是糖果少,孩子多(m我们可以把这个问题抽象成,从n个孩子中,抽取一部分孩子分配糖果,让满足的孩子的个数(期望值)是最大的。这个问题的限制值就是糖果个数m。

我们每次从剩下的孩子中,找出对糖果大小需求最小的,然后发给他剩下的糖果中能满足他的最小的糖果,这样得到的分配方案,也就是满足的孩子个数最多的方案。

2.钱币找零

这个问题在我们的日常生活中更加普遍。假设我们有1元、2元、5元、10元、20元、50元、100元这些面额的纸币,它们的张数分别是c1、c2、c5、c10、c20、c50、c100。我们现在要用这些钱来支付K元,最少要用多少张纸币呢?

生活中,我们肯定是先用面值最大的来支付,如果不够,就继续用更小一点面值的,以此类推,最后剩下的用1元来补齐。在贡献相同期望值(纸币数目)的情况下,我们希望多贡献点金额,这样就可以让纸币数更少,这就是一种贪心算法的解决思路。

3.区间覆盖

假设我们有n个区间,区间的起始端点和结束端点分别是[l1,r1],[l2,r2],[l3,r3],……,[ln,rn]。我们从这n个区间中选出一部分区间,这部分区间满足两两不相交(端点相交的情况不算相交),最多能选出多少个区间呢?

这个处理思想在很多贪心算法问题中都有用到,比如任务调度、教师排课等等问题。

这个问题的解决思路是这样的:我们假设这n个区间中最左端点是lmin,最右端点是rmax。这个问题就相当于,我们选择几个不相交的区间,从左到右将[lmin,rmax]覆盖上。我们按照起始端点从小到大的顺序对这n个区间排序。

我们每次选择的时候,左端点跟前面的已经覆盖的区间不重合的,右端点又尽量小的,这样可以让剩下的未覆盖区间尽可能的大,就可以放置更多的区间。这实际上就是一种贪心的选择方法。

如何用贪心算法实现霍夫曼编码?

霍夫曼编码用这种不等长的编码方法,编码字符。要求各个字符的编码之间,不会出现某个编码是另一个编码前缀的情况。把出现频率比较多的字符,用稍微短一些的编码;出现频率比较少的字符,用稍微长一些的编码。

假设我有一个包含1000个字符的文件,每个字符占1个byte(1byte=8bits),存储这1000个字符就一共需要8000bits,那有没有更加节省空间的存储方式呢?

假设我们通过统计分析发现,这1000个字符中只包含6种不同字符,假设它们分别是a、b、c、d、e、f。而3个二进制位(bit)就可以表示8个不同的字符,所以,为了尽量减少存储空间,每个字符我们用3个二进制位来表示。那存储这1000个字符只需要3000bits就可以了,比原来的存储方式节省了很多空间。不过,还有没有更加节省空间的存储方式呢?

a(000)、b(001)、c(010)、d(011)、e(100)、f(101)

霍夫曼编码是一种十分有效的编码方法,广泛用于数据压缩中,其压缩率通常在20%~90%之间。

霍夫曼编码不仅会考察文本中有多少个不同字符,还会考察每个字符出现的频率,根据频率的不同,选择不同长度的编码。霍夫曼编码试图用这种不等长的编码方法,来进一步增加压缩的效率。如何给不同频率的字符选择不同长度的编码呢?根据贪心的思想,我们可以把出现频率比较多的字符,用稍微短一些的编码;出现频率比较少的字符,用稍微长一些的编码。

编码不等长,如何读出来解析?

对于等长的编码来说,我们解压缩起来很简单。比如刚才那个例子中,我们用3个bit表示一个字符。在解压缩的时候,我们每次从文本中读取3位二进制码,然后翻译成对应的字符。但是,霍夫曼编码是不等长的,每次应该读取1位还是2位、3位等等来解压缩呢?这个问题就导致霍夫曼编码解压缩起来比较复杂。为了避免解压缩过程中的歧义,霍夫曼编码要求各个字符的编码之间,不会出现某个编码是另一个编码前缀的情况。

假设这6个字符出现的频率从高到低依次是a、b、c、d、e、f。我们把它们编码下面这个样子,任何一个字符的编码都不是另一个的前缀,在解压缩的时候,我们每次会读取尽可能长的可解压的二进制串,所以在解压缩的时候也不会歧义。经过这种编码压缩之后,这1000个字符只需要2100bits就可以了。

尽管霍夫曼编码的思想并不难理解,但是如何根据字符出现频率的不同,给不同的字符进行不同长度的编码呢?

利用大顶堆,根据频率放字符。

分治算法

分治算法(divideandconquer)的核心思想其实就是四个字,分而治之,也就是将原问题划分成n个规模较小,并且结构与原问题相似的子问题,递归地解决这些子问题,然后再合并其结果,就得到原问题的解。

分治算法是一种处理问题的思想,递归是一种编程技巧。实际上,分治算法一般都比较适合用递归来实现。分治算法的递归实现中,每一层递归都会涉及这样三个操作:

分治算法能解决的问题,一般需要满足下面这几个条件:

分治算法应用举例分析

如何编程求出一组数据的有序对个数或者逆序对个数呢?

我们可以将数组分成前后两半A1和A2,分别计算A1和A2的逆序对个数K1和K2,然后再计算A1与A2之间的逆序对个数K3。那数组A的逆序对个数就等于K1+K2+K3。借助归并排序算法

给10GB的订单文件按照金额排序这样一个需求?

我们就可以先扫描一遍订单,根据订单的金额,将10GB的文件划分为几个金额区间。比如订单金额为1到100元的放到一个小文件,101到200之间的放到另一个文件,以此类推。这样每个小文件都可以单独加载到内存排序,最后将这些有序的小文件合并,就是最终有序的10GB订单数据了。

回溯算法

应用场景:深度优先搜索,正则表达式匹配、编译原理中的语法分析。很多经典的数学问题都可以用回溯算法解决,比如数独、八皇后、0-1背包、图的着色、旅行商问题、全排列等等

回溯的处理思想,有点类似枚举搜索。我们枚举所有的解,找到满足期望的解。为了有规律地枚举所有可能的解,避免遗漏和重复,我们把问题求解的过程分为多个阶段。每个阶段,我们都会面对一个岔路口,我们先随意选一条路走,当发现这条路走不通的时候(不符合期望的解),就回退到上一个岔路口,另选一种走法继续走。

八皇后问题

我们有一个8x8的棋盘,希望往里放8个棋子(皇后),每个棋子所在的行、列、对角线都不能有另一个棋子。

1.0-1背包

很多场景都可以抽象成这个问题模型。这个问题的经典解法是动态规划,不过还有一种简单但没有那么高效的解法,那就是今天讲的回溯算法。

我们有一个背包,背包总的承载重量是Wkg。现在我们有n个物品,每个物品的重量不等,并且不可分割。我们现在期望选择几件物品,装载到背包中。在不超过背包所能装载重量的前提下,如何让背包中物品的总重量最大?

对于每个物品来说,都有两种选择,装进背包或者不装进背包。对于n个物品来说,总的装法就有2^n种,去掉总重量超过Wkg的,从剩下的装法中选择总重量最接近Wkg的。不过,我们如何才能不重复地穷举出这2^n种装法呢?

回溯方法:我们可以把物品依次排列,整个问题就分解为了n个阶段,每个阶段对应一个物品怎么选择。先对第一个物品进行处理,选择装进去或者不装进去,然后再递归地处理剩下的物品。

动态规划

0-1背包问题

对于一组不同重量、不可分割的物品,我们需要选择一些装入背包,在满足背包最大重量限制的前提下,背包中物品总重量的最大值是多少呢?

思路:

(1)把整个求解过程分为n个阶段,每个阶段会决策一个物品是否放到背包中。每个物品决策(放入或者不放入背包)完之后,背包中的物品的重量会有多种情况,也就是说,会达到多种不同的状态,对应到递归树中,就是有很多不同的节点。

(2)我们把每一层重复的状态(节点)合并,只记录不同的状态,然后基于上一层的状态集合,来推导下一层的状态集合。我们可以通过合并每一层重复的状态,这样就保证每一层不同状态的个数都不会超过w个(w表示背包的承载重量),也就是例子中的9。

划分n个阶段,每一个阶段基于上一个阶段推导,动态地往前推进,就避免了重复计算。

0-1背包问题升级版

对于一组不同重量、不同价值、不可分割的物品,我们选择将某些物品装入背包,在满足背包最大重量限制的前提下,背包中可装入物品的总价值最大是多少呢?

什么样的问题适合用动态规划来解决呢?

一个模型三个特征

一个模型:多阶段决策最优解模型

三个特征:

两种动态规划解题思路总结

1.状态转移表法

一般能用动态规划解决的问题,都可以使用回溯算法的暴力搜索解决。画出递归树。从递归树中,我们很容易可以看出来,是否存在重复子问题,以及重复子问题是如何产生的

找到重复子问题之后,接下来,我们有两种处理思路,第一种是直接用回溯加“备忘录”的方法,来避免重复子问题。从执行效率上来讲,这跟动态规划的解决思路没有差别。第二种是使用动态规划的解决方法,状态转移表法。

我们先画出一个状态表。状态表一般都是二维的,所以你可以把它想象成二维数组。其中,每个状态包含三个变量,行、列、数组值。我们根据决策的先后过程,从前往后,根据递推关系,分阶段填充状态表中的每个状态。最后,我们将这个递推填表的过程,翻译成代码,就是动态规划代码了。

需要很多变量来表示,那对应的状态表可能就是高维的,比如三维、四维。那这个时候,我们就不适合用状态转移表法来解决了。一方面是因为高维状态转移表不好画图表示,另一方面是因为人脑确实很不擅长思考高维的东西。

2.状态转移方程法

我们需要分析,某个问题如何通过子问题来递归求解,也就是所谓的最优子结构。根据最优子结构,写出递归公式,也就是所谓的状态转移方程。有了状态转移方程,代码实现就非常简单了。一般情况下,我们有两种代码实现方法,一种是递归加“备忘录”,另一种是迭代递推。

min_dist(i,j)=w[i][j]+min(min_dist(i,j-1),min_dist(i-1,j))

我要强调一点,不是每个问题都同时适合这两种解题思路。有的问题可能用第一种思路更清晰,而有的问题可能用第二种思路更清晰,所以,你要结合具体的题目来看,到底选择用哪种解题思路。

状态转移表法解题思路大致可以概括为,回溯算法实现-定义状态-画递归树-找重复子问题-画状态转移表-根据递推关系填表-将填表过程翻译成代码。状态转移方程法的大致思路可以概括为,找最优子结构-写状态转移方程-将状态转移方程翻译成代码。

如何量化两个字符串的相似度?

编辑距离指的就是,将一个字符串转化成另一个字符串,需要的最少编辑操作次数(比如增加一个字符、删除一个字符、替换一个字符)。编辑距离越大,说明两个字符串的相似程度越小;相反,编辑距离就越小,说明两个字符串的相似程度越大。对于两个完全相同的字符串来说,编辑距离就是0。

编辑距离有多种不同的计算方式,比较著名的有莱文斯坦距离(Levenshteindistance)和最长公共子串长度(Longestcommonsubstringlength)。其中,莱文斯坦距离允许增加、删除、替换字符这三个编辑操作,最长公共子串长度只允许增加、删除字符这两个编辑操作。

莱文斯坦距离和最长公共子串长度,从两个截然相反的角度,分析字符串的相似程度。莱文斯坦距离的大小,表示两个字符串差异的大小;而最长公共子串的大小,表示两个字符串相似程度的大小。

两个字符串mitcmu和mtacnu的莱文斯坦距离是3,最长公共子串长度是4。

如何编程计算莱文斯坦距离?

这个问题是求把一个字符串变成另一个字符串,需要的最少编辑次数。整个求解过程,涉及多个决策阶段,我们需要依次考察一个字符串中的每个字符,跟另一个字符串中的字符是否匹配,匹配的话如何处理,不匹配的话又如何处理。所以,这个问题符合多阶段决策最优解模型。

推荐算法

利用向量的距离,求相似成度。

搜索:如何用A*搜索算法实现游戏中的寻路功能?

那如何快速找出一条接近于最短路线的次优路线呢?

这个快速的路径规划算法,就是我们今天要学习的A*算法。实际上,A*算法是对Dijkstra算法的优化和改造。

通过这个顶点跟终点之间的直线距离,也就是欧几里得距离来近似地估计这个顶点跟终点的路径长度(注意:路径长度跟直线距离是两个概念)

这个距离记作h(i)(i表示这个顶点的编号),专业的叫法是启发函数(heuristicfunction)

因为欧几里得距离的计算公式,会涉及比较耗时的开根号计算,所以,我们一般通过另外一个更加简单的距离计算公式,那就是曼哈顿距离(Manhattandistance)

曼哈顿距离是两点之间横纵坐标的距离之和。计算的过程只涉及加减法、符号位反转,所以比欧几里得距离更加高效。

inthManhattan(Vertexv1,Vertexv2){//Vertex表示顶点,后面有定义

returnMath.abs(v1.x-v2.x)+Math.abs(v1.y-v2.y);

}

f(i)=g(i)+h(i),顶点与起点之间的路径长度g(i),顶点到终点的路径长度估计值h(i).f(i)的专业叫法是估价函数(evaluationfunction)。

A*算法就是对Dijkstra算法的简单改造,f(i)最小的先出列。

它跟Dijkstra算法的代码实现,主要有3点区别:

java怎么学习?java怎么入门?java在哪学?java怎么学才快?不用担心,这里为大家提供了java速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

THE END
1.程序员高手必会的十大编程算法编程算法有哪些程序员高手必会的十大编程算法 算法(Algorithm)是指解题方案的准确而完整的描述,是一系列解决问题的清晰指令,算法代表着用系统的方法描述解决问题的策略机制。也就是说,能够对一定规范的输入,在有限时间内获得所要求的输出。如果一个算法有缺陷,或不适合于某个问题,执行这个算法将不会解决这个问题。不同的算法可能用https://blog.csdn.net/liuhaiabc/article/details/52663417
2.什么是GC算法?有哪些GC算法?–编程技术之美有哪些GC算法? GC算法指垃圾回收算法,是自动内存管理的一种方式。它的主要目的是回收未使用的内存,释放内存空间以供后续使用。 主要的GC算法有: 引用计数算法:给每个对象添加一个引用计数器,当有一个地方引用它时,计数器值加1;当引用失效时,计数器值减1;计数器值为0时回收对象。优点是实现简单,缺点是无法回收http://www.itzhimei.com/archives/4629.html
3.28个不得不看的经典编程算法发起人的描述:《来自圣经的证明》收集了数十个简洁而优雅的数学证明,迅速赢得了大批数学爱好者的追捧。如果还有一本《来自圣经的算法》,哪些算法会列入其中呢? ***名:Union-find 严格地说,并查集是一种数据结构,它专门用来处理集合的合并操作和查询操作。并查集巧妙地借用了树结构,使得编程复杂度降低到了令人难以置https://mobile.51cto.com/news-455988.htm
4.常用编程思想与算法JeffD本文是在阅读Aditya Bhargava先生算法图解一书所做的总结,文中部分代码引用了原文的代码,在此感谢Aditya Bhargava先生所作出的这么简单的事例,对基础算法感兴趣的朋友可以阅读原文。由于本人也是编程初学者,所以本书比较浅显易懂,所介绍的算法配上插图也十分易懂,这里只是介绍几种最基础的算法由浅入深以帮助理顺一些简单https://www.cnblogs.com/Jeffding/p/7425230.html
5.编程和数学有什么区别?编程和数学都需要很高的抽象思维能力,两者在很多地方都有共同之处。编程中的很多算法都来自于数学理论的支持,但两者在具体的应用逻辑上还是存在一定的差别。比如:对任意给定的一组数进行排序,使之从大到小进行排列。 这是一个编程的入门问题,但它就很难称得上是一个数学问题。类似这种问题,我们人类看起来可能很简单http://shaoer.cctv.com/m/a/index.shtml?id=ARTIiBhAaPjbYAQLuiq8b0jg170418
6.Java面试题大全(整理版)1000+面试题附答案详解最全面看完稳了Java 并发编程(一) 1、在 java 中守护线程和本地线程区别? 2、线程与进程的区别? 3、什么是多线程中的上下文切换? 4、死锁与活锁的区别,死锁与饥饿的区别? 5、Java 中用到的线程调度算法是什么? 6、什么是线程组,为什么在 Java 中不推荐使用? https://maimai.cn/article/detail?fid=1752437513&efid=uSgZIWSJqvkGwxf4vJW75w
7.Java集合面试问题40个「附答案」每种编程语言中都有集合,最初的Java版本包含几种集合类:Vector、Stack、HashTable和Array。 随着集合的广泛使用,Java1.2提出了囊括所有集合接口、实现和算法的集合框架。在保证线程安全的情况下使用泛型和并发集合类,Java已经经历了很久。它还包括在Java并发包中,阻塞接口以及它们的实现。 https://www.oh100.com/kaoshi/java/370200.html
8.Python基础知识Python编程基础算法Python作为目前编程开发的主流语言之一,在企业中的应用范围越来越广,广阔的发展前景吸引了很多小伙伴想要入行Python,在学习Python时,一定要对基础技术知识有一个良好的了解,这样才会事半功倍,今天八维职业学校就和大家一起来看看Python编程中的基础算法,希望对各位学子有帮助。 https://www.bwie.com/jsgh/66.html
9.机器学习常见算法类型都有哪些算法是程序员在学习软件编程开发技术的时候需要重点掌握的一个编程开发技术知识,而今天我们就通过案例分析来了解一下,机器学习常见算法类型都有哪些。 1.分类算法 这是一种监督学习方法。有很多算法帮助我们解决分类问题,比如K近邻、决策树、朴素贝叶斯、贝叶斯网络、逻辑回归、SVM等算法。人工神经网络和深度学习也往往用https://www.douban.com/note/782408490/
10.C程序设计常用算法代码litan1986一、计数、求和、求阶乘等简单算法 此类问题都要使用循环,要注意根据问题确定循环变量的初值、终值或结束条件,更要注意用来表示计数、和、阶乘的变量的初值。 例:用随机函数产生100个[0,99]范围内的随机整数,统计个位上的数字分别为1,2,3,4,5,6,7,8,9,0的数的个数并打印出来。 http://blog.chinaunix.net/uid-22327815-id-1775075.html
11.什么是机器学习常见的机器学习算法有哪些什么是机器学习常见的机器学习算法有哪些 机器学习是人工智能领域中的一个重要分支,它通过使用大量的数据和算法,使计算机系统能够自动学习和改进,而无需显式的编程指令。机器学习算法是机器学习的核心组成部分,它们对数据进行分析和模式识别,从而实现预测、分类和决策等任务。本文将介绍机器学习的基本概念,并介绍几种常见https://wenku.baidu.com/view/9b19f784dd80d4d8d15abe23482fb4daa58d1d9e.html
12.KeilFlashProgramming(1)闪存编程 Flash编程算法是一种用于擦除应用程序或将应用程序下载到Flash设备的软件。具有设备支持的包通常包含预定义的Flash算法,用于对DFP支持的设备进行编程。ARhttps://www.jianshu.com/p/4c1e08a4d5d1