五大常用算法学习笔记

一、分治算法:快速排序、归并排序、大整数乘法、二分查找、递归(汉诺塔)

  1. 基本概念:把一个复杂的问题分成若干个相同或相似的子问题,再把子问题分成更小的子问题… , 知道最后子问题可以简单的直接求解,原问题的解即子问题的解的合并。

看上去有点类似Fork/Join框架,或map-reduce。

排序算法中的快速排序、归并排序都是使用的分治算法。

  1. 分治算法的适用场景:
    1)当问题规模缩小到一定的程度就可以很容易解决
    2)该问题可以分解为若干个规模较小的相同问题
    3)该问题分解出的若干子问题的解可以合并为该问题的解
    4)每个子问题都是独立的,相互之间没有交集。
  2. 使用分治法的经典场景:
    1)二分搜索
    2)大整数乘法
    3)合并排序
    4)快速排序
    5)汉诺塔
  3. 分治算法经典例题:
    输入一组整数,求出这组数字子序列和中最大值。也就是求出最大子序列的和,不必求出最大的那个序列。例如:序列:-2, 11, -1, 13, -5, -2 , 则最大子序列的和为20。
public static void main(String[] args) {int[] a = { -2, 11, -4, 13, -5, -2 };// 最大子序列和为20int[] b = { -6, 2, 4, -7, 5, 3, 2, -1, 6, -9, 10, -2 };// 最大子序列和为16System.out.println(maxSubSum1(a));System.out.println(maxSubSum4(b));
}// 最大子序列求和算法一
public static int maxSubSum1(int[] a) {int maxSum = 0;// 从第i个开始找最大子序列和for (int i = 0; i < a.length; i++) {// 找第i到j的最大子序列和for (int j = i; j < a.length; j++) {int thisSum = 0;// 计算从第i个开始,到第j个的和thisSumfor (int k = i; k <= j; k++) {thisSum += a[k];}// 如果第i到第j个的和小于thisSum,则将thisSum赋值给maxSumif (thisSum > maxSum) {maxSum = thisSum;}}}return maxSum;
}// 时间复杂度O(n的平方)
public static int maxSubSum2(int[] a) {int maxSum = 0;for (int i = 0; i < a.length; i++) {// 将sumMax放在for循环外面,避免j的变化引起i到j的和sumMax要用for循环重新计算int sumMax = 0;for (int j = i; j < a.length; j++) {sumMax += a[j];if (sumMax > maxSum) {maxSum = sumMax;}}}return maxSum;
}// 递归,分治策略
// 2分logn,for循环n,时间复杂度O(nlogn)
public static int maxSubSum3(int[] a) {return maxSumRec(a, 0, a.length - 1);
}public static int maxSumRec(int[] a, int left, int right) {// 递归中的基本情况if (left == right) {if (a[left] > 0)return a[left];elsereturn 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;}// 返回最大子序列在左侧,在右侧,在中间求出的值中的最大的return max3(maxLeftSum, maxRightSum, maxLeftBorderSum + maxRightBorderSum);
}public static int max3(int a, int b, int c) {return a > b ? (a > c ? a : c) : (b > c ? b : c);
}// 时间复杂度:O(n); 任何a[i]为负时,均不可能作为最大子序列前缀;任何负的子序列不可能是最有子序列的前缀
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;
}

二、动态规划算法

  1. 基本概念:将待求解的问题分解为若干个子问题,按顺序求解子问题,前一问题的解,为后一问题的求解提供有用的信息。在求解任一子问题时,列出各种可能的局部解,通过决策保留那些有可能达到最优的局部解,丢弃其他局部解。依次解决各种子问题,最后一个子问题就是初始问题的解。
    由于动态规划算法解决的问题是有重叠的子问题,为了减少重复计算,对每一个子问题只解一次,将其不同阶段的不同状态保存在一个二维数组中。

