看看目前为止做过的动态规划题目

  • 算法导论课+Hot100DP

    • image.pngimage.png
  • 动态规划,是两种思想的结合:分治思想(子问题)+解决冗余(填表查表);动态规划可解的前提,是原问题具备最优子结构,通过一步操作(转移方程),将原问题转为子问题求解

    • 可总结为:最优子结构,重叠子问题
    • 同时也是判断一个思路是否符合DP的标准
  • 是否具备最优子结构(不重不漏+最优性原理),需要打开思路;常需要列举,max, min 等求解;
  • 对于求解问题需要明确,以定义最优值
  • 求解当前问题时,是建立在已知全部子问题解的假设下的。原问题应该由子问题不重不漏的组成。
  • 做dP过程遇到一些技巧题(变形)
    • 1-“股票买卖问题:由于含有冷冻期,定义目标解时,每个状态(第i天)的最大收益,通过max{…}表示,基于此设计状态转移方程
    • 2-打家劫舍III。此题最优解的定义与股票买卖问题有异曲同工之妙。同时,是dp和树的结合(想想为什么是后续遍历)
    • 3-分割等和子集:对所求目标变形。dp过程的目标解,并非来自直接题目所求,而是需要做一定的换算
  • DP的艺术很大一部分来自目标解的定义。
    • 上面的变形题,不管是max/min{ }来间接表示目标解,还是通过约束进行计算转换,都是
    • 还有,单单是目标解本身定义的好,往往在求解时就能茅舍顿开-见 “最大正方形面积”

sum_Note_20220223:

  • 复习一遍
  • 做Dp,一定要清楚子问题是什么?如果子问题无法很好入手和得到,那么可不可以将原问题拆解为多个“不重不漏”的问题的集合(比如冷冻期股票问题、最大乘积数组、求最长无重复字符 子字符串长度),最后用max{}等技巧来求解。分解原问题,目的是为了更好的“新的问题”下的“子问题”。只有原问题和子问题清楚,才能使用动态规划,设计 动态转移方程。

切杆问题

