今天又到了熟悉的刷题环节,最近可能是过年🧨有点懒了,好多东西都挤在了一起,好想多几个脑袋瓜和多几双手来帮帮我,哈哈。
最近看到了涉及到括号相关的算法题,就优先做了一些整理我怕一拖就拖没了。那么现在我们就开始进入正题:
20. 有效的括号
可能这道题并不是很难,我之前做会比较慢,可能是没有找到解题的具体思路;后来一直跟着大佬的教程去刷题,慢慢的也在学习解题的相关的思路:
可以从最简单的思路出发, 比如说我只需要去匹配一个 "()"
应该怎么去做呢?
其实就是通过定一个变量left
,有左括号呢,我们就去+1
;遇到右括号了,我们就去-1
; 等到结束后,我们去查看left
是否等于0
。 等于0
就是说左右括号一一进行匹配了,那我们可以来试一试
// 两个()
var isVaild = function(s) {
let left = 0;
for (let i = 0; i < s.length; i++) {
if (s[i] === '(') {
left++;
} else {
left--;
}
// 因为是一一对应的关系
if (left < 0) return false;
}
return left === 0
}
现在,我们来思考一下如果是多种括号的情况下,这种思路是否是可行的呢?
假设的是可行的,我们分别去定义left1, left2,left3, ...leftn,这种方案是否是合适的呢?我们其实可以通过刚才的思路和代码,去想一想利用什么样的数据结构也可以做到同样的效果呢?
我想试试栈
的结构能不能解决问题,依次将左边的括号的进栈, 如果和右边的括号有匹配到的;那么我们就将其出栈
。这样我们就只需要最后看一下栈中是否还有元素来看是否合法。
代码实现:
var isVaild = function(s) {
// 定义栈
let left = [];
for (let i = 0; i< s.length; i++) {
if (s[i] === "(" || s[i] === "[" || s[i] === "{") {
left.push(s[i])
} else {
if (left.length && findTop(s[i]) === left[left.length-1]) {
left.pop();
} else {
return false;
}
}
}
return left.length === 0;
}
findTop(value) {
if (value === '[') return ']';
if (value === '{') return '}';
return ')';
}
921. 使括号有效的最少添加
其实这道题,可以从上面的题解中得到一点思路就是说,(
和)
是需要一一匹配的;那么同样的 一个(
需要一个 )
; 一个右括号呢,也需要一个左括号;我们能做的事情就是如何给它匹配上, 匹配上的个数不就是我们想要的答案嘛。
代码实现:
/**
* @param {string} s
* @return {number}
*/
var minAddToMakeValid = function(s) {
let all_need = 0, right_need = 0;
for (let i = 0; i < s.length; i++) {
// 如果是左括号
if (s[i] === '(') {
// 需要一个右括号
right_need++;
}
// 如果是右括号
if (s[i] === ')' ) {
// 就不需要 右括号了 这里是重要‼️
right_need--;
// 如果每次遍历 right_need都减1
// 我们需要做两件事
if (right_need === -1) {
// 1 重置 right_need
right_need = 0;
// 2. 说明我需要左括号了
left_need++;
}
}
}
return right_need + all_need;
}
其实这道题,我去书写代码的时候,只关注了一个变量right_need
的变化:
首先,最开始的时候如果有遇到(
的时候,我们肯定是需要 )
的;
那么如果我们没有遇到 (
呢?是不是就不需要 )
了呢? 没错是这样的。
比如说 ))
此时我需要并不是左括号,而是右括号。
right_need === -1
的存在就是为了应对上面提到的情况,满足我们对(
的需求。
right_need + all_need
其实就已经很明显了, 需要将各自对于(
和)
的需求进
行计算,并返回最终的结果。
1541. 平衡括号字符串的最少插入次数
具体的实现思路和上面的题目是一致的,只不过需要注意的是两点:
- 一个左括号需要消耗点 2个右括号
- 右括号的数量必须时刻保持为偶数个
代码实现:
/**
* @param {string} s
* @return {number}
*/
var minInsertions = function(s) {
// 核心思路之前的几乎是一样的
// 只不过中间有一些处理的细节需要细细的斟酌一下
let all_need = 0, right_need = 0;
for (let i = 0; i < s.length; i++) {
if (s[i] === "(") {
right_need += 2;
// 如果 right_need 不是偶数呢
if (right_need % 2 === 1) {
// 需要一个右括号
all_need++;
// 一个左括号需要两个右括号, 右括号必须为偶数
right_need -= 1;
}
}
if (s[i] === ")") {
right_need--;
if (right_need === -1) {
// 说明是 ")"多了
// 需要左括号了
all_need++;
// 消耗掉两个 右括号
right_need = right_need + 2;
}
}
}
return all_need + right_need;
}
32. 最长有效括号
这道代码题实现的比较匆忙,可能是中午喝的酒还没有褪去,多少有点迷糊。有不正确的地方希望可以批评指正
代码实现:
/**
* @param {string} s
* @return {number}
*/
var longestValidParentheses = function(s) {
// 使用到了 dp[i] 去存储每次的长度值
let stack = [];
let dp = new Array(s.length+1).fill(0);
for (let i = 0; i < s.length; i++) {
if (s[i] === '(') {
stack.push(i);
// dp[i+1]
dp[i+1] = 0;
} else {
if (stack.length) {
let left_index = stack.pop();
let len = i - left_index + 1 + dp[left_index];
dp[i+1] = len;
} else {
dp[i+1] = 0;
}
}
}
// 结果
let res = 0;
for (let i = 0; i < dp.length; i++) {
res = Math.max(res, dp[i])
}
return res;
}
今天的刷题任务暂时告一段落,我的肚子好像在叫,我去补充点能量了,明天见!!!