动态规划算法以分治算法类似,不同在于:适合于动态规划算法求解的问题,经分解后得到的子问题,往往不是互相独立的,而是下一个子阶段的求解是建立在上一个子阶段的解的基础上,进行进一步求解的。

  1. 动态规划的适用场景
    1)最优化原理:该问题的最优解所包含的子问题的解也是最优的。
    2)无后效性:某阶段状态一旦确定,就不受这个状态以后决策的影响。即某状态以后的过程不会影响以前的状态,只与当前状态有关。
    3)有重叠子问题:即子问题之间不相互独立,一个子问题的解在下一阶段决策中可能被多次使用到。
  2. 经典问题:
    给定两个字符串str1和str2,返回两个字符串的最长公共子序列,例如:str1=“1A2C3D4B56",str2=“B1D23CA45B6A”,"123456"和"12C4B6"都是最长公共子序列,返回哪一个都行。

分析:这事经典的动态规划问题,假设str1的长度为M, str2的长度为N, 则生成M*N的二维数组dp, dp[i][j]的含义是str1[0…i]与str2[0…j]的最长公共子序列的长度。

dp值的求法如下:
dp[i][j]的值比如和dp[i-1][j], dp[i][j-1]相关,结合下面的代码来看,实际上从第一行和第一列开始计算的,

public static void main(String[] args) {String A = "1A2C3D4B56";String B = "B1D23CA45B6A";System.out.println(findLCS(A, A.length(), B, B.length()));
}public static int findLCS(String A, int Alen, String B, int Blen) {int dp[][] = new int[Alen+1][Blen+1];for (int i = 0; i < Alen; i++) {for (int j = 0; j < Blen; j++) {if (A.charAt(i) == B.charAt(j)) {dp[i + 1][j + 1] = dp[i][j] + 1;} else {dp[i + 1][j + 1] = Math.max(dp[i + 1][j], dp[i][j + 1]);}}}return dp[Alen][Blen];
}

三、贪心算法

贪心算法是通过局部最优解来达到全局最优解。

  1. 下面是一个可以试用贪心算法解的题目,贪心解的确不错,可惜不是最优解。

    [背包问题]有一个背包,背包容量是M=150。有7个物品,物品可以分割成任意大小。

    要求尽可能让装入背包中的物品总价值最大,但不能超过总容量。

    物品 A B C D E F G

    重量 35 30 60 50 40 10 25

    价值 10 40 30 50 35 40 30

    分析:
    目标函数: ∑pi最大

约束条件是装入的物品总重量不超过背包容量,即∑wi<=M( M=150)
1)根据贪心的策略,每次挑选价值最大的物品装入背包,得到的结果是否最优呢?
2)每次挑选重量最小的物品装入背包,是否能得到最优解?
3)每次选取单位重量价值最大的物品,成为解本地的策略?

贪心算法简单易行,但贪心算法需要证明后才能真正运用到算法中。一般来说,贪心算法的证明围绕着整个问题的最优解一定由在贪心策略中存在的子问题的最优解得来的。

对于本题的三种贪心策略,都无法成立,即无法被证明。解释如下:

1)选取价值最大者。
反例:W=30
物品:A B C
重量:28 12 12
价值:30 20 20

根据策略,选A, 但选BC最合适

2)选取重量最小,反例与上述类似

3)选取单位重量价值最大的物品。反例:
W=30
物品:A B C
重量:28 20 10
价值:28 20 10

根据策略,三种物品单位重量价值一样,程序无法依据现有策略作出判断,如果选择A,则答案错误。

2)贪心算法的经典案例:
设有n个正整数,将他们连成一排,组成一个最大的多位整数。
例如:n=3时,3个整数13,312,343,连成的最大整数为34331213。
又如:n=4时,4个整数7,13,4,246,连成的最大整数为7424613。

要求输入:n, N个数
输出:连成的多位数

算法分析:该题很容易想到贪心法,但解题时很多人把整数按从大到小的顺序连接起来,测试题目的例子也都符合,但结果不对。例如:我们很容易找到12, 121应该组成12121而非12112, 但如12, 123呢,就是12312,而不是12123。所以,通过整数排序的方法是不对的。

结论:该题可以用贪心算法,只是刚才采用的贪心策略不对。正确的贪心算法的标准是:先把整数转成字符串,然后再比较a+b和b+a, 如果a+b >= b+a, 就把a排在b前面, 反之把a排在b后面。

四、回溯算法

1.基本概念:回溯算法是一个类似枚举的搜索尝试过程,主要在搜索尝试过程中寻找问题的解,当发现已不满足求解条件时,就“回溯”返回,尝试别的路径。深度优先。