image.png
动态规划 - 图4%22%20aria-hidden%3D%22true%22%3E%0A%20%3Cuse%20xlink%3Ahref%3D%22%23E1-MJMATHI-72%22%20x%3D%220%22%20y%3D%220%22%3E%3C%2Fuse%3E%0A%20%3Cuse%20xlink%3Ahref%3D%22%23E1-MJMAIN-5B%22%20x%3D%22451%22%20y%3D%220%22%3E%3C%2Fuse%3E%0A%20%3Cuse%20xlink%3Ahref%3D%22%23E1-MJMATHI-6E%22%20x%3D%22730%22%20y%3D%220%22%3E%3C%2Fuse%3E%0A%20%3Cuse%20xlink%3Ahref%3D%22%23E1-MJMAIN-5D%22%20x%3D%221330%22%20y%3D%220%22%3E%3C%2Fuse%3E%0A%20%3Cuse%20xlink%3Ahref%3D%22%23E1-MJMAIN-3D%22%20x%3D%221886%22%20y%3D%220%22%3E%3C%2Fuse%3E%0A%20%3Cuse%20xlink%3Ahref%3D%22%23E1-MJMATHI-6D%22%20x%3D%222943%22%20y%3D%220%22%3E%3C%2Fuse%3E%0A%20%3Cuse%20xlink%3Ahref%3D%22%23E1-MJMATHI-61%22%20x%3D%223821%22%20y%3D%220%22%3E%3C%2Fuse%3E%0A%3Cg%20transform%3D%22translate(4351%2C0)%22%3E%0A%20%3Cuse%20xlink%3Ahref%3D%22%23E1-MJMATHI-78%22%20x%3D%220%22%20y%3D%220%22%3E%3C%2Fuse%3E%0A%3Cg%20transform%3D%22translate(572%2C-150)%22%3E%0A%20%3Cuse%20transform%3D%22scale(0.707)%22%20xlink%3Ahref%3D%22%23E1-MJMAIN-31%22%20x%3D%220%22%20y%3D%220%22%3E%3C%2Fuse%3E%0A%3Cg%20transform%3D%22translate(353%2C0)%22%3E%0A%20%3Cuse%20transform%3D%22scale(0.707)%22%20xlink%3Ahref%3D%22%23E1-MJMAIN-3C%22%3E%3C%2Fuse%3E%0A%20%3Cuse%20transform%3D%22scale(0.707)%22%20xlink%3Ahref%3D%22%23E1-MJMAIN-3D%22%20x%3D%22778%22%20y%3D%220%22%3E%3C%2Fuse%3E%0A%3C%2Fg%3E%0A%20%3Cuse%20transform%3D%22scale(0.707)%22%20xlink%3Ahref%3D%22%23E1-MJMATHI-69%22%20x%3D%222057%22%20y%3D%220%22%3E%3C%2Fuse%3E%0A%3Cg%20transform%3D%22translate(1699%2C0)%22%3E%0A%20%3Cuse%20transform%3D%22scale(0.707)%22%20xlink%3Ahref%3D%22%23E1-MJMAIN-3C%22%3E%3C%2Fuse%3E%0A%20%3Cuse%20transform%3D%22scale(0.707)%22%20xlink%3Ahref%3D%22%23E1-MJMAIN-3D%22%20x%3D%22778%22%20y%3D%220%22%3E%3C%2Fuse%3E%0A%3C%2Fg%3E%0A%3Cg%20transform%3D%22translate(2800%2C0)%22%3E%0A%20%3Cuse%20transform%3D%22scale(0.707)%22%20xlink%3Ahref%3D%22%23E1-MJMAIN-31%22%3E%3C%2Fuse%3E%0A%20%3Cuse%20transform%3D%22scale(0.707)%22%20xlink%3Ahref%3D%22%23E1-MJMAIN-30%22%20x%3D%22500%22%20y%3D%220%22%3E%3C%2Fuse%3E%0A%3C%2Fg%3E%0A%3C%2Fg%3E%0A%3C%2Fg%3E%0A%20%3Cuse%20xlink%3Ahref%3D%22%23E1-MJMAIN-7B%22%20x%3D%228531%22%20y%3D%220%22%3E%3C%2Fuse%3E%0A%20%3Cuse%20xlink%3Ahref%3D%22%23E1-MJMATHI-72%22%20x%3D%229032%22%20y%3D%220%22%3E%3C%2Fuse%3E%0A%20%3Cuse%20xlink%3Ahref%3D%22%23E1-MJMAIN-5B%22%20x%3D%229483%22%20y%3D%220%22%3E%3C%2Fuse%3E%0A%20%3Cuse%20xlink%3Ahref%3D%22%23E1-MJMATHI-6E%22%20x%3D%229762%22%20y%3D%220%22%3E%3C%2Fuse%3E%0A%20%3Cuse%20xlink%3Ahref%3D%22%23E1-MJMAIN-2212%22%20x%3D%2210584%22%20y%3D%220%22%3E%3C%2Fuse%3E%0A%20%3Cuse%20xlink%3Ahref%3D%22%23E1-MJMATHI-69%22%20x%3D%2211585%22%20y%3D%220%22%3E%3C%2Fuse%3E%0A%20%3Cuse%20xlink%3Ahref%3D%22%23E1-MJMAIN-5D%22%20x%3D%2211930%22%20y%3D%220%22%3E%3C%2Fuse%3E%0A%20%3Cuse%20xlink%3Ahref%3D%22%23E1-MJMAIN-2B%22%20x%3D%2212431%22%20y%3D%220%22%3E%3C%2Fuse%3E%0A%20%3Cuse%20xlink%3Ahref%3D%22%23E1-MJMATHI-70%22%20x%3D%2213432%22%20y%3D%220%22%3E%3C%2Fuse%3E%0A%20%3Cuse%20xlink%3Ahref%3D%22%23E1-MJMAIN-5B%22%20x%3D%2213935%22%20y%3D%220%22%3E%3C%2Fuse%3E%0A%20%3Cuse%20xlink%3Ahref%3D%22%23E1-MJMATHI-69%22%20x%3D%2214214%22%20y%3D%220%22%3E%3C%2Fuse%3E%0A%20%3Cuse%20xlink%3Ahref%3D%22%23E1-MJMAIN-5D%22%20x%3D%2214559%22%20y%3D%220%22%3E%3C%2Fuse%3E%0A%20%3Cuse%20xlink%3Ahref%3D%22%23E1-MJMAIN-7D%22%20x%3D%2214838%22%20y%3D%220%22%3E%3C%2Fuse%3E%0A%3C%2Fg%3E%0A%3C%2Fsvg%3E#card=math&code=r%5Bn%5D%3Dmax_%7B1%3C%3Di%3C%3D10%7D%5C%7Br%5Bn-i%5D%2Bp%5Bi%5D%5C%7D%0A&id=R25Q6)

