1. 有效的括号
方法一:栈
给定一个只包括 ‘(’,’)’,’{’,’}’,’[’,’]’ 的字符串 s ,判断字符串是否有效。
有效字符串需满足:
左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。
class Solution:
def isValid(self, s: str) -> bool:
if len(s) % 2 != 0:
return False
pairs = {
')': '(',
']': '[',
'}': '{'
}
stack = []
for char in s:
if char in pairs:
if not stack or stack[-1] != pairs[char]:
return False
stack.pop()
else:
stack.append(char)
return not stack
2. 最长有效括号
方法一:栈
给你一个只包含 ‘(’ 和 ‘)’ 的字符串,找出最长有效(格式正确且连续)括号子串的长度。
有效定义为:
()
()()
(()())
视频中的方法三:https://leetcode-cn.com/problems/longest-valid-parentheses/solution/zui-chang-you-xiao-gua-hao-by-leetcode-solution/
大约从11分钟开始
class Solution:
def longestValidParentheses(self, s: str) -> int:
if not s: return 0
stack = []
ans = 0
for i in range(len(s)):
# 入栈条件
if not stack or s[i] == '(' or s[stack[-1]] == ')':
stack.append(i) # 下标入栈
else:
# 计算结果
stack.pop()
ans = max(ans, i - (stack[-1] if stack else -1))
return ans
方法二:动态规划
时间复杂度O(n),空间复杂度O(n)
1)解题思路:
动态规划,dp[i]表示以索引i为结尾的最长有效括号字串的长度。
如果s[i] == ‘(’,则以i结尾的字符串不可能是有效括号,dp[i] = 0。
如果s[i] == ‘)’,有以下情况:
s[i-1] == ‘(’,则dp[i] = dp[i-2] + 2
s[i-1] == ‘)’,则dp[i] = dp[i-1] + 2 + dp[i - dp[i-1] - 2]
2)详细解释:
-
dp数组意义:dp[i] 表示以下标 ii 字符结尾的最长有效括号的长度
-
状态转移:
如果s[i] == ‘(’,则以i结尾的字符串不可能是有效括号,dp[i] = 0。
1)字符串形如 “……()”,如果第i-1号和第i号是左括号和右括号:
因为结束部分的 “()” 是一个有效子字符串,并且将之前有效子字符串的长度增加了 2 。
2)字符串形如 “……))”,如果第i号和第i-1号都是右括号“)”:
dp[i-1]是一些有效括号的长度,因此和i搭配成新的有效括号组合的是i-dp[i-1]-1,所以+2,在i-dp[i-1]-1之前可能还有有效括号长度,所以加dp[i-dp[i-1]-2].
3)代码
class Solution:
def longestValidParentheses(self, s: str) -> int:
if not s:
return 0
dp = [0] * len(s)
for i in range(1, len(s)):
if s[i] == ')':
if s[i-1] == '(':
dp[i] = (dp[i-2] if i >= 2 else 0) + 2
else:
if i - dp[i-1] - 1 >= 0 and s[i - dp[i-1] - 1] == '(':
dp[i] = dp[i-1] + 2 + (dp[i - dp[i-1] - 2] if i - dp[i-1] - 2 >= 0 else 0)
return max(dp)
public class Solution {
public int longestValidParentheses(String s) {
int maxans = 0;
int[] dp = new int[s.length()];
for (int i = 1; i < s.length(); i++) {
if (s.charAt(i) == ')') {
if (s.charAt(i - 1) == '(') {
dp[i] = (i >= 2 ? dp[i - 2] : 0) + 2;
} else if (i - dp[i - 1] >= 1 && s.charAt(i - dp[i - 1] - 1) == '(') {
dp[i] = dp[i - 1] + ((i - dp[i - 1]) >= 2 ? dp[i - dp[i - 1] - 2] : 0) + 2;
}
maxans = Math.max(maxans, dp[i]);
}
}
return maxans;
}
}
对应思考1:
s.charAt(i - dp[i - 1] - 1) == '('
对应思考2:
i - dp[i - 1] >= 1 # i - dp[i - 1]-1不能 == -1,这样就越界了,找到的是数组倒数第一个元素是否是“(”,滥竽充数了
对应思考3:
如果i - dp[i-1] - 2 == -1, python中会去找数组倒数第一个元素dp[i - dp[i - 1] - 2] = dp[-1], dp[-1]最后一个更新所以在计算前面的dp[i]时,可以用dp[-1],不影响正确答案;但java不行,负数下标会报错。c不会报错,但会指向第0个元素的地址 - 1,这个地址存储的数字不确定是啥。因此要写成:
((i - dp[i - 1]) >= 2 ? dp[i - dp[i - 1] - 2] : 0)
方法三:正向逆向结合法
n:字符串长度
left:左括号个数
right:右括号个数
maxlength:有效括号子串最大长度
class Solution:
def longestValidParentheses(self, s: str) -> int:
n, left, right, maxlength = len(s), 0, 0, 0
for i in range(n):
if s[i] =='(':
left+=1
else:
right+=1
if left == right:
maxlength = max(maxlength, 2 * right)
elif right > left:
left = right = 0
left = right = 0
for i in range(n-1,-1,-1):
if s[i] =='(':
left+=1
else:
right+=1
if left == right:
maxlength = max(maxlength, 2 * left)
elif right < left:
left = right = 0
return maxlength
3. 最大乘积子数组
方法一:DP
https://leetcode-cn.com/problems/maximum-product-subarray/solution/xiang-xi-tong-su-de-si-lu-fen-xi-duo-jie-fa-by–36/
我们先定义一个数组 dpMax,用 dpMax[i] 表示以第 i 个元素的结尾的子数组,乘积最大的值,也就是这个数组必须包含第 i 个元素。
那么 dpMax[i] 的话有几种取值:
如果A[i]为0,那么maxDP和minDP都为0,我们需要从A[i + 1]重新开始。
public int maxProduct(int[] nums) {
int n = nums.length;
if (n == 0) {
return 0;
} else if (n == 1) {
return nums[0];
}
int dpMax = nums[0];
int dpMin = nums[0];
int max = nums[0];
for (int i = 1; i < n; i++) {
//更新 dpMin 的时候需要 dpMax 之前的信息,所以先保存起来
int preMax = dpMax;
dpMax = Math.max(dpMin * nums[i], Math.max(dpMax * nums[i], nums[i]));
dpMin = Math.min(dpMin * nums[i], Math.min(preMax * nums[i], nums[i]));
max = Math.max(max, dpMax);
}
return max;
}
方法二:正向逆向结合法
https://leetcode-cn.com/problems/maximum-product-subarray/solution/python5xing-bu-tong-yu-hui-su-dpde-tricksjie-fa-by/
class Solution:
def maxProduct(self, nums: List[int]) -> int:
nums_reverse = nums[::-1]
for i in range(1, len(nums)):
nums[i] *= nums[i - 1] or 1 # or 1的作用是,当nums[i - 1]==0时,nums[i]乘等自身
nums_reverse[i] *= nums_reverse[i - 1] or 1
return max(max(nums),max(nums_reverse))