回溯算法是一种选优搜索法,按选优条件向前搜索,以达到目标。当搜索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术成为回溯法,而满足回溯条件的某个状态的点成为“回溯点”。

对于回溯算法的简单描述是:把问题的解空间转化为图或树的结构,然后使用深度优先进行遍历,遍历过程中寻找所有可行解,从而找到最优解。

其基本思想类似于:图的深度优先搜索;二叉树的后序遍历。

回溯法的详细描述为:回溯法按深度优先搜索解空间树。首先从根节点出发,当搜索到解空间数的某一节点时,先利用剪枝函数判断该节点是否可行(即能得到问题的解)。如果不可行,则跳过对该节点为根的子树的搜索,逐层向其祖先节点回溯;否则,进入该子树,继续按深度优先策略搜索。
2. 回溯算法的实现:递归和迭代

1.回溯算法的经典问题:0-1背包问题

有n种物品和一个背包,第i种物品的重量是wi,其价值为pi,背包的容量为c. 问:怎样把物品装入背包,背包中的物品的总价值最大。

分析:从n种物品中选择部分物品,这样的题目解空间是子集树。例如,当物品的种类数为3是,其解空间如下图:
在这里插入图片描述
边1表示选择该物品,边0表示不选择该物品。这样,这个树从根节点到叶子节点,包含了把物品放入背包的所有可能性。
回溯搜索过程,如果来到了叶子节点,表示一条搜索路径结束,如果该路径上存在更优的解,则保存下来,如果不是叶子节点,是中间的节点(如B), 就遍历其子节点(D和E), 如果子节点满足剪枝条件,就继续回溯搜索子节点。

五、分支限界算法

  1. 基本概念

类似于回溯法,也是一种在问题的解空间树T上搜索问题解的算法。但在一般情况下,分支限界法与回溯法的求解目标不同。回溯法的求解目标是找出解空间树中满足约束条件的所有解,而分支限界法的求解目标则是满足约束条件的一个解,或是从满足约束条件的解中找出使某一目标函数值达到极大或极小的解,即在某种意义下的最优解。

分支限界法的基本思想是对有约束条件的最优化问题的所有可行解(数目有限)空间进行搜索。该算法在具体执行时,把全部可行的解空间不断分割为越来越小的自己(成为分支),并为每个自己内的解的值计算一个下界或上界(成为界定)。

在每次分支后,对凡是界限超出已知可行解值的那些子集不再做进一步分支。这样,解的许多子集(即搜索树上的许多节点)就可以不必考虑了,从而缩小了搜索范围。这一过程一直进行到找出可行解为止,该可行解的值不大于任务子集的界限,因此这种算法一般可以求得最优解。

将问题分支为子问题,并对这些子问题定界的步骤称为分支定界法。

知识附录:深度优先搜索和广度优先搜索

1)广度优先搜索:使用队列的先进先出
在这里插入图片描述
2)深度优先搜索:
在这里插入图片描述
2. 分支限界法的经典问题:旅行售货员问题

1)问题描述:某售货员要到若干城市去卖商品,已知各城市之间的路程。他要选定一条从驻地出发,经过每个城市一次,最后回到驻地的路线,使总的路程最小。

下图为1,2,3,4 四个城市及路线图,任意两个城市之间不一定都有路可达。
在这里插入图片描述
2)问题理解:
分支限界法利用:广度优先搜索和最优值策略
利用二位数组保存图信息,一旦一个城市没有通向另外城市的路,则不可能有回路,不用再找下去了。
我们任意选择一个城市,作为出发点(因为最后都是一个回路,从哪出发都一样)

3)关键思路:
想象一下,我们就是旅行员,从城市1出发,根据广度优先搜索的思路,我们要把从城市1能到达的下一个城市,都要作为一种路径走一下试试。可在程序里面怎样实现这种“试试”呢?

答案是:可以利用一种数据结构,保存我们每走一步后,当前的一些状态参数。比如,我们已经走过的城市数目(这样就知道,我们有没有走完,比如上图,当我们走了四个城市之后,无论从第四个城市是否能回到起点城市,都意味着我们走完了,只是这条路径合不合约束以及能不能得到最优解的问题)。我们把这种保存状态参数的数据结构定义成Node。需要另一个数据结构用来保存我们每次试出来的路径,这就是MiniHeap

