一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第6天,点击查看活动详情。
大厂高频算法面试题:《括号问题系列》,通过括号问题四连击,您将学到通过有限变量解法,如何定义动态规划含义。
一、括号问题I
括号有效配对是指:
1)任何一个左括号都能找到和其正确配对的右括号
2)任何一个右括号都能找到和其正确配对的左括号
有效的: (()) ()() (()()) 等
无效的: (() )( 等
怎么判断一个括号字符串有效?
1、分析
只需要一个变量即可搞定,有效括号配对问题,遇到左括号,count++,遇到右括号,count--,如果count小于0,说明右括号比左括号多,后续不用看了,直接返回false,如果遍历结束,count == 0,说明是有效,否则无效
2、实现
public static boolean valid(String s) {
if (s == null || s.length() == 0) {
return false;
}
char[] str = s.toCharArray();
int count = 0;
for (int i = 0; i < str.length; i++) {
count += str[i] == '(' ? 1 : -1;
if (count < 0) {
return false;
}
}
return count == 0;
}
复制代码
二、括号问题II
括号有效配对是指:
1)任何一个左括号都能找到和其正确配对的右括号
2)任何一个右括号都能找到和其正确配对的左括号
有效的: (()) ()() (()()) 等
无效的: (() )( 等
如果一个括号字符串无效,返回至少填几个字符能让其整体有效
1、分析
只需要两个变量即可搞定,count(含义跟括号问题I一样),need,如果count == -1,说明右括号比左括号多一个,此时need++,count恢复到0,count = 0,如果遍历完毕后,发现count>0,说明左括号比右括号大,需要补偿count次右括号,所以至少需要添加need + count,如果count == 0,则至少需要添加need
2、实现
public static int needParentheses(String s) {
if (s == null || s.length() == 0) {
return 0;
}
char[] str = s.toCharArray();
int count = 0;
int need = 0;
for (int i = 0; i < str.length; i++) {
if (str[i] == '(') {
count++;
} else { // 遇到的是')'
if (count == 0) {
need++;
} else {
count--;
}
}
}
return count + need;
}
复制代码
三、括号问题III
括号有效配对是指:
1)任何一个左括号都能找到和其正确配对的右括号
2)任何一个右括号都能找到和其正确配对的左括号
返回一个有效括号字符串中,最大嵌套层数
比如:(()()) 返回2层,(()(())) 返回3层,()(()) 返回2层
1、分析
遇到左括号count++,遇到右括号count--,count最大值就是嵌套了几层
2、实现
// 校验是否是合法有效括号
public static boolean isValid(char[] str) {
if (str == null || str.length == 0) {
return false;
}
int status = 0;
for (int i = 0; i < str.length; i++) {
if (str[i] != ')' && str[i] != '(') {
return false;
}
if (str[i] == ')' && --status < 0) {
return false;
}
if (str[i] == '(') {
status++;
}
}
return status == 0;
}
public static int deep(String s) {
char[] str = s.toCharArray();
if (!isValid(str)) {
return 0;
}
int count = 0;
int max = 0;
for (int i = 0; i < str.length; i++) {
if (str[i] == '(') {
max = Math.max(max, ++count);
} else {
count--;
}
}
return max;
}
复制代码
四、括号问题IV
括号有效配对是指:
1)任何一个左括号都能找到和其正确配对的右括号
2)任何一个右括号都能找到和其正确配对的左括号
返回一个括号字符串中,最长的括号有效子串的长度
1、分析
子串一定是连续的
以什么什么结尾入手
dp[i]
含义:arr[0...i]中以i结尾的最长有效括号子串长度是多少,潜台词:如果i遇到左括号,则dp[i]
等于0,因为不可能有效括号以左括号结尾,违背dp[i]
定义的含义
如果当前来到i位置是右括号,i-1位置的dp值为4,说明dp[i-1]
往前推,能推动4个合法的括号,那么i-5位置上如果是左括号,那么至少dp[i]
= 5,如果i-5位置上是右括号,那么dp[i]
= 0,就算左边还有遇到左括号能匹配上,也是0,因为dp[i]
的含义就是能匹配的有效括号子串最长长度,dp[i-1]
已经记录了最长的括号有效子串的长度,前边就算有左括号匹配,也是dp[i-1]
算好的值
- i位置是右括号,如果
dp[i-1]
的前一位是右括号,则dp[i]
= 0 - i位置是右括号,如果
dp[i-1]
的前一位是左括号,则dp[i] 至少是 dp[i-1] + 2,此时需要再往前看一位,有可能扩大
2、实现
public static int maxLength(String s) {
if (s == null || s.length() < 2) {
return 0;
}
char[] str = s.toCharArray();
int[] dp = new int[str.length];
int pre = 0;
int ans = 0;
// dp[0] = 0;
for (int i = 1; i < str.length; i++) {
if (str[i] == ')') {
pre = i - dp[i - 1] - 1; // 与str[i]配对的左括号的位置 pre
if (pre >= 0 && str[pre] == '(') {
dp[i] = dp[i - 1] + 2 + (pre > 0 ? dp[pre - 1] : 0);
}
}
ans = Math.max(ans, dp[i]);
}
return ans;
}
复制代码