获得徽章 17
- 678. 有效的括号字符串
思路:
常规判断有效括号一般去计算最终的平衡度(或者叫最终剩余的左括号数量)是否为0去判断最终是否有效,
但是*号的出现可能导致平衡度出现多种情况, 为了描述多种情况用一个范围[min, max] 去表示 最低可能的平衡度为min, 最大可能的平衡度为max.
在扫描过程中遇到" ( "同时加1, 遇到” ) “同时减1、遇到*则扩展范围(--min, max++)
在扫描过程中一旦连最大可能的平衡度max 都小于等于0 说明当前左括号数量小于右括号数量, 最终一定是无效括号.
最终如果在[mid, max] 区间存在平衡度为0, 则可能存在有效括号的情况展开赞过评论1 - 28. 实现 strStr()
思路1: 暴力
见代码
思路2: KMP算法 (双指针)
先通过计算一个叫next的数组, next[i] 表示 [0,i]之间最长的公共前后缀的长度. 它的意义在于当模式串[j]和主串[i]发生不匹配时, 直接用next[j - 1] 位置继续与主串的i开始比较即可, 不必再从模式串的头开始匹配.
核心在于如何计算next数组. 就是计算每个位置next[i]的最长公共前后缀的长度
比如 ABABAA
next[0] = 0 , A
next[1] = 0 , AB
next[2] = 1 , ABA
next[3] = 2 , ABAB
next[4] = 3 , ABABA
next[5] = 1 , ABABAA
在代码实现上通过定义前后缀两个指针去迭代计算最长公共前后缀的长度
1) 当 pattern[j] == pattern[i] 时, 前后缀指针同时加1即可
2)但是当 pattern[j] != pattern[i] 时, 但是它们的上一部分(公共前后缀) 是匹配的. 所以从 next[j - 1] 开始计算公共前后缀(即 [0, j-1]的 最长公共前后缀),
此时再判断上一个公共部分j 与 当前公共部分的i 比较. 此时同理再次判断 i 和 j 是否不匹配. 匹配走上面 “1)” 过程 , 不匹配重复走的"2)" 过程.
总的来说就是不断缩小可能的公共部分去比较, 进而找到最长的公共前后缀.展开赞过53 - 448. 找到所有数组中消失的数字
思路: 占坑法
遍历到i 时, 用nums[i] 值作为索引index在 nums[index] 上占坑,
1、负数占坑法
比如将 nums[index]乘与 -1 变成负数, 到时候遍历到被占坑过的数的时候 取绝对值即可取回未被占坑前的数, 就可以重新用它去占坑. 最后如果一个数小于n说明未被占过坑.
2、加法占坑法
比如将 nums[index]加 上 n(数组长度) 去占坑, 到时候遍历到被占坑过的数的时候取对n的余数即可取回未被占坑前的数, 就可以重新用它取占坑.
最后如果不为负数说明未被占过坑.
占坑结束后, 再扫一遍数组, 如果该数未被占过坑说明是消失的数字.展开赞过评论1 - 122. 买卖股票的最佳时机 II
思路1: 贪心
只要有涨就进行买卖, 最终的利润一定是最大.
所有累加所有自增区间即可.
思路2: 动态规划
1、状态
dp[i][0] = 表示第i天交易完后未持有股票的最大利润
dp[i][1] = 表示第i天交易完后持有一支股票的最大利润
2、 状态转移方程
a) 未持有股票的状态转移方程
dp[i][0] = max{dp[i-1][0], dp[i-1][1] + prices[i]}
解释 :
如果第i天是未持有股票的状态, 那么昨天(即第i-1天)的状态有两种情况
情况1: 昨天也未持有股票, 所以今天的状态不变(即利润不变), 即dp[i-1][0]
情况2: 昨天持有而今天没持有说明今天股票卖掉了, 增加了prices[i]的利润
则今天的状态为: dp[i-1][1] + prices[i]
而要保证今天的利润(状态)最大, 从两种可能状态中选最大的
所以最终状态转移方程如上
b) 持有股票的状态转移方程
dp[i][1] = max{dp[i-1][0] - prices[i], dp[i-1][1]}
解释 :
如果第i天是持有股票的状态, 那么昨天(即第i-1天)的状态有两种情况
情况1: 昨天也持有, 说明今天跟昨天状态不变, 即 dp[i-1][1]
情况2: 昨天未持有而今天持有, 说明买了股票, 则利润减少 prices[i],
即dp[i-1][0] - prices[i]
而要保证今天的利润(状态)最大, 从两种可能状态中选最大的
所以最终状态转移方程如上.
3、边界条件
a) 初始状态
第一天如果是未持有股票,则利润为0:
则状态为: dp[0][0] = 0
第一天如果是持有股票,则利润为:-prices[0]
dp[0][1] = -prices[0]
b) 最终状态
结果所求的利润最大, 即最后一天的状态为未持有股票的状态
既, dp[prices.length-1][0] 状态展开赞过22 - 22.括号生成
思路1: 暴力
暴力生成所有括号组合, 然后再判断该括号组合是否有效.
可以这样暴力生成, 比如结果集合一开始是["(", ")"], 然后遍历结果集合的每个元素分别拼接"(" 和 ")", 于是现在结果集合变成4个 ["((", "()", ")(", "))"], 然后一样遍历结果集合的每个元素分别拼接"(" 和 ")", 然后同上.....
至于判断是否是有效括号, 用一个变量去表示平衡度, 扫一遍括号组合, 遇到"("平衡度+1, 遇到 “)” 平衡度-1, 平衡度为负数要立刻返回false(说明右括号数量此时大于左括号数量), 最后判断平衡度是否是0即可
思路2: 回溯
如图按照该决策树进行回溯即可
减枝条件是 1、当已选择路径中右括号数量大于左括号, 2、第一个选择的符号为右括号.
退出条件是左括号和右括号数量等于n展开赞过评论2