![](https://img-blog.csdnimg.cn/20201014180756916.png?x-oss-process=image/resize,m_fixed,h_64,w_64)
动态规划
九幽孤翎
蜉蝣只有认清自己的渺小,才能有化茧成蝶的一天
展开
-
Leetcode_1823_找出游戏的获胜者_约瑟夫环
以前看了很久都没会,今天看了突然会了,其实很简单,举个例子就行我们定义f(m,n) = m个人,每n个人杀一个的最终获胜者那么f(10,3)就是1,2,3,4,5,6,7,8,9,10中每3个人杀一个的获胜者那么进行完一轮后,就是4,5,6,7,8,9,10,1,2我们对比一下原始的f(9,3)——1,2,3,4,5,6,7,8,9其实很容易观察到这两个数列之间的关系f(10,3) = (f(9,3) + 3 - 1)% 10 + 1其实也就是f(m,n) = (f(m-1,n) + n -原创 2022-05-04 14:48:00 · 815 阅读 · 0 评论 -
Leetcode_152_乘积最大子数组_动态规划
简单的dp,需要注意考虑0以及只有一个负数的情况class Solution { public int maxProduct(int[] nums) { int temp = 1; int len = nums.length; // 以下标结尾的最大乘积 int[][] dp = new int[len][2]; if(nums[0] > 0) { dp[0][0] = nums[0];原创 2022-03-14 16:17:28 · 673 阅读 · 0 评论 -
Leetcode_bytedance-006_夏季特惠_01背包
学acm的第一个专题,好怀念改了半天没过,一看题解爆int,气晕import java.util.Scanner;// 一个游戏实际的价格是b - (a - b) = 2 * b - aclass Game { Integer cost; Integer value; public Game(Integer cost, Integer value) { this.cost = cost; this.value = value; }原创 2022-03-13 10:44:09 · 418 阅读 · 0 评论 -
Leetcode_剑指Offer46_把数字翻译成字符串_dp
很容易观察到是一道动态规划class Solution { public int translateNum(int num) { String s = String.valueOf(num); int len = s.length(); int[] dp = new int[len]; dp[0] = 1; for(int i = 1;i < len ;i ++) { dp[i] = dp原创 2022-03-06 13:04:01 · 58 阅读 · 0 评论 -
Leetcode_322_零钱兑换_动态规划
经典完全背包,其实有很多优化空间,筛选背包可以用二分直接从合适的硬币开始遍历import java.util.Arrays;// 冲刺089class Solution { public int coinChange(int[] coins, int amount) { int len = coins.length; int[] dp = new int[amount + 1]; Arrays.fill(dp, -1); dp[原创 2021-09-17 17:15:02 · 79 阅读 · 0 评论 -
Leetcode_221_最大正方形_动态规划
很有意思的一道动态规划,状态转移方程很关键// 冲刺081class Solution { public int maximalSquare(char[][] matrix) { int m = matrix.length; int n = matrix[0].length; int ans = 0; int[][] dp = new int[m][n]; for (int i = 0; i < n; i++)原创 2021-09-14 16:02:08 · 82 阅读 · 0 评论 -
Leetcode_600_不含连续1的非负整数_数位dp
我们定义dp[i][j]为第i位为j的合法总数,通过static预处理所有结果。针对某一个数,我们先将其转化为二进制,然后从最高位开始往下找;如果当前位为1,则代表若当前为取0,其余低位可以随意取,即ans += dp[i][0],这一位后面就固定为1了,当前一位也是1的时候,我们就可以返回结果了;如果当前位为0,则直接跳过当前位。如果成功遍历到最低位,还要加上最大的那个结果(也就是一开始给的参数n),ans+=1;class Solution { // 第i位为j的合法总数 st原创 2021-09-11 17:53:11 · 112 阅读 · 0 评论 -
Leetcode_72_编译距离_动态规划
看题解后才搞出来的;我们先定义dp方程 :dp[i][j]代表word1的前i位和word2的前i位匹配所需要的最小步骤;然后列出状态转移方程:假设现在word1的前i位和word2的前i位经过dp[i][j]步运算后完全匹配,那么当i+1或者j+1,对应的dp[i+1][j]或者dp[i][j+1] = dp[i][j] + 1;当i+1并且j+1时,匹配word1的i+1位和word2的j+1位,相等的话直接转移,不想等+1最后对边界预处理。// 冲刺062class Solution {原创 2021-09-08 14:42:13 · 90 阅读 · 0 评论 -
Leetcode_64_最小路径和_动态规划
经典倒着算的dp ,可能出错的地方在循环的退出条件。// 冲刺061class Solution { public int minPathSum(int[][] grid) { int m = grid.length; int n = grid[0].length; int m1 = m - 1; int n1 = n - 1; // 防止越界的预处理 for (int i = m1 - 1; i原创 2021-09-08 12:48:26 · 73 阅读 · 0 评论 -
Leetcode_552_学生出勤记录Ⅱ_数位dp
一道典型的数位dp,先划分一下状态按照相邻有连续的0,1,2,3+个L以及存在0,1,2+个A来进行划分,求笛卡尔积,将同类的状态进行合并0:相邻的前1位是P,且没有A1:相邻的前2位是PL,且没有A2:相邻的前2位是LL,且没有A3:相邻的前1位是P/A,且有1个A4:相邻的前2位是PL/AL,且有1个A5:相邻的前2位是LL,且有1个A6:已经有连续的三个L或者出现过2个A我们可以用dp[i][j]表示前i位状态位j的个数的人数我们所求的就是∑05dp[n][j]\sum_0原创 2021-08-18 11:02:51 · 77 阅读 · 0 评论 -
Leetcode_526_优美的排列_状压dp
先观察n的范围为[1,15],所以我们可以先用暴力的方式计算出所有答案,然后存入数组,直接O(1)获取答案。但全排列15的阶层太大了,内存会爆掉。class Solution { public static void main(String[] args) { String[][] strings = new String[6][]; for (int i = 1; i <= 5; i++) { strings[i] = new Str原创 2021-08-16 14:01:40 · 84 阅读 · 0 评论 -
Leetcode_576_出界的路径数_动态规划
一开始用搜索写,超时了,看了题解后才想到的dp我是废物QAQdp[i][j][k]代表从起点开始走了i步到了(j,k)的走法数量dp[i][j][k]等于前一步的上下左右四个方位的和class Solution { public int findPaths(int m, int n, int maxMove, int startRow, int startColumn) { final int mod = 1000000007; final int[][] d原创 2021-08-15 11:24:50 · 85 阅读 · 0 评论 -
Leetcode_233_数字1的个数_数位dp/模拟
我们先计算 0-9, 0-99 ,0-999的答案cnt[0-9]=1cnt[00-99]=十位上的1 + 个位上的1 = 10 + 10组 * cnt[0-9]cnt[000-999]=百位上的1 + 十位上的1 + 个位上的1 = 100 + 10组 * cnt[00-99]找到规律:cnt[0-n位9] =10(n-1) + 10 * cnt[0-(n-1)位9]然后我们从最低位开始计算答案,这里以195为例子1.计算1位,0~5,只有1个12.计算2位,00~95,00~95 = 90原创 2021-08-14 18:21:57 · 154 阅读 · 0 评论 -
Leetcode_516_最长回文子序列_动态规划
过于经典dp[i][j]为[i,j]的子数组中的最长回文子序列长度,我们只需要比较头和尾是否相同,然后对dp[i+1][j-1]进行状态转移即可,边界条件正好没问题。class Solution { public int longestPalindromeSubseq(String s) { int n = s.length(); int[][] dp = new int[n][n]; for (int i = n - 1; i >= 0;原创 2021-08-12 15:23:37 · 109 阅读 · 0 评论 -
Leetcode_1524_和为奇数的子数组数目_前缀和_动态规划
听到研三学长面试时候的一道真题,顺手搜了一波题,就找到一个类似的,顺手写一下,真题写在后面了。先贴一个n2的超时做法:class Solution { public int numOfSubarrays(int[] arr) { int len = arr.length; int ans = 0; int mod = 1000000000 + 7; // dp[i][j]代表从第i个开始,第j个结束的子数组的奇偶性,false为偶,原创 2021-08-12 14:58:59 · 436 阅读 · 0 评论 -
Leetcode_446_等差数列划分Ⅱ - 子序列_动态规划
就离谱,昨天还奶了一口这题要是从子数组改成子序列难度就大了,没想到今天就出来了orz先看到数组长度1000,没跑了,动态规划 n2 做法。核心在于,如果确定了两个数,那必然能确定以这两个数为尾部的一条等差数列。我们使用动态规划的思想,从长度为2开始逐步延长,每增加一个新的元素,数列条数要增加的量,即为以这个新元素为末尾元素,之前的所有元素中的一个为倒数第二个元素,所构成的等差数列的数量(这个值我们之前必然已经得到了)。想到这里,我们基本已经可以列出状态转移方程。需要注意的是,等差数列长度至少为3,也就是原创 2021-08-11 20:05:53 · 128 阅读 · 0 评论 -
Leetcode_300_最长递增子序列_动态规划+二分
class Solution { public int lengthOfLIS(int[] nums) { ArrayList<Integer> dp = new ArrayList<>(); for (int num : nums) { int len = dp.size(); if (len == 0 || num > dp.get(len - 1)) {原创 2021-05-11 15:19:03 · 83 阅读 · 0 评论 -
Leetcode_53_最大子序和_贪心
特判一下全负数接着每当出现一段数总和为负数,就全部丢弃每当出现一段数总和为正数,并且增加的是正数,更新答案与标程的动态规划以及分治有异曲同工之妙class Solution { public int maxSubArray(int[] nums) { int ans = 0; int now = 0; boolean flag = true; for (int num : nums) { if (num原创 2021-04-30 00:47:24 · 79 阅读 · 0 评论 -
Leetcode_70_爬楼梯_dp
别问我为什么是斐波那契数列真要问我只能告诉你,我做过,23333好吧,其实是动态规划当前层的方法状态为前1层和前2层的方法总数。class Solution { public int climbStairs(int n) { int[] nums = new int[n + 2]; nums[1] = 1; nums[2] = 2; for (int i = 3; i <= n; i++) { n原创 2021-04-30 00:30:49 · 76 阅读 · 0 评论 -
Leetcode_32_最长有效括号_栈/dp/贪心
看了编程的思路后写的,和标程基本一样我觉得这个压入-1的操作,不是一般人能想到的第一遍写的时候用的是Stack,但所用时间是deque的两倍dp的话是最容易想到的,但方程的推到略有难度最后一种巧妙的贪心,个人觉得也很难想到orzclass Solution { public int longestValidParentheses(String s) { Deque<Integer>stack = new ArrayDeque<Integer>();原创 2021-04-29 23:42:32 · 83 阅读 · 0 评论 -
Leetcode_403_青蛙过河_dp
dp[i][k]代表第i块,上次跳了k距离的状态,第i块最多跳i步,预处理非法状态,中间状态 第j块最多跳j步,剪枝非法状态。class Solution { public boolean canCross(int[] stones) { int len = stones.length; //dp[i][k]代表第i块,上次跳了k距离的状态 boolean[][] dp = new boolean[len][len]; for (原创 2021-04-29 10:28:14 · 110 阅读 · 0 评论 -
Leetcode_5_最长回文子串_dp
难点还是想到动态规划回文串是经典的动态规划使用场景因为回文串可以由通过判定头尾,从子串转移过来至于马拉车算法,饶了我吧,acm退队了,不想卷这种算法了QAQ顺便提一下,这个用startindex与maxlen来暂存字符串信息挺好的,值得借鉴另外我使用了maxlen初始值为1来规避掉了标程的特判,也是一个不错的写法~(java中substring的len溢出会自动给你补终止符)class Solution { public String longestPalindrome(String原创 2021-04-28 15:35:29 · 100 阅读 · 0 评论 -
Leetcode_10_正则表达式匹配_dp
写完以后感觉不是很难的一道题,难点是想到动态规划因为每一步的是否匹配是可以由之前的匹配状态转移过来比如{aa,aa*}的匹配状态可以从{a,a}以及{aa,a}等状态转移过来。我们应该将s字符串作为大循环开始匹配因为s与p的关系是多对一–如果p是“*”,我们就要检测p当前的字符与 * 之前的字符是否匹配,----若匹配(注意,“.”也可以匹配),我们可以由p之前的状态转移过来,dp[i][j] = dp[i - 1][j],也可以由s之前的状态转移过来dp[i][j] = dp[i][j - 2原创 2021-04-28 15:30:09 · 134 阅读 · 0 评论 -
Leetcode_746_使用最小花费爬楼梯_dp
12/21经典dpclass Solution { public int minCostClimbingStairs(int[] cost) { int n=cost.length; int []dp=new int[n+1]; for(int i=0;i<n;i++){ dp[i]=Integer.MAX_VALUE-999; } dp[n]=0; for(int i原创 2020-12-21 11:32:12 · 300 阅读 · 0 评论 -
Leetcode_1690_石子游戏 Ⅶ_动态规划
12/17后有详细解答步骤class Solution { public int stoneGameVII(int[] stones) { int n=stones.length; //从第一个到第i个,石头的总数 int []sum=new int[n]; sum[0]=stones[0]; for(int i=1;i<n;i++){ sum[i]=sum[i-1]+stones[i原创 2020-12-17 12:49:48 · 380 阅读 · 0 评论 -
Leetcode_714_买卖股票的最佳时机_动态规划
12/17设立两种状态,一种是持有股票的状态,一种是没有股票的状态,然后进行状态转移后面有详细的思维过程最终代码如下class Solution { public int maxProfit(int[] prices, int fee) { //no是不持有,yes是持有股票 int no = 0; int yes = -prices[0]; for (int i = 1; i < prices.length; i++)原创 2020-12-17 11:40:04 · 331 阅读 · 0 评论 -
Leetcode_376_摆动序列_动态规划_贪心
12/12动态规划设定up和down两个变量分别存储尾部上升和尾部下降的最长子序列如果当前元素比前一个元素大,up=down+1对前一个元素,一定有以前一个元素结尾的长度为down的尾部下降子序列,再接上当前元素,就能成为一个尾部上升的子序列,用这个值去更新up同理若当前元素比前一个元素小,用up+1去更新downclass Solution { public int wiggleMaxLength(int[] nums) { int n = nums.length;原创 2020-12-12 09:39:05 · 355 阅读 · 0 评论