关于动态规划:动态规划LeetCode-509斐波那契数列

Leetcode 509 题道歉拖更了 2 天,嘿嘿。这周咱们基于动静布局根本思维,做一道 Leetcode 的简略题。 题干简述Leetcode 509 题就是计算斐波那契数列。 公式:F(n) = F(n - 1) + F(n - 2) 给定:n 要求:计算F(n) 解题思路为什么说计算斐波那契数列是动静布局外面最简略的一道题呢? 是因为题目间接给出了状态转移方程F(n) = F(n - 1) + F(n - 2),拿着公式计算就能够了。 代码实现class Solution: def fib(self, n: int) -> int: if n == 0: return 0 dp = [0]*(n+1) dp[0] = 0 dp[1] = 1 for i in range(2, n+1): dp[i] = dp[i-1] + dp[i-2] return dp[n]复杂度工夫复杂度O(n),空间复杂度O(n)。 转载申明:本文章容许转载,原文地址:「动静布局」LeetCode 509(斐波那契数列)

March 15, 2023 · 1 min · jiezi

关于动态规划:动态规划LeetCode-416分割等和子集

原文归档:「烤冷面讲算法,每周一讲」原文链接:「动静布局」LeetCode 416(宰割等和子集) LeetCode 416上一周讲了01背包问题,这周咱们趁热打铁,用01背包问题的思路来解决 LeetCode 416 题。 题干简述给定:一个只蕴含正整数的非空数组 nums 。 要求:判断 nums 是否能够被宰割成元素和相等的两个子集。 题目详情:416. 宰割等和子集 解题思路解题的关键在于咱们是否从nums中找出一些元素,「元素的和」等于「总和」的一半,如果找失去,答案即为 true,否则就是 false。依据第 1 点,咱们能够把这道题转化为01背包问题,背包容量=nums元素和/2,物品就是nums数组中的每个元素,物品的分量和价值相等,等于元素的值(也就是nums[i])。除此之外还有一些边界条件: 首先,nums中所有元素的和必须为偶数,否则不可能被宰割成元素和相等的两个子整数集。其次,若 nums 中某个元素的值>总元素和/2,间接 return false。图解算法官网案例: Input: nums = [1,5,11,5] Output: true Explanation: The array can be partitioned as [1, 5, 5] and [11]. 就像「01背包问题」这篇文章提到的那样,咱们能够画出这样一个矩阵: 1234567891011nums[0]=111111111111nums[1]=511115666666nums[2]=11111156666611nums[3]=51111566661011代码实现class Solution: def canPartition(self, nums: List[int]) -> bool: s = sum(nums) target = s // 2 # 边界值检测 if s % 2 == 1: return False # 边界值检测 maxNum = 0 for num in (nums): maxNum = max(num, maxNum) if maxNum > target: return False dp = [([0] * target) for p in range(len(nums))] # 填充矩阵第一行 for j in range(0, target): subTarget = j + 1 if subTarget >= nums[0]: dp[0][j] = nums[0] # 填充矩阵残余所有行 for i in range(1, len(nums)): num = nums[i] for j in range(0, target): subTarget = j + 1 if subTarget > num: dp[i][j] = max(dp[i-1][j], dp[i-1][j-num]+num) elif subTarget == num: dp[i][j] = num else: dp[i][j] = dp[i - 1][j] if dp[i][target-1] == target: return True return False复杂度工夫复杂度O(n^2),空间复杂度O(n^2),在 LeetCode 下面的体现并不现实: ...

March 6, 2023 · 1 min · jiezi

关于动态规划:状态机动态规划之股票问题总结