剑指 Offer 14- I. 剪绳子

此题我认为本质也是“切杆问题”
image.png
这道题在解的时候,容易陷入剪几段不确定,要列举很多情况的误区。实际上,定义f[m] 为长度为m下,符合题意的最优解。写动态转移方程时,便可以轻松包含全部“剪法的情况”:动态规划 - 图6
剪成任意多段(>2),肯定第一刀是剪成2段, 或者说剪得再碎,也能拼成两段。所以这就是一个常见的dp问题。小细节是,因为至少要剪一刀,注意f[ ]的初始条件和特殊情况下的直接返回值,并不是对应的。

背包问题

image.png
动态规划 - 图8
边界条件:
dp[i][j] = 0 ; if i=0
dp[i][j] = 0; if j = 0 ;
效率:O(nW)

矩阵链乘问题

image.png
此DP难的是对问题的抽象
动态规划 - 图10
在实现代码时,可以用自底向上的方式,以链长l 递增方向
扩展思考: 如何优雅的打印链乘结果?

最长子序列

image.png
动态规划 - 图12

求构成数的最小数量平方和

image.png
动态规划 - 图14

求最長遞增子序列(dp解、dp解2-貪心思想)

image.png
dp解1
动态规划 - 图16
dp解2-利用贪心思想
动态规划 - 图17
这里关键,find 第一个 小于nums[i的的dp 位置pos,更新dp[pos+1]位置
举例:已有子序列 <2>-<4><6>
if num[i] = 5 , pos = 2 , 更新dp[3]=5 , 得 <2><4><5>
if num[i] = 3 , pos = 1 , 更新dp[2]=3 , 得 <2><3><5>

股票买卖含冷冻期

给定一个整数数组,其中第 i 个元素代表了第 i 天的股票价格 。

设计一个算法计算出最大利润。在满足以下约束条件下,你可以尽可能地完成更多的交易(多次买卖一支股票):

你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
卖出股票后,你无法在第二天买入股票 (即冷冻期为 1 天)。
示例:

输入: [1,2,3,0,2]
输出: 3
解释: 对应的交易状态为: [买入, 卖出, 冷冻期, 买入, 卖出]

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-with-cooldown
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

分析:
之前的草稿,虽然字好丑懒得写了,将就看吧🤣
image-20210914103851105.png

最小硬币数

给你一个整数数组 coins ,表示不同面额的硬币;以及一个整数 amount ,表示总金额。

计算并返回可以凑成总金额所需的 最少的硬币个数 。如果没有任何一种硬币组合能组成总金额,返回 -1 。

你可以认为每种硬币的数量是无限的。

示例 1:
输入:coins = [1, 2, 5], amount = 11
输出:3
解释:11 = 5 + 5 + 1
示例 2:
输入:coins = [2], amount = 3
输出:-1
示例 3:

动态规划 - 图19
将dp[i]初始化为一个大数{flag+1},最后return dp[amount] >flage ? -1 : dp[amount] 即可

小偷偷家

  • 题目描述
    • 小偷偷家,不能偷相邻的两家。传入一个nums数组,值是每一家的财产,均大于零,求最佳的偷家结果

分析-看官方解:

  • 动态规划 - 图20
  • 这里其实有个细节需要好好推敲,对于dp[i], 确实只有2种情况,nums[i]选还是不选;不选择,则dp[i] = dp[i-1]. 但关键是选择的时候,这里dp[i] = dp[i-2]+nums[i]; 但我们并不知道dp[i-1]是选了nums[i-1],还是没选nums[i-1],似乎dp[i-1]要是没选,则最优解应该是dp[i-1]+nums[i], 我们并没有考虑到这个情况; 但实际上,这个动态规划方程恰好囊括了全部情况的最优解,我们再进一步分析:
  • 假设dp[i-1]选了nums[i-1],那么di[i]=max{dp[i-1],dp[i-2]+nums[i]}毫无疑问是对的
  • 假设dp[i-1]没选nums[i-1], 则dp[i-1] = dp[i-2], 故di[i]=max{dp[i-1],dp[i-2]+nums[i]} 考虑了所有的情况

分析-另外一种解

  • 有时候不一定会想得这么仔细,这里提供另外一种解
  • f[i] 表示考虑第1,…,第i家时,第i家选择时的最佳偷窃策略
  • g[i] 表示考虑第1,…,第i家时,第i家不选择时的最佳偷窃策略
  • 目标解Max{f[i],g[i] }
  • 状态转移方程:
    • f[i] = g[i-1]+nums[i]
    • g[i] = max{g[i-1],f[i-1]}

打家劫舍III

在上次打劫完一条街道之后和一圈房屋后,小偷又发现了一个新的可行窃的地区。这个地区只有一个入口,我们称之为“根”。 除了“根”之外,每栋房子有且只有一个“父“房子与之相连。一番侦察之后,聪明的小偷意识到“这个地方的所有房屋的排列类似于一棵二叉树”。 如果两个直接相连的房子在同一天晚上被打劫,房屋将自动报警。

计算在不触动警报的情况下,小偷一晚能够盗取的最高金额。

示例 1:

输入: [3,2,3,null,3,null,1]

  1. 3<br /> / \

2 3
\ \
3 1

输出: 7
解释: 小偷一晚能够盗取的最高金额 = 3 + 3 + 1 = 7.
示例 2:

分析

  • 首先本题是dp问题和二叉树的结合。如何结合?根节点的状态作为原问题,将子问题的解(状态)作为子孙节点的状态。对二叉树的后续遍历,由于祖先后遍历,相当于一般动态规划问题自底向上求解的过程。当然,代码写成后续递归遍历(简单),就是对应动态规划问题自顶向下求解。Anyway实现方式不是重点,重点是,dp思想恰好通过后续遍历进行体现:访问祖先之前,全部孙子均已遍历,求解原问题时,子问题全部解已知。
  • 第二个要点,类似于股票求解问题。用 max{ }结构定义最优解,这样写状态转移方程时,更简单。

解:
动态规划 - 图21

能否分割等和子集

image.png
分析:

  • 这是一个NP问题,所以我们的思路是,能否分割等和子集,并没有多项式时间内能求解的方法
  • 先求数组全部元素和sum。 数组长度小于2,不可;sum 是奇数,不可;sum是偶数,dp_target = sum/2 , 转化为背包问题求解
    • 这样做有什么好处?只管只要能够挑选一些元素,使其和等于dp_target, 就求解了原问题:能否分割等和子集

动态规划 - 图23
优化空间复杂度:滚动数组

  • 注意到每个问题的状态:dp[i][j]只由两个子问题的状态决定
    • dp[i-1][j-nums[i]] —>dp[j-nums[i]]
    • dp[i-1][j] —> dp[j]
  • 所以最少只需要用一个一纬数组保存此刻状态,并不断更新即可:
    • when i=i, dp[j] = dp[j] || dp[j-nums[i]]
    • 外层循环是i-从小到大 , 内层循环是j-必须从大到小,因为需要用到旧值,j>j-nums,故dp[j]要先更新

寻找目标和(本题和上一题是一类)

image.png

分析

  • 基本思路就是转换为背包问题
  • 能否从Nums[ ]中挑选一些数,使其和为newTar=(sum+tar)/2

    • 先求总的sum, if abs [tar] >sum , return 0; if abs[tar] = sum , return 1
    • newTar 是奇,不可能
    • newTar是偶数,继续求解
    • 动态规划 - 图25

      *求回文串的数量

  • https://leetcode-cn.com/problems/palindromic-substrings/)

  • image.png

分析

  • 必须掌握的是 中心 拓展算法(非DP)
  • image.png

    1. class Solution {
    2. public int countSubstrings(String s){
    3. int l = s.length();
    4. int cou=0;
    5. for(int i=0;i<2*l-1;i++){
    6. //枚举每个中心(每个中心点的left,right坐标)
    7. int left = i/2;
    8. int right = i/2+i%2;
    9. while(left>=0 && right<l && s.charAt(left)==s.charAt(right)){
    10. cou++;
    11. left--;
    12. right++;
    13. }
    14. }
    15. return cou;
    16. }
    17. }
    • 动态规划算法
      • 看下题,对dp[][]数组,统计值为true的个数,即为本题的解
    • Manacher 算法-DP
      • 埋个坑,后面再补吧..

最长回文串

image.png
分析

  • 本题和上一题本质是同一道题,解题方法是互通的。
  • 因为无论是求解回文子串的数量还是 求解最长回文子串,都需要遍历所有是回文子串的状态
  • 下面给出DP求解方法(非马拉车算法)
  • 动态规划 - 图29
  • 注意实现时,枚举的是子字符串的长度 ```java public String longestPalindrome(String s) {

    1. int len = s.length();
    2. if(len<2) return s;
    3. char[] sChar = s.toCharArray();
    4. boolean dp[][] = new boolean[len][len];
    5. //初始化,另外一个边界条件不需要刻意初始化
    6. for(int i=0;i<len;i++) dp[i][i]=true;
    7. int maxLen = 1,beginFlag=0;
    8. for(int sublen=2;sublen<=len;sublen++){//从2开始循环,1已求解
    9. //枚举所有左端点
    10. for(int left=0;left<len;left++){//左端点的上限可以宽松
    11. //左端点确定,长度确定,确定右端点
    12. int right = left+sublen-1; //记得减一
    13. if(right >=len) break;
    14. if(sChar[right] != sChar[left]) dp[left][right]=false;
    15. else{
    16. if(right-left<3){
    17. dp[left][right] = true;
    18. }else{
    19. dp[left][right] = dp[left+1][right-1];
    20. }
  1. }
  2. if(dp[left][right] && right-left+1 > maxLen){
  3. maxLen = right-left+1;
  4. beginFlag = left;
  5. }
  6. }
  7. }
  8. return s.substring(beginFlag,beginFlag+maxLen);
  9. }
  1. <a name="HQUHt"></a>
  2. ### 最大子序和
  3. [53. 最大子数组和](https://leetcode-cn.com/problems/maximum-subarray/)<br />![image.png](https://cdn.nlark.com/yuque/0/2021/png/22442214/1633312300932-c0ae2593-83ea-4efe-bb42-ba52e2317326.png#clientId=u14209b24-897e-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=269&id=u4d0d870a&margin=%5Bobject%20Object%5D&name=image.png&originHeight=538&originWidth=967&originalType=binary&ratio=1&rotation=0&showTitle=false&size=37631&status=done&style=none&taskId=u489a3417-4bc0-481b-96b3-1cb5e87d23a&title=&width=483.5)<br />分析:<br />![](https://cdn.nlark.com/yuque/__latex/d4c2cca2c87b55f86740e48e9f7a02f7.svg#card=math&code=dp%5Bi%5D%3A%E8%A1%A8%E7%A4%BA%E4%BB%A5nums%5Bi%5D%E5%85%83%E7%B4%A0%E7%BB%93%E5%B0%BE%E7%9A%84%E6%9C%80%E5%A4%A7%E8%BF%9E%E7%BB%AD%E5%AD%90%E6%95%B0%E7%BB%84%E5%92%8C%5C%5C%0Adp%5Bi%5D%3Ddp%5Bi-1%5D%2Bnums%5Bi%5D%2Cif%5C%20dp%5Bi-1%5D%3E0%5C%5C%0Adp%5Bi%5D%3Dnums%5Bi%5D%2Cif%5C%20dp%5Bi-1%5D%3C%3D0%3B%5C%5C%0A%E7%AD%89%E4%BB%B7%E5%86%99%E6%B3%95%EF%BC%9Adp%5Bi%5D%3Dmax%5C%7Bdp%5Bi-1%5D%2Bnums%5Bi%5D%2Cnums%5Bi%5D%20%5C%7D%5C%5C%0A%E8%BE%B9%E7%95%8C%EF%BC%9Adp%5B0%5D%3D0%5C%5C%0Atarget%3AMax%5C%7Bdp%5Bi%5D%5C%7D&id=L1ERf)
  4. <a name="pPs30"></a>
  5. ### *最大乘积数组
  6. [152. 乘积最大子数组](https://leetcode-cn.com/problems/maximum-product-subarray/)<br />给你一个整数数组 nums,请你找出数组中乘积最大的连续子数组(该子数组中至少包含一个数字),并返回该子数组所对应的乘积
  7. 分析
  8. - 此题和上一题【最大子序和】有相似的最优解结构,但又不同。因为它的状态转移方程更加复杂。
  9. - 由于nums[i]是负数时,负负得正,那么nums[i]<0时,我们需要乘上![](https://cdn.nlark.com/yuque/__latex/7b1481438b878ba4459874141ed98ce6.svg#card=math&code=f_%7Bmin%7D%5Bi-1%5D&id=CnPc9)
  10. - 这启发我们,为了写出动态方程,我们不仅需要维护f_max, 还要维护f_min ; **这是很常用的一个技巧**
  11. - ![](https://cdn.nlark.com/yuque/__latex/792486448089c5995794bdecc1691024.svg#card=math&code=dpMax%5Bi%5D%3A%E8%A1%A8%E7%A4%BA%E4%BB%A5nums%5Bi%5D%E7%BB%93%E5%B0%BE%E7%9A%84%E6%9C%80%E5%A4%A7%E8%BF%9E%E7%BB%AD%E5%AD%90%E6%95%B0%E7%BB%84%E4%B9%98%E7%A7%AF%5C%5C%0AdpMin%5Bi%5D%3A%E8%A1%A8%E7%A4%BA%E4%BB%A5nums%5Bi%5D%E7%BB%93%E5%B0%BE%E7%9A%84%E6%9C%80%E5%B0%8F%E8%BF%9E%E7%BB%AD%E5%AD%90%E6%95%B0%E7%BB%84%E4%B9%98%E7%A7%AF%5C%5C%0AdpMax%5Bi%5D%20%3D%20Max%5C%7BdpMax%5Bi-1%5D%2Anums%5Bi%5D%2CdpMin%5Bi-1%5D%2Anums%5Bi%5D%2Cnums%5Bi%5D%5C%7D%5C%5C%0AdpMin%5Bi%5D%20%3D%20Min%5C%7BdpMax%5Bi-1%5D%2Anums%5Bi%5D%2CdpMin%5Bi-1%5D%2Anums%5Bi%5D%2Cnums%5Bi%5D%5C%7D%5C%5C%0A%E8%BE%B9%E7%95%8C%EF%BC%9A%5C%5CdpMax%5B0%5D%3DdpMin%5B0%5D%3Dnums%5B0%5D%5C%5C%0A&id=UoRq7)
  12. <a name="zWhNo"></a>
  13. ### 不同路径I 和 不同路径II
  14. - 比较简单就不写了
  15. - [63. 不同路径 II](https://leetcode-cn.com/problems/unique-paths-ii/)
  16. - [62. 不同路径](https://leetcode-cn.com/problems/unique-paths/)
  17. <a name="Tt2qb"></a>
  18. ### *单词拆分

给定一个非空字符串 s 和一个包含非空单词的列表 wordDict,判定 s 是否可以被空格拆分为一个或多个在字典中出现的单词。

说明:

拆分时可以重复使用字典中的单词。 你可以假设字典中没有重复的单词

示例 1:

输入: s = “leetcode”, wordDict = [“leet”, “code”] 输出: true 解释: 返回 true 因为 “leetcode” 可以被拆分成 “leet code”。

  1. 分析:
  2. - 字符串s能被分解,一定是开头的子串也能被分解。可以抓住这一点,来列举所有可能的情况:
  3. - 对于一个字符串s(0,i),能被分解的情况是存在 j , 使得 s(0 , j) s(j, i ) 能被分解;0<i<len
  4. - dp[i]表示,s(0,i)是否可以被空格拆分为一个或多个在字典中出现的单词
  5. - ![](https://cdn.nlark.com/yuque/__latex/9d463485cdc6084b1a3b5777b33d722a.svg#card=math&code=dp%5Bi%5D%20%3D%20true%2Cif%5C%20once%5C%20dp%5Bj%5D%5C%26contains%28s%28j%2Ci%29%29%20%3D%3D%20true%2C%200%3C%3Dj%3Ci%20%5C%5C%0Aelse%5C%20dp%5Bi%5D%20%3D%20false&id=dejrg)
  6. - 边界条件:dp[0]=true
  7. <a name="GilCx"></a>
  8. ### [140. 单词拆分 I](https://leetcode-cn.com/problems/word-break-ii/)[I](https://leetcode-cn.com/problems/word-break-ii/)
  9. 字典树
  10. <a name="JFwQV"></a>
  11. ### 求最大正方形面积
  12. ![image.png](https://cdn.nlark.com/yuque/0/2021/png/22442214/1633401149272-8ef7c87c-0d75-49f0-88a7-c019cc6a640d.png#clientId=u14209b24-897e-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=198&id=ue5b26939&margin=%5Bobject%20Object%5D&name=image.png&originHeight=395&originWidth=920&originalType=binary&ratio=1&rotation=0&showTitle=false&size=58505&status=done&style=none&taskId=u327e6d94-c13e-44f3-84f2-ea59004c7c6&title=&width=460)<br />分析<br />![](https://cdn.nlark.com/yuque/__latex/a377f5edba31be1928486ebcd75c50f1.svg#card=math&code=dp%5Bi%5D%5Bj%5D%E8%A1%A8%E7%A4%BA%E4%BB%A5nums%5Bi%5D%5Bj%5D%E4%B8%BA%E6%AD%A3%E6%96%B9%E5%BD%A2%E5%8F%B3%E4%B8%8B%E8%A7%92%E6%97%B6%EF%BC%8C%E6%9C%80%E5%A4%A7%E7%9A%84%E9%9D%A2%E7%A7%AF%E8%BE%B9%E9%95%BF%5C%5C%0Aif%5C%20nums%5Bi%5D%5Bj%5D%3D0%2Cdp%5Bi%5D%5Bj%5D%3D0%5C%5C%0Aif%5C%20nums%5Bi%5D%5Bj%5D%3D1%2Cdp%5Bi%5D%5Bj%5D%3DMin%5C%7Bdp%5Bi-1%5D%5Bj%5D%2Cdp%5Bi-1%5D%5Bj-1%5D%2Cdp%5Bi%5D%5Bj-1%5D%20%5C%7D&id=hWvqd)
  13. <a name="TaolJ"></a>
  14. ### 求最长无重复字符子字符串长度
  15. 请从字符串中找出一个最长的不包含重复字符的子字符串,计算该最长子字符串的长度。
  16. ![image.png](https://cdn.nlark.com/yuque/0/2021/png/22442214/1636426691994-ca3fa4be-61d7-4d28-bfe9-9654deabfd5b.png#clientId=u9470d9aa-9ef1-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=183&id=u1206caf1&margin=%5Bobject%20Object%5D&name=image.png&originHeight=366&originWidth=551&originalType=binary&ratio=1&rotation=0&showTitle=false&size=21727&status=done&style=none&taskId=ue4715257-8a12-4e6f-a7e6-26a479516e0&title=&width=275.5)
  17. 注:此题字符串中的字符没有说就是小写字母<br />![](https://cdn.nlark.com/yuque/__latex/39a6acbd810df0fdae2bd5e5cd7754a9.svg#card=math&code=%E7%94%A8%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%92%E6%98%AF%E6%9C%80%E5%BF%AB%E7%9A%84%EF%BC%8C%E7%BB%93%E5%90%88%E6%BB%91%E5%8A%A8%E7%AA%97%E5%8F%A3%EF%BC%8C%E8%BE%BE%E5%88%B0O%28n%29%2CO%281%29%2C%E5%9F%BA%E6%9C%AC%E6%80%9D%E8%B7%AF%E5%B0%B1%E6%98%AF%5C%5C%0Af%28i%29%EF%BC%9A%E8%A1%A8%E7%A4%BA%E4%BB%A5%E7%AC%ACi%E4%B8%AA%E5%AD%97%E7%AC%A6%E7%BB%93%E5%B0%BE%E7%9A%84%E6%9C%80%E9%95%BF%E6%97%A0%E9%87%8D%E5%A4%8D%E5%AD%97%E7%AC%A6%E7%9A%84%E5%AD%90%E4%B8%B2%E9%95%BF%E5%BA%A6%5C%5C%0A%E5%9C%A8%E7%A1%AE%E5%AE%9A%E7%8A%B6%E6%80%81%E8%BD%AC%E7%A7%BB%E6%96%B9%E7%A8%8B%E6%97%B6%EF%BC%8C%E6%9C%89%E4%B8%80%E4%B8%AA%E5%85%B3%E9%94%AE%E7%9A%84%E5%8F%98%E9%87%8F%EF%BC%8Cd%3A%20%E5%BD%93%E5%89%8D%E5%AD%97%E7%AC%A6%E4%B8%8E%E4%B8%8A%E4%B8%80%E6%AC%A1%E8%AF%A5%E5%AD%97%E7%AC%A6%E5%87%BA%E7%8E%B0%E7%9A%84%E8%B7%9D%E7%A6%BB%5C%5C%0A%20%20if%20%E6%9C%AA%E5%87%BA%E7%8E%B0%E8%BF%87%EF%BC%8C%20f%28i%29%3Df%28i-1%29%2B1%5C%5C%0A%20%20d%3C%3Df%28i-1%29%3Af%28i%29%3Dd%5C%5C%0A%20%20d%3Ef%28i-1%29%3Af%28i%29%3Df%28i-1%29%2B1%5C%5C&id=t569b)
  18. ```java
  19. package SwordOf.dynamicPro;
  20. import org.junit.Test;
  21. import java.util.HashMap;
  22. import java.util.HashSet;
  23. public class LengthOfLongestSubstring {
  24. /*剑指上s的值只是小写字母,但leetcode则没有这一限制;
  25. 所以不能用一个小数组来记录下标了,需要用HashMap<字符,上一次出现的值>*/
  26. public int lengthOfLongestSubstring(String s) {
  27. if (s.length() == 0) return 0;
  28. /* int[] preAppearPosition = new int[26];
  29. for (int i = 0; i < 26; i++) {
  30. preAppearPosition[i] = -1;
  31. }*/
  32. HashMap<Character, Integer> map = new HashMap<>();
  33. int maxLen = Integer.MIN_VALUE;
  34. int len = 0;//len表示当前字符到到上一次该字符出现的情况;len>=1, 1就是相邻aa的情况;
  35. int fPre = 0;
  36. for (int i = 0; i < s.length(); i++) {
  37. char ch = s.charAt(i);
  38. //该字符从未出现过
  39. if (!map.containsKey(ch)) {
  40. // fPre = fPre++;
  41. fPre++;
  42. map.put(ch, i);
  43. } else { //该字符出现过
  44. //先求两个该字符间的距离,再分两种情况处理
  45. len = i - map.get(ch);
  46. map.put(ch,i);
  47. if (len <= fPre) fPre = len;
  48. else {
  49. //fPre = fPre++;什么玩意
  50. fPre++;
  51. }
  52. }
  53. if (fPre > maxLen) maxLen = fPre;
  54. }
  55. return maxLen;
  56. }
  57. @Test
  58. public void test() {
  59. String s = "abcabcbb";
  60. int len = lengthOfLongestSubstring(s);
  61. System.out.println(len);
  62. }
  63. @Test
  64. public void test2() {
  65. int i = 0;
  66. for (int j = 0; j < 2; j++) {
  67. i=++i;
  68. // i=i++;
  69. }
  70. System.out.println(i);
  71. }
  72. }