Node{int s; //结点深度,即当前走过了几个城市int x[MAX_SIZE]; //保存走到这个结点时的路径信息
}
MiniHeap{//保存所有结点并提供一些结点的操作
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/556052.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

8客户端安装后无法启动_新君越涉水后车辆无法启动

车型&#xff1a;2010君越故障现象&#xff1a;涉水后车辆无法启动询问客户&#xff1a;涉水的水深10cm左右。 外观检查&#xff1a;TCM连接器进水、其它没发现进水迹象使用压缩空气吹干TCM连接器的进水&#xff0c;并处理机舱的接地点。GDS检测&#xff1a;U0074,控制模块通信…

Java中的return this

Java中的return this return this就是返回当前对象的引用(就是实际调用这个方法的实例化对象) 示例&#xff1a; /*** 资源url*/public HttpConfig url(String url) {urls.set(url);//return this就是返回当前对象的引用(就是实际调用这个方法的实例化对象)return this;}调用…

mybatis 依赖于jdbc_大数据基础:Mybatis零基础入门

在Java企业级开发任务当中&#xff0c;持久层框架的选择&#xff0c;国内市场的主流选择一定有Mybatis的一席之地&#xff0c;从入门来说&#xff0c;Mybatis的学习难度不算高&#xff0c;但是要把Mybatis发挥出真正的效用&#xff0c;还是需要深入学习的。今天的大数据基础分享…

kendo treeview 修改节点显示值_VBA学习笔记60-1: Treeview控件

学习资源&#xff1a;《Excel VBA从入门到进阶》第60集 by兰色幻想本节讲Treeview控件。TreeView控件是以树形结构显示数据的控件。利用TreeView控件&#xff0c;可以设计出树形结构图&#xff0c;便于用户选择不同的项目。总公司人事结构是一级节点&#xff0c;公司一、公司二…

Java之路:this关键字的用法

&#xff08;1&#xff09;this代表当前对象的一个引用。所谓当前对象&#xff0c;指的是调用类中方法或属性的那个对象。 最经常使用this关键字的情况&#xff0c;是在对象的一个属性被方法或构造器的参数屏蔽时&#xff0c;需要调用这个被屏蔽的属性&#xff0c;如下&#xf…

跑分cpu_一加8T现身跑分网站:CPU正式敲定 10月15日见

一加8T将于10月15日发布(海外版将于10月14日发布)&#xff0c;现在关于一加8T的核心规格确认。今天&#xff0c;一加8T现身GeekBench跑分网站&#xff0c;确认该机搭载的是高通骁龙865旗舰处理器&#xff0c;而非高通骁龙865 Plus。与搭载高通骁龙865的一加8相比&#xff0c;一…

发那科攻丝回退参数_乐享:发那科MF选配功能诊断小结

小编微信&#xff1a;shukong99999乐享数控&#xff0c;专注数控电气乐享那科选项功能小结大家好&#xff0c;我是乐享数控&#xff0c;好久不见&#xff0c;今天起&#xff0c;给大家多总结&#xff0c;相互交流进步。1发那科MF选项功能诊断小结在调试过程中&#xff0c;除了M…

matlab怎么画二维热力图_[原创]Day3.箱线图和热力图的绘制

使用Matplotlib和Seaborn进行绘制箱线图和热力图。箱线图箱线图(boxplot)又称盒式图&#xff0c;可以显示数据的分散情况&#xff0c;由五个数值点组成&#xff1a;最大值(max)-上界、最小值(min)-下界、中位数(median)和上下四分位数(Q1, Q3)。它可以帮我们分析出数据的差异性…

vue图片点击超链接_10秒钟,告别ppt中难看的超链接

我相信大多数同学在创建超链接的时候都很疑惑为什么字体颜色会变成蓝色&#xff0c;且下方会出现一条横线&#xff0c;能不能把横线去掉或者改变颜色呢&#xff1f;零壹君回答你&#xff1a;能&#xff01;快来跟零壹君一起学习吧&#xff01;选中文字—点击【插入】—【超链接…

arr数组怎么取值_记一次思否问答的问题思考:Vue为什么不能检测数组变动

作者 | hfhan来源 | https://segmentfault.com/a/1190000015783546问题描述&#xff1a;Vue检测数据的变动是通过Object.defineProperty实现的&#xff0c;所以无法监听数组的添加操作是可以理解的&#xff0c;因为是在构造函数中就已经为所有属性做了这个检测绑定操作。但是官…

使用 ref 对已渲染到页面的节点进行标记

一、字符串形式的 ref <input type"text" /*给标签打上标记 ipt */ ref"ipt" />拿到标记的节点&#xff0c;对其进行操作 handleClick () > {console.log(this);// 用 ref 标记了的标签&#xff0c;都会保存在 refs 里面console.log(this.refs…

JAVA之private修饰成员方法默认是final型的?

Java之private修饰成员方法默认是final型的&#xff1f; private修饰的成员方法默认是final型的&#xff1f; 用fianl声明的成员方法是最终方法&#xff0c;最终方法不能被子类覆盖&#xff08;重写&#xff09; 从表面上看这个命题是错误的&#xff0c;private访问修饰符修饰…

程序员你真的理解final关键字吗?

文章目录1、修饰类2、修饰方法3、修饰变量4、final变量修饰变量&#xff08;成员变量、局部变量&#xff09;4、1 final修饰成员变量&#xff1a;4、2 final修饰局部变量&#xff1a;5、final变量和普通变量的区别6、final与static的藕断丝连7、关于final修饰参数的争议前言 提…

axios vue 动态date_Web前端Vue系列之-Vue.js 实战

课程简介&#xff1a;课程目标&#xff1a;通过本课程的学习&#xff0c;让大家掌握Vue.js的进阶知识并在项目中应用。适用人群&#xff1a;具有一定vue开发基础的开发人员。课程概述&#xff1a;Vue (读音 /vjuː/&#xff0c;类似于 view) 是一套用于构建用户界面的渐进式Jav…

vue 组件 - 非单文件组件

一、定义组件 const school Vue.extend({name: xuexiao, // ----------------------------> 指定组件在开发者工具中显示的名字template: // ----------------------------> 模板<div>... 此处是结构</div>,data() { // ---------------------------->…

matlab安装好 启动总是闪退_在Ubuntu16.04下安装MATLAB2017b

1. 前言最近在折腾Ubuntu系统的高端机子&#xff0c;matlab这家伙的交互和可视化太方便了&#xff01;于是想在Linux下安装matlab&#xff0c;在各个版本中&#xff0c;matlab2017的性价比是非常高的&#xff0c;因此选择安装介个。阅读了很多帖子&#xff0c;综合找到几个靠谱…

vue 脚手架

一、 脚手架 初始 全局安装脚手架 npm i -g vue/cli切换到项目根目录&#xff0c;使用 vue create 项目名称 创建项目使用 npm run serve | yarn serve 启动项目 如果中途卡顿 使用 npm 淘宝镜像 npm config set registry --> https://registry.npm.taobao.orgvue 隐藏了…

这篇文章绝对让你深刻理解java类的加载以及ClassLoader源码分析

前言 package com.jvm.classloader;class Father2{public static String strFather"HelloJVM_Father";static{System.out.println("Father静态代码块");} }class Son2 extends Father2{public static String strSon"HelloJVM_Son";static{Syste…

bigdecimal js 判断等于0_为啥阿里禁用BigDecimal的equals方法做等值比较

BigDecimal&#xff0c;相信对于很多人来说都不陌生&#xff0c;很多人都知道它的用法&#xff0c;这是一种java.math包中提供的一种可以用来进行精确运算的类型。很多人都知道&#xff0c;在进行金额表示、金额计算等场景&#xff0c;不能使用double、float等类型&#xff0c;…

git提交到github总是要输入密码_GitHub不为人知的秘密

本来想叫《GitHub骚操作》的&#xff0c;发现相关的文章已经有很多&#xff0c;而且和我本章要讲的内容完全不同&#xff0c;所以就换了这个也算贴切的标题。起因之前写过一篇文章《VM Manager 插件分享》&#xff0c;事后我发现有个地方不对劲&#xff01;看之前文章标题大家应…