状态机动静布局之股票问题总结前言在后面的三篇股票问题的文章当中咱们一共介绍了6道对于股票相干的算法题,这些算法题的一个集中的特点就是状态比拟多,须要咱们去仔细分析状态之间的转换,而这种状态之间的转换特变像状态机,因而这种动静布局也被称作状态机动静布局。 如果须要认真的去剖析下面思维导图当中的各个问题,能够参考上面的文章: 内容链接交易股票的最佳时机I和II这种动静布局你见过吗——状态机动静布局之股票问题(上)交易股票的最佳时机III和Iv这种动静布局你见过吗——状态机动静布局之股票问题(中)交易股票的最佳时机含冷冻期和手续费这种动静布局你见过吗——状态机动静布局之股票问题(下)本篇文章就是对下面6个问题进行汇总不便大家查阅,如果大家想仔细分析这几个问题还是下面三篇文章更适合,内容更加具体,如果你想疾速理解状态机动静布局,那么这篇文章的状态转移剖析应该可能帮忙你。 在本文谈到的6个问题都是动静布局的问题,因而你能够须要相熟一下动静布局的套路,在求解动静布局问题的时候通常的步骤有以下几个: 寻找可能示意状态的数组dp,即咱们须要寻找dp的含意,剖析须要用几纬数组示意具体的状态。通过剖析问题,寻找动静转移公式。初始化状态数组。通过剖析动静转移方程,确定数组的遍历程序。交易股票的最佳时机I给定一个数组 prices ,它的第 i 个元素 prices[i] 示意一支给定股票第 i 天的价格。你只能抉择 某一天 买入这只股票,并抉择在将来的某一个不同的日子卖出该股票。设计一个算法来计算你所能获取的最大利润。返回你能够从这笔交易中获取的最大利润。如果你不能获取任何利润,返回 0 。状态示意数组在这个问题当中咱们用一个二维数组去示意咱们的状态,在这个问题当中次要有两个状态,一个是手上有股票,另一是手上没有股票: dp[i][0]示意在第i天手上没有股票可能取得的最大的收益,比方咱们在第一天的没有股票的收益为0元。dp[i][1]示意在第i天手上存在股票可能取得的最大的收益,比方咱们在第一天买入股票之后收益为-prices[0]。那么咱们最初的答案是dp[N][0],这个示意在最初一天,咱们的手中不存在股票,即咱们将股票卖出去可能获取的最大的收益。 状态转移方程当初咱们来剖析一下如何进行状态的转移: dp[i][0]的状态如何从第i-1的状态转移过去: 如果第i-1个状态是手中不存在股票,即dp[i-1][0],那么第i个状态也没有股票,那么间接是dp[i][0] = dp[i - 1][0],因为没有进行交易。如果第i-1个状态手中存在股票,即dp[i-1][1],那么如果想在第i个状态没有股票,那么就须要将股票卖出,那么收益就为dp[i-1][1] +prices[i],即dp[i][0] = dp[i-1][1] +prices[i]。综合下面的两种转移形式能够失去上面的转移方程:$$dp[i][0] = max(dp[i - 1][0], dp[i - 1][1] + prices[i])$$ dp[i][1]的状态如何进行转移: 如果第i-1个状态是手中不存在股票,即dp[i-1][0],而第i个状态有股票,那么dp[i][0] = -prices[i],因为买入股票,而且只可能买入一次,因而间接等于-prices[i]即可,留神这里不能是dp[i - 1][0] - prices[i],因为在dp[i-][0]当中可能存在先买入再卖出的状况,而题干要求只能买入卖出一次。如果第i-1个状态手中存在股票,即dp[i-1][1],而第i个状态有股票,因而不须要进行交易,即dp[i][1]=dp[i - 1][1]。综合下面的两种转移形式能够失去上面的转移方程:$$dp[i][1] = max(dp[i - 1][1], -prices[i]);$$ 参考代码如下: class Solution { public int maxProfit(int[] prices) { int[][] dp = new int[prices.length][2]; // 初始化数组 dp[0][0] 默认等于0 不必 // 显示初始化 dp[0][1] = -prices[0]; for (int i = 1; i < prices.length; i++) { dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][1] + prices[i]); dp[i][1] = Math.max(dp[i - 1][1], -prices[i]); } return dp[prices.length - 1][0]; }}进行数组空间优化 ...

July 30, 2022 · 6 min · jiezi

关于动态规划:这种动态规划你见过吗状态机动态规划之股票问题下

这种动静布局你见过吗——状态机动静布局之股票问题(下)前言在后面的两篇文章这种动静布局你见过吗——状态机动静布局之股票问题(上)和这种动静布局你见过吗——状态机动静布局之股票问题(中)曾经谈了4道和股票问题相干的题目,具体解释了状态机动静布局和他的基本原理和利用形式。在本篇文章当中,会再介绍剩下的两道股票问题,持续深刻和学习状态机动静布局。 最佳交易股票机会含冷冻期题目给定一个整数数组prices,其中第 prices[i] 示意第 i 天的股票价格 。 设计一个算法计算出最大利润。在满足以下约束条件下,你能够尽可能地实现更多的交易(屡次交易一支股票):卖出股票后,你无奈在第二天买入股票 (即冷冻期为 1 天)。 留神:你不能同时参加多笔交易(你必须在再次购买前发售掉之前的股票)。 示例示例1: 输出: prices = [1,2,3,0,2]输入: 3 解释: 对应的交易状态为: [买入, 卖出, 冷冻期, 买入, 卖出]示例2: 输出: prices = [1]输入: 0状态示意数组和状态转移方程和后面的题目一样首先还是须要进行状态的定义和状态转移的剖析,在这个问题当中咱们用一个二维数组dp[i][j]示意各种不同的状态下的收益,在这个问题当中咱们有以下几个状态: dp[i][0],示意在遍历到第i支股票的时候没有进行一次买入和卖出。 在这个时候没有进行买入和卖出,这个时候的收益和遍历到第i-1支股票的时候没有买入和卖出的状况是一样的,他们的收益都等于0,即dp[i][0] = 0,dp[i - 1][0] = 0。dp[i][1],示意在遍历到第i支股票的时候手中含有股票,这个状况能够由三种状况转移过去: 在遍历到第i-1支股票的时候手中曾经存在股票了,这个时候只须要放弃状态,那么在第i支股票的时候的收益和第i-1支股票的收益是相等的,即dp[i][1] = dp[i - 1][1]。第二种状况就是在遍历到第i-1支股票的时候手中不存在股票,那么这个时候要想手中存在股票就须要进行买入了,那么就须要破费prices[i],那么在遍历到第i支股票的时候收益等于dp[i][1] = dp[i - 1][0] - prices[i]。第三种状况是前一天是处于冷冻期(这里所谈到的冷冻期并不只是前2天卖出,导致的前一天的冷冻期,还有可能是更早之前卖出的,而后放弃它的状态,相当于是冷冻期的续期,只不过在续期当中是能够进行买股票的),那么当初是能够进行买入的,即dp[i][1] = dp[i - 1][3] - prices[i],其中dp[i][3]示意遍历到第i支股票的时候处于冷冻期的收益。综合以上三种状况:$$dp[i][1] = max(dp[i - 1][1], max(dp[i - 1][0] - prices[i], dp[i-1][3] - prices[i]))$$ dp[i][2],示意在第i支股票的时候手中不含有股票,能够转移到这个状态的状态一共有两种: 在遍历到第i-1支股票的时候手中原本就不含有股票,那么咱们只须要放弃状态即可,即dp[i][2] = dp[i - 1][2]。在遍历到第i-1支股票的时候手中含有股票,那么咱们须要将这个股票进行售出,即dp[i][2] = dp[i - 1][1] + prices[i]。综合以上两种状况:$$dp[i][2] = max(dp[i - 1][2], dp[i - 1][1] + prices[i])$$ ...

July 28, 2022 · 4 min · jiezi

关于动态规划:这种动态规划你见过吗状态机动态规划之股票问题中

前言在后面的文章这种动静布局你见过吗——状态机动静布局之股票问题(上)咱们曾经介绍了两个根本的股票问题,并且对状态机动静布局做出了简要的介绍,以及在状态机当中的状态是如何进行转换的,然而在后面的两个问题当中状态的个数比拟少,可能不不便大家了解状态机的含意,在本篇文章所谈到的两个问题当中状态的数目还是比拟多的,因而对于大家深刻了解状态机动静布局可能会好一点。 卖股票的最佳时机 III题目给定一个数组,它的第 i 个元素是一支给定的股票在第 i 天的价格。设计一个算法来计算你所能获取的最大利润。你最多能够实现 两笔 交易。留神:你不能同时参加多笔交易(你必须在再次购买前发售掉之前的股票)。示例示例1 输出:prices = [3,3,5,0,0,3,1,4] 输入:6 解释:在第 4 天(股票价格 = 0)的时候买入,在第 6 天(股票价格 = 3)的时候卖出,这笔交易所能取得利润 = 3-0 = 3 。随后,在第 7 天(股票价格 = 1)的时候买入,在第 8 天 (股票价格 = 4)的时候卖出,这笔交易所能取得利润 = 4-1 = 3 。 示例2 输出:prices = [1,2,3,4,5] 输入:4 解释:在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能取得利润 = 5-1 = 4 。留神你不能在第 1 天和第 2 天接连购买股票,之后再将它们卖出。因为这样属于同时参加了多笔交易,你必须在再次购买前发售掉之前的股票。 这道题目跟之前的两道题目不同之处在于,在上篇文章当中的两道题要么是可能购买一次,要么可能购买无数次,而在本道题目当中只可能购买两次,在这种状况下咱们应该如何定义各种状态呢? 状态示意数组和状态转移在这道题目当中咱们也是二维数组进行状态的示意,二维数组为dp[N][5],5示意咱们有5个状态,dp[N][i]示意第N天的第i个状态可能多大的收益!(为了不便上面介绍,假如一天有一个股票,dp[N][]示意第N天的状态,对应第N个股票的状态) dp[N][0],示意第N天一次买入和卖出的操作都没有过,那么dp[N][0] = dp[N - 1][0],跟前一天的状态一样,都没有进行股票的买入和卖出,其实也能够间接令dp[N][0] = 0,因为没有进行操作咱们的收益必定等于0。dp[N][1],示意第N天曾经进行过第一次买入,这个买入能够是在第N天进行买入,也能够在后面N-1天买入,而后在第N天放弃状态。 ...

July 27, 2022 · 5 min · jiezi

关于动态规划:这种动态规划你见过吗状态机动态规划之股票问题上

前言在本篇文章当中次要通过介绍各种股票问题跟大家介绍状态机动静布局,次要理解在股票问题当中是如何在动静布局当中进行状态转移的,通过认真分析状态转移过程给大家介绍状态机动静布局。所谓状态机,就是有很多状态和他们之间的转移关系组成起来造成零碎,这个说法看起来有点高大上,其实很简略,在前面讲动静布局解法的时候大家就明确了。 交易股票的最佳时机I给定一个数组 prices ,它的第 i 个元素 prices[i] 示意一支给定股票第 i 天的价格。你只能抉择 某一天 买入这只股票,并抉择在将来的某一个不同的日子卖出该股票。设计一个算法来计算你所能获取的最大利润。返回你能够从这笔交易中获取的最大利润。如果你不能获取任何利润,返回 0 。 示例 1: 输出:[7,1,5,3,6,4] 输入:5 解释:在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。留神利润不能是 7-1 = 6, 因为卖出价格须要大于买入价格;同时,你不能在买入前卖出股票。 示例 2: 输出:prices = [7,6,4,3,1] 输入:0 解释:在这种状况下, 没有交易实现, 所以最大利润为 0。 暴力解法在这个问题当中,咱们的工作是在某一天买入股票,而后在将来某天再将股票卖出去,那么咱们就能够用一个二重循环,第一层循环遍历每一天的股票,第二层循环遍历该天之后的股票,而后找到差值最大的那一天即可,也就是寻找某天前面价值最高的股票!通过做差失去差值,将差值最大的返回即可! class Solution { public int maxProfit(int[] prices){ int ans = 0; for (int i = 0; i < prices.length - 1; i++) { for (int j = i + 1; j < prices.length; j++) { ans = Math.max(ans, prices[j] - prices[i]); } } return ans; }}下面的代码的工夫复杂度为$O(n^2)$,空间复杂度为$O(1)$,因为工夫简单度过高,下面的代码在Leetcode下面提交会超时。 ...

July 25, 2022 · 4 min · jiezi

关于动态规划:动态规划算法笔记

装满背包的递推公式 dp[j] += dp[j - nums[i]];dp[j]的含意是指在背包容量为j的状况下,背包能装的最大分量nums[i]就是第i个物品的分量 动静布局就是以后值依赖于前一个值,实现全局最优 备忘:如果求组合数,外层遍历物品如果求排列数,外层遍历背包 如果遍历整颗树,递归函数就不能有返回值遍历某一条固定路线,递归函数就肯定要有返回值 二叉树节点的深度:指从根节点到该节点的最长简略门路边的条数二叉树节点的高度:指从该节点到叶子节点的最长简略门路边的条数 6.24算法题

June 24, 2022 · 1 min · jiezi

关于动态规划:算法动态规划

动静布局的基础知识爬楼梯的起码老本一个数组 cost 的所有数字都是负数,它的第 i 个数字示意在一个楼梯的第 i 级台阶往上爬的老本,在领取了老本 cost[i]之后能够从第 i 级台阶往上爬 1 级或 2 级。假如台阶至多有 2 级,既能够从第 0 级台阶登程,也能够从第 1 级台阶登程,请计算爬上该楼梯的起码老本。例如,输出数组[1,100,1,1,100,1],则爬上该楼梯的起码老本是 4,别离通过下标为 0、2、3、5 的这 4 级台阶,如图 14.1 所示。函数f(i)示意从楼梯的第 i 级台阶再往上爬的起码老本 f(i) = min(f(i-1), f(i-2)) + cost[i]/** * @param {number[]} cost * @return {number} */var minCostClimbingStairs = function (cost) { let len = cost.length; const dp = new Array(len + 1); dp[0] = dp[1] = 0; for (let i = 2; i <= len; i++) { dp[i] = Math.min(dp[i - 1] + cost[i - 1], dp[i - 2] + cost[i - 2]); } return dp[len];};单序列问题单序列问题是与动静布局相干的问题中最有可能在算法面试中遇到的题型。这类题目都有适宜使用动静布局的问题的特点,如解决问题须要若干步骤,并且每个步骤都面临若干抉择,须要计算解的数目或最优解。除此之外,这类题目的输出通常是一个序列,如一个一维数组或字符串。 ...

May 15, 2022 · 4 min · jiezi

关于动态规划:背包问题的核心公式

背包问题的外围公式把每个背包问题的外围代码放在一块,更好的辨别不同问题的代码实现。当然,在实现代码之前,要先理解每个背包问题解决问题的思路。 物品的分量数组是 weight (int[]),价值数组是 value (int[]),背包容量是 bagWeight 1. 0-1 背包从大到小遍历,为了保障每个物品仅被增加一次 1.1 应用二维数组存储递推公式 dp[i][j] = max(dp[i-1][j], dp[i-1][j - weight[i]] + value[i]) (dp[i][j]:放入物品和不放入物品,哪个值大) dp 大小 int[weight.size()][bagWeight+1] ([物品个数][背包容量+1]) 代码 // 先遍历物品,再遍历背包for(int i = 0; i < weight.size(); i++) { for(int j = bagWeight; j >= 0; j--) { if (j < weight[i]) dp[i][j] = dp[i-1][j] else dp[i][j] = max(dp[i-1][j], dp[i-1][j-weight[i]] + value[i]) }}1.2 应用一维数组存储递推公式 dp[j] = max(dp[j], dp[j - weight[i]] + value[i])( dp[j]:放入物品和不放入物品,哪个值大) ...

December 18, 2021 · 1 min · jiezi

关于动态规划:递推算法与递推套路手撕算法篇

分割咱们:有道技术团队助手:ydtech01 / 邮箱:[ydtech@rd.netease.com] 之前学习基础知识的时候也说了,递推和动静布局有这暧昧不清的关系,能够说,动静布局就是多了一个决策过程的递推。因而,咱们明天的刷题也会波及到一些比较简单的动静布局的题目,同样可能对咱们粗浅的了解递推算法起到帮忙,也为咱们之后深刻学习动静布局算法和动静布局的优化打下基础。 一、前置常识每一个递推算法,都有一个递推公式,通过递推公式咱们能够更加明确的理解递推算法。 1.1 斐波那契数列的递推公式应用场景:当咱们下(上)一行的状态能够仅仅通过上(下)一行的信息推导进去,并要求咱们求解最初(第)一行时,咱们无需将每一行的数据都存储在数组当中,能够通过滚动数组的技巧,节俭空间复杂度。 具体实现:假如咱们曾经晓得第一行的数据,并且通过第一行数据通过肯定的运算能够失去第二行的数据,那么,咱们只须要一个数组长期存储两行数据,就能够将之后的每一行数据的后果计算出来,一直的滚动替换这两行数据,最终求解出最初一行数据的形式。关键点:推导计算以后行和下(上)一行的索引。因为数组是滚动的,因而,咱们指标行的索引也是随时变动的,以下为求取以后行和上(下)一行的通用公式: 以后行: const curIdx = i % 2因为咱们的滚动数组只有2行,因而,以后索引只有与2求模即可;上(下)一行:const preIdx = +!curIdx因为滚动数组只有两行,索引要么是0,要么是1,咱们对以后行取反便可失去上(下)一行的索引(留神,在js中,对1取反是false,对0取反是true,因而咱们通过一个隐式类型转换将布尔类型转换为数字类型)。这道题咱们要怎么了解呢?咱们如果想要爬到第 n 阶楼梯,那么上一步有可能是在 n-1 ,也有可能是在 n-2 理论应用:前面刷题时会常常用到,详见下文 二、刷题正餐2.1 LeetCode 120. 三角形最小门路和2.1.1 解题思路依照咱们之前将的递推套路:1. 定义递推状态:在这道题中,咱们每走一步的门路和次要取决于以后所处的行数i和以后的列数j,因而,咱们这道题的递推状态应该是:dp[i, j]2. 递推公式:确定了递推状态之后,咱们就要确定递推公式了。那么,第i行第j列的数据要如何能力推导进去呢?首先,根据题意,咱们要求最小门路和,如果咱们从最底下往上走,那么咱们能够晓得,下一行i的数据应该是上一行i+1非法门路的最小值加上以后走到节点的值。因而,咱们失去了如下公式: // 第i行第j列数据的推导公式dp[i, j] = min(dp[i+1, j], dp[i+1, j+1]) + val[i,j]3.剖析边界条件:咱们须要将咱们题目已知的条件初始化到咱们的递推数组当中作为边界条件。这道题中,边界条件就是最初一行的数据,咱们将最初一行的数据先退出到滚动数组当中,这样之后就能够依据最初一行数据一直的往上推导总门路和,从而找到最小门路。4. 程序实现:咱们间接应用循环加滚动数组技巧实现。 2.1.2 代码演示function minimumTotal(triangle: number[][]): number { const n = triangle.length; // 递推公式(状态本义方程)以下为自底向上走的公式 // dp[i, j] = min(dp[i+1, j], dp[i+1, j+1]) + val[i,j] // 因为i只跟i+1无关,因而,咱们能够用滚动数组的技巧定义dp数组 let dp: number[][] = []; for(let i=0;i<2;i++){ dp.push([]); } // 首先初始化最初一行的数值,因为应用了滚动数组的技巧,因而,咱们最初一行的索引应该是(n-1)%2 for(let i=0;i<n;i++) { dp[(n-1)%2][i] = triangle[n-1][i]; } // 而后从倒数第二行开始求值 for(let i = n-2;i>=0;--i) { // 因为应用了滚动数组,因而,以后行的下标为i%2,而下一行的下标则是以后行下标取反 let idx = i % 2; let nextIdx = +!idx; // 依据下面的公式计算出每一个地位上的值 for (let j=0; j <= i; j++) { dp[idx][j] = Math.min(dp[nextIdx][j], dp[nextIdx][j + 1]) + triangle[i][j]; } } // 最终,三角形顶点的那个值就是咱们要求的值 return dp[0][0];};2.2 LeetCode 119. 杨辉三角 II2.2.1 解题思路这道题与上一道题相似,仍然能够依据上一行推导出下一行的值,因而还是要祭出滚动数组的技巧,递推状态与递推公式的剖析也比拟相似,大家能够本人尝试推导。而这一道题的边界条件,其实就是每一行的第一位都应该是1。 ...

October 28, 2021 · 3 min · jiezi

关于动态规划:算法最长公共子串

问题:有两个字符串str和str2,求出两个字符串中最长公共子串长度。 比方:str=acbcbcef,str2=abcbced,则str和str2的最长公共子串为bcbce,最长公共子串长度为5。 计划:如果字符雷同则置为1,否则置为0缩小反复计算,arr[i] [j] = arr[i-1] [j-1],此处要留神的点是当i==0 || j==0时要间接设值。 Java代码实现: // 动静布局实现,工夫复杂度O(m*n),空间复杂度(m*n) private static String getLcs(String s1, String s2) { int maxLen = 0, maxEnd = 0; int[][] arr = new int[s1.length()][s2.length()]; for (int i = 0; i < s1.length(); i++) { for (int j = 0; j < s2.length(); j++) { if (s1.charAt(i) == s2.charAt(j)) { if (i == 0 || j == 0) { arr[i][j] = 1; } else { arr[i][j] = arr[i - 1][j - 1] + 1; } } else { arr[i][j] = 0; } if (arr[i][j] > maxLen) { maxEnd = i; maxLen = arr[i][j]; } } } if (maxLen == 0) { return ""; } return s1.substring(maxEnd - maxLen + 1, maxEnd); }参考文章 求两个字符串的最长公共子串https://blog.csdn.net/qq_2580... ...

July 19, 2021 · 1 min · jiezi

关于动态规划:动态规划这词太吓人其实可以叫状态缓存

摘要:平时练习算法题学习算法常识时,常常会发现题解里写着“动静布局”,外面一上来就是一个简单的dp公式,对于新人来说除了说声“妙啊”,剩下就是纳闷,他是怎么想到这个公式的?我能想到吗?这玩意工作中有用吗?本文分享自华为云社区《动静布局到底是怎么想到的?【奔跑吧!JAVA】》,原文作者:breakDraw。 平时练习算法题学习算法常识时,常常会发现题解里写着“动静布局”,外面一上来就是一个简单的dp公式,对于新人来说除了说声 剩下就是纳闷,他是怎么想到这个公式的?我能想到吗?这玩意工作中有用吗?加上“动静布局”这高端的名字,而后就劝退了不少试图去了解他的人。 动静布局听起来太吓人,能够换个说法我在心田更喜爱叫他“状态缓存”如果是服务开发,置信很相熟这个词语, 利用缓存来放慢一些反复的申请的响应速度。而这个缓存的特点是 和其余缓存有所关联。 比方咱们的服务要计算7天内的某金钱总和,计算后要缓存一下。起初又收到一个申请,要计算8天内的金钱总和那咱们只须要取之前算过的7天内的金钱综合,加上第8天的金钱就行了。 1+4的思考套路本人针对动静布局总结了一个本人的思考套路,我叫他1组例子4个问题,就叫1+4好了,通过这5个过程,能够站在普通人的角度(就是非acm大佬那种的角度),去了解动静布局是如何被思考进去的 在超时的思路上写出一组计算过程的例子在超时例子的根底上,有哪些反复、节约的中央?如何定义dp数组状态的变动方向是什么,是怎么变动的边界状态是什么简略例子以一道简略题为例:爬楼梯:https://leetcode-cn.com/problems/climbing-stairs/ 这时候就要静下心,察看这个解法的例子中是否有反复经验的场景,而这个反复经验的场景就叫状态。我解决动静布局的题目时, 都会问本人3个问题,个别就能顺利地解决。 ①在超时的思路上写出一组计算过程的例子如果咱们思考最简略的解法, 就是从终点开始,每次抉择走1步或者走2步,看下是否走到起点,能走到则办法数+1。但这种办法注定超时(O(n^2))但我还是照着这个过程模仿了一下,轻易列了几个1 ->2-> 3-> 4-> 51 ->2 ->3-> 51->3->4->51->3->5 ②在超时例子的根底上,有哪些反复、节约的中央?在下面,我发现了反复的中央 也就是说从3到5总共就2种路线,曾经在1->2之后计算过了,我前面从1走到3再往后走时,没必要再去算了。换言之,当我走到3的时候,其实早就能够晓得前面还剩下多少种走法。发现反复的中央后,就能够开始建设dp公式了。 ③如何定义dp数组?定义dp数组,也就是定义下面提到的反复的中央。从新看下之前的那句话当我走到3的时候,其实早就能够晓得前面还剩下多少种走法。所以dp[3]代表的就是从3往后,有多少种可走的办法。 ④状态的变动方向是什么,是怎么变动的首先思考状态的变动方向从新看这句话:当我走到3的时候,其实早就能够晓得前面还剩下多少种走法 阐明后果取决于往 前面 的状态因而咱们要先计算前面的状态, 即从后往前算 接着思考这个前面的状态和以后的状态有什么分割,是怎么变动的这个个别都蕴含在题目条件中依据题意,要么走2步,要么走1步,因而每当我走到一层时,下一次就2种状态能够变动。那么对于第3层而言,他后续有2种走法,走1步或者走2步那么他的状况就是dp[3] = dp[3+1] + dp{3+2}如果层数设为i,那么这个变动状况就是dp[i] = dp[i+1] + dp[i+2] ⑤边界状态是什么?边界状态就是不须要依赖前面的状态了,间接能够失去后果的状态。在这里必定就是最初一层dp[n], 最初一层默认是一种走法。 dp[n]=1 实现依据下面的过程,本人便定义了这个状态和变动 定义:dp[i] : 代表从第i层往后,有多少种走法方向和变动:dp[i] = dp[i+1] + dp[i+2];边界: dp[n] = 1依据这个写代码就很容易了代码: public int climbStairs(int n) { int[] dp = new int[n + 1]; dp[n] = 1; dp[n-1] = 1; for(int i = n-2; i >=0;i--) { dp[i] = dp[i+1] + dp[i+2]; } return dp[0]; }进阶版,二维的动静布局https://leetcode-cn.com/problems/number-of-ways-to-stay-in-the-same-place-after-some-steps/ ...

June 26, 2021 · 1 min · jiezi

关于动态规划:动态规划01背包LCSLIS

动静布局的外围是当时找到该事件的动静转移方程,我临时只学习了几个经典的dp案例,道阻且长! Bone CollectorMany years ago , in Teddy’s hometown there was a man who was called “Bone Collector”. This man like to collect varies of bones , such as dog’s , cow’s , also he went to the grave …The bone collector had a big bag with a volume of V ,and along his trip of collecting there are a lot of bones , obviously , different bone has different value and different volume, now given the each bone’s value along his trip , can you calculate out the maximum of the total value the bone collector can get ? ...

April 28, 2021 · 4 min · jiezi

关于动态规划:动态规划-01背包问题

有 NN 件物品和一个容量是 VV 的背包。每件物品只能应用一次。 第 ii 件物品的体积是 vivi,价值是 wiwi。 求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。输入最大价值。 输出格局第一行两个整数,N,VN,V,用空格隔开,别离示意物品数量和背包容积。 接下来有 NN 行,每行两个整数 vi,wivi,wi,用空格隔开,别离示意第 ii 件物品的体积和价值。 输入格局输入一个整数,示意最大价值。 数据范畴0<N,V≤10000<N,V≤10000<vi,wi≤10000<vi,wi≤1000 输出样例4 51 22 43 44 5 输入样例:8

January 3, 2021 · 1 min · jiezi

关于动态规划:状压-DP-是什么这篇题解带你入门

题目地址(464. 我能赢么)https://leetcode-cn.com/probl... 题目形容在 "100 game" 这个游戏中,两名玩家轮流抉择从 1 到 10 的任意整数,累计整数和,先使得累计整数和达到或超过 100 的玩家,即为胜者。如果咱们将游戏规则改为 “玩家不能重复使用整数” 呢?例如,两个玩家能够轮流从公共整数池中抽取从 1 到 15 的整数(不放回),直到累计整数和 >= 100。给定一个整数 maxChoosableInteger (整数池中可抉择的最大数)和另一个整数 desiredTotal(累计和),判断先出手的玩家是否能稳赢(假如两位玩家游戏时都体现最佳)?你能够假如 maxChoosableInteger 不会大于 20, desiredTotal 不会大于 300。示例:输出:maxChoosableInteger = 10desiredTotal = 11输入:false解释:无论第一个玩家抉择哪个整数,他都会失败。第一个玩家能够抉择从 1 到 10 的整数。如果第一个玩家抉择 1,那么第二个玩家只能抉择从 2 到 10 的整数。第二个玩家能够通过抉择整数 10(那么累积和为 11 >= desiredTotal),从而取得胜利.同样地,第一个玩家抉择任意其余整数,第二个玩家都会赢。前置常识动静布局回溯公司阿里linkedin暴力解(超时)思路题目的函数签名如下: def canIWin(self, maxChoosableInteger: int, desiredTotal: int) -> bool:即给你两个整数 maxChoosableInteger 和 desiredTotal,让你返回一个布尔值。 两种非凡状况首先思考两种非凡状况,前面所有的解法这两种非凡状况都实用,因而不再赘述。 如果 desiredTotal 是小于等于 maxChoosableInteger 的,间接返回 True,这不难理解。如果 [1, maxChoosableInteger] 全副数字之和小于 desiredTotal,谁都无奈赢,返回 False。个别状况思考完了非凡状况,咱们持续思考个别状况。 首先咱们来简化一下问题, 如果数字能够轻易选呢?这个问题就简略多了,和爬楼梯没啥区别。这里思考暴力求解,应用 DFS + 模仿的形式来解决。 ...

December 28, 2020 · 5 min · jiezi

关于动态规划:DP-就是暴力暴力就是艺术

题目地址(面试题 17.23. 最大黑方阵)https://leetcode-cn.com/probl... 题目形容给定一个方阵,其中每个单元(像素)非黑即白。设计一个算法,找出 4 条边皆为彩色像素的最大子方阵。返回一个数组 [r, c, size] ,其中 r, c 别离代表子方阵左上角的行号和列号,size 是子方阵的边长。若有多个满足条件的子方阵,返回 r 最小的,若 r 雷同,返回 c 最小的子方阵。若无满足条件的子方阵,返回空数组。示例 1:输出:[  [1,0,1],  [0,0,1],  [0,0,1]]输入: [1,0,2]解释: 输出中 0 代表彩色,1 代表红色,标粗的元素即为满足条件的最大子方阵示例 2:输出:[  [0,1,1],  [1,0,1],  [1,1,0]]输入: [0,0,1]提醒:matrix.length == matrix[0].length <= 200前置常识动静布局公司暂无思路看了下数据范畴,矩阵大小不超过 $200 \times 200$,因而答案应该就是暴力,这个数据范畴差不多 N 的三次方的复杂度都能够通过,其中 N 为矩阵的边长。起因我也在之前的文章来和大家聊聊我是如何刷题的(第三弹)中讲过了,那就是 $200^3$ 刚好是是 800 万,再多就很容易超过 1000 万了。 乍一看,这道题和 221. 最大正方形,实则不然。 这道题是能够空心的,只有边长是局部都是 0 即可,这就齐全不同了。 如下图,红色局部就是答案。只须要保障边全副是 0 就好了,所以外面有一个 1 无所谓的。 咱们无妨从部分动手,看能不能关上思路。 这是一种罕用的技巧,当你面对难题无从下手的时候能够画个图,从非凡状况和部分状况开始,帮忙咱们关上思路。比方我想计算以如下图红色格子为右下角的最大黑方阵。咱们能够从以后点向上向左扩大直到非 0。 在下面的例子中,不难看出其最大黑方阵不会超过 min(4, 5)。 ...

December 28, 2020 · 2 min · jiezi

关于动态规划:动态规划算法

动静布局算法 问题要害特色:最优子结构,子问题重叠 确定定义问题规模解的个别递归表达式对问题规模升序遍历每种规模的问题应用递归表达式, 其中递归求解子问题间接通过拜访mem获取计算完以后规模问题后, 向mem中存入后果

December 20, 2020 · 1 min · jiezi

关于动态规划:搞事代码找茬

最近老是想起陈芝麻烂谷子的事件,阐明工龄所剩无几了。 - 1 -又是在那边远的 2009 年,那个“杯具”曾经不是杯具的年头,度厂办个算法较量,办出了点儿杯具的滋味。 较量的名字叫“百度之星”,那些年在校园里影响力还蛮大的(如同当初还是),大略赛制就是通过初赛、复赛、决赛这么几轮,选出几个社会主义四有青年瓜分奖金。值得一提的是,头两年(05、06)冠军都被楼教主承包了。 为什么说有点杯具的滋味呢,因为那年的初赛完结当前,度厂搞了个骚操作,把所有参赛选手提交的代码导出来,打了个包,发在贴吧里。 于是贴吧忽然就炸了。 - 2 -要晓得初赛是网络赛,各个学校的 ACM(或OI) 集训队的队员们很可能都是凑在机房一起参加,毕竟毛主席教诲咱们人多力量大嘛。 所以这就有点意思了:如果同一个题,两份代码长得很像,阐明相互剽窃概率就很大。 问题是参赛人数有点多,两两比照这 O(n^2) 的工夫复杂度,靠人肉有点儿吃不消;但这么大一个瓜,光看不吃又有点惋惜了。 那么这瓜到底该怎么吃呢? - 3 -还好,作为一个比赛战五渣的我,通过初赛的能力没有,搞事件的能力还是有一点的。 为了比照两份代码的类似度,那我首先得找到一个指标。 作为一个长于 舞弊 思考的社会主义三无青年,我预计作弊者在拿到弊友代码后不会间接提交,至多会做些更换变量名之类操作;但比赛工夫紧迫,大概率来不及批改整体框架。 那么,只有我能算出批改的水平,就能判断类似度了:假如两份代码长度别离是 m、n,批改了 x 个字符, 咱们大抵能够把 100% - x / ((m + n) / 2) 当成类似度(没被批改的字符占比)。 但如何计算这批改的水平呢?毕竟批改前后代码长度很可能不同,不适宜通过逐字比拟来找到差异。 - 4 -既然间接解决两段代码有点辣手,那无妨先考虑一下简略的 case 。 比如说要将字符串 "a" 改成 "b",这个简略,只有改一个字符就行。 又比如说要将字符串 "a" 改成 "ab",这个也简略,只有增加一个字符就行。 再比如说要将字符串 "ab" 改成 "b",这个仍然简略,只有删除一个字符就行。 如果我能算出将一段字符串通过增加、删除、批改三种操作批改成另一个字符串的起码操作次数,应该就能把这瓜给吃了。 如同是找到了方向,然而要怎么实现呢? - 5 -既然间接解决两段代码还是有点辣手,那无妨再考虑一下略微简单一点的 case ,比方把字符串 X = "baidu" 变成 Y = "bytedance"。 ...

August 8, 2020 · 3 min · jiezi