Authonr: Lijb算法
Email: lijb1121@163.com数组
五大经常使用算法简介安全
一、递归与分治 递归算法:直接或者间接不断反复调用自身来达到解决问题的方法。这就要求原始问题能够分解成相同问题的子问题。 示例:阶乘、斐波纳契数列、汉诺塔问题 斐波纳契数列:又称黄金分割数列,指的是这样一个数列:一、一、二、三、五、八、1三、2一、……在数学上,斐波纳契数列以以下被以递归的方法定义:F1=1,F2=1,Fn=F(n-1)+F(n-2)(n>2,n∈N*))。 分治算法:待解决复杂的问题可以简化为几个若干个小规模相同的问题,而后逐步划分,达到易于解决的程度。 一、将原问题分解为n个规模较小的子问题,各子问题间独立存在,而且与原问题形式相同 二、递归的解决各个子问题 三、将各个子问题的解合并获得原问题的解 示例:棋盘覆盖、找出伪币、求最值 棋盘覆盖:在一个(2^k)*(2^k)个方格组成的棋盘上,有一个特殊方格与其余方格不一样,称为特殊方格,称这样的棋盘为一个特殊棋盘。要求对棋盘的其他部分用L型方块填满 二、动态规划 动态规划与分治法类似,都是组合子问题的解来解决原问题的解,与分治法的不一样在于:分治法的子问题是相互独立存在的,而动态规划应用于子问题重叠的状况。 动态规划方法一般用来求解最优化问题,这类问题能够有不少可行解,每一个解都有一个值,找到具备最优值的解称为问题的一个最优解,而不是最优解,可能有多个解都达到最优值。 设计动态规划算法的步骤: 一、刻画一个最优解的结构特征 二、递归地定义最优解的值 三、计算最优解的值,一般采用自底向上的方法 四、利用算出的信息构造一个最优解 示例:0-1背包问题,钢条切割问题等。 三、贪心算法 贪心算法是就问题而言,选择当下最好的选择,而不从总体最优考虑,经过局部最优但愿致使全局最优。 贪心算法的要素 1)贪心选择性质:能够经过局部最优选择来构造全局最优解。换言之,直接作出在当前问题中看来最优的选择,而没必要考虑子问题的解。 2)最优子结构:一个问题的最优解包含其子问题的最优解。 贪心算法的设计步骤: 1)将最优化问题转换为这样的形式:对其作出一次选择后,只剩下一个子问题须要求解 2)证实作出贪心选择后,原问题老是存在最优解,即贪心选择老是安全的 3)证实作出贪心选择后,剩余的子问题知足性质:其最优解与贪心选择组合便可获得原问题的最优解,这样就获得了最优子结构。 示例:背包问题,均分纸牌,最大整数 四、回溯法 回溯法是一种搜索算法,从根节点出发,按照深度优先搜索的策略进行搜索,到达某一节点后 ,探索该节点是否包含该问题的解,若是包含则进入下一个节点进行搜索,如果不包含则回溯到父节点选择其余支路进行搜索。 回溯法的设计步骤: 1)针对所给的原问题,定义问题的解空间 2)肯定易于搜索的解空间结构 3)以深度优先方式搜索解空间,并在搜索过程当中用剪枝函数除去无效搜索。 示例:0-背包问题、旅行商问题、八皇后问题 五、 分支限界法 和回溯法类似,也是一种搜索算法,但回溯法是找出问题的许多解,而分支限界法是找出原问题的一个解。或是在知足约束条件的解中找出使某一目标函数值达到极大或极小的解,即在某种意义下的最优解 在当前节点(扩展节点)处,先生成其全部的儿子节点(分支),而后再从当前的活节点(当前节点的子节点)表中选择下一个扩展节点。为了有效地选择下一个扩展节点,加速搜索的进程,在每个活节点处,计算一个函数值(限界),并根据函数值,从当前活节点表中选择一个最有利的节点做为扩展节点,使搜索朝着解空间上有最优解的分支推动,以便尽快地找出一个最优解。 分支限界法: 1)FIFO分支限界法 3)优先队列分支限界法:按照优先队列中规定的优先级选取优先级最高的节点成为当前扩展节点。 示例:装载问题,旅行售货员问题
动态规划算法函数
编辑距离问题优化
什么是两个字符串的编辑距离(edit distance)?给定字符串s1和s2,以及在s1上的以下操做:.net
试问最小须要多少次这样的操做才能使得s1转换为s2?设计
好比,单词“cat”和“hat”,这样的操做最少须要一次,只须要把“cat”中的“c”替换为“h”便可。单词“recall”和“call”,这样的操做最少须要两次,只须要把“recall”中的“r”和“e”去掉便可。单词“Sunday”和“Saturday”,这样的操做最少须要3次,在“Sunday”的“S”和“u”中插入“a”和“t”,再把“n”替换成“r”便可。code
那么,是否存在一种高效的算法,可以快速、准确地计算出两个字符串的编辑距离呢?递归
动态规划算法队列
咱们使用动态规划算法(Dynamic Programming)来计算出两个字符串的编辑距离。 咱们从两个字符串s1和s2的最末端向前遍从来考虑。假设s1的长度为m,s2的长度为n,算法以下:
这样,咱们就有了子结构问题。对于动态规划算法,咱们还须要一个初始化的过程,而后中间维护一张二维表便可。初始化的过程以下: 若是m为0,则至少须要操做n次,即在s1中逐个添加s2的字符,一共是n次;若是n为0,则至少须要操做m次,即把s1的字符逐个删除便可,一共是m次。
Python实现
利用DP算法解决两个字符串的编辑距离的Python代码以下:
''' [@author](https://my.oschina.net/arthor) lijb [@company](https://my.oschina.net/u/3478402) 东网科技 [@date](https://my.oschina.net/u/2504391) 2019/3/22 10:06 ''' #使用动态规划算法计算字符串的编辑距离 #传入两个字符串类型的参数 def edit_distance(s1, s2): m, n = len(s1), len(s2) #建立数组 dp = [[0 for _ in range(n+1)] for _ in range(m+1)] # 使用动态规划算法 for i in range(m + 1): for j in range(n + 1): if i == 0: dp[i][j] = j elif j == 0: dp[i][j] = i elif s1[i-1] == s2[j-1]: dp[i][j] = dp[i-1][j-1] else: dp[i][j] = 1 + min(dp[i][j-1], # Insert dp[i-1][j], # Remove dp[i-1][j-1]) # Replace return dp[m][n] # Driver program str1 = "ljb" str2 = "lijb" edit_dist = edit_distance(str1, str2) print("The Edit Distance of '%s' and '%s' is %d."%(str1, str2, edit_dist))
输出结果以下:
The Edit Distance of 'ljb' and 'lijb' is 1.
Java实现
利用DP算法解决两个字符串的编辑距离的Java代码以下:
package com.neunn; /** * [@author](https://my.oschina.net/arthor) lijb * [@company](https://my.oschina.net/u/3478402) 东网科技 * @date 2019/3/22 10:06 */ public class Dynamic_Programming { public static void main(String[] args) { String str1 = "lijb"; String str2 = "ljb"; int edit_dist = edit_distance(str1, str2); System.out.println("The Edit Distance of" + str1 + " and " + str2 + " is: " + edit_dist); } /** * 计算两个字符串的编辑距离(Edit Distance) * @param str1 字符串参数1 * @param str2 字符串参数2 * @return 编辑距离 */ public static int edit_distance(String str1, String str2) { int m = str1.length(); int n = str2.length(); // 初始化表格,用于维护子问题的解 int[][] dp = new int[m + 1][n + 1]; for (int i = 0; i <= m; i++) for (int j = 0; j <= n; j++) dp[i][j] = 0; /** * 使用动态规划算法 */ for (int i = 0; i <= m; i++) { for (int j = 0; j <= n; j++) { if (i == 0) { dp[i][j] = j; } else if (j == 0) { dp[i][j] = i; } else if (str1.charAt(i - 1) == str2.charAt(j - 1)) { dp[i][j] = dp[i - 1][j - 1]; } else { /* * dp[i][j-1]: Insert * dp[i-1][j]: Remove * dp[i-1][j-1]: Replace */ dp[i][j] = 1 + min(min(dp[i][j - 1], dp[i - 1][j]), dp[i - 1][j - 1]); } } } return dp[m][n]; } public static int min(int i, int j) { return (i <= j) ? i : j; } }
输出结果以下:
The Edit Distance of ljb and lijb is: 1
Scala实现
利用DP算法解决两个字符串的编辑距离的Scala代码以下:
package com.neunn /** * @author lijb * @company 东网科技 * @date 2019/3/22 10:19 */ class Dynamic_Programming { } object Dynamic_Programming { def main(args: Array[String]): Unit = { val str1 = "ljb"; val str2 = "lijb"; val edit_dist = edit_distance(str1, str2) println("The Edit Distance of " + str1 + " and " + str2 + " is: " + edit_dist); } def edit_distance(str1: String, str2: String): Int = { val m = str1.length val n = str2.length /** * 建立数组并初始化 */ val dp = Array.ofDim[Int](m + 1, n + 1) for (i <- 0 to m) { for (j <- 0 to n) { dp(i)(j) = 0 } } /** * 使用动态规划算法 */ for (i <- 0 to m) { for (j <- 0 to n) { if (i == 0) { dp(i)(j) = j } else if (j == 0) { dp(i)(j) = i } else if (str1.charAt(i - 1) == str2.charAt(j - 1)) { dp(i)(j) = dp(i - 1)(j - 1) } else { dp(i)(j) = 1 + min(min(dp(i)(j - 1), dp(i - 1)(j)), dp(i - 1)(j - 1)) } } } dp(m)(n) } def min(i: Int, j: Int): Int = if (i <= j) i else j }
输出结果以下:
The Edit Distance of ljb and lijb is: 1