LeetCode --- 字符串系列 --- 分割平衡字符串
分割平衡字符串
题目
在一个「平衡字符串」中,'L' 和 'R' 字符的数量是相同的。
给出一个平衡字符串 s,请你将它分割成尽可能多的平衡字符串。
返回可以通过分割得到的平衡字符串的最大数量。
示例
示例 1:
输入:s = "RLRRLLRLRL"
输出:4
解释:s 可以分割为 "RL", "RRLL", "RL", "RL", 每个子字符串中都包含相同数量的 'L' 和 'R'。
示例 2:
输入:s = "RLLLLRRRLR"
输出:3
解释:s 可以分割为 "RL", "LLLRRR", "LR", 每个子字符串中都包含相同数量的 'L' 和 'R'。
示例 3:
输入:s = "LLLLRRRR"
输出:1
解释:s 只能保持原样 "LLLLRRRR".
示例 4:
输入:s = "RLRRRLLRLL"
输出:2
解释:s 可以分割为 "RL", "RRRLLRLL", 每个子字符串中都包含相同数量的 'L' 和 'R'。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/split-a-string-in-balanced-strings/
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
解题思路
单看上面前三个例子,很容易让人理解错题意
所以我加上了第四个例子
主要在于对字符串的动作是分割
,而不是切割
处理字符串过程不能舍弃字符串
分割
不舍弃字符串,切割
会舍弃字符串
本题的题意是分割
。所以难度是简单
平民思路:
1、
定义两个对象 A,B。用来存储 R 和 L 当前的字符计数
A = { R: 0, L: 0 }
B = { R: 0, L: 0 }
2、
循环 `平衡字符串` ,判断第一个字符是 R 或者 L,则 A 里面的 R 或 L 属性计数加 1
3、
计算 A 对象中 R 和 L 的 `计数总和 alen`,用该 `计数总和 alen` 截取 `平衡字符串` ,得到用来做对比的字符串 BChar
例如 A 中,占据 `平衡字符串` 前两位,则需要第三和第四位与前两位做对比
即 BChar = string.slice(alen, alen * 2)
4、
循环 Bchar,判断第一个字符是 R 或者 L,则 B 里面的 R 或 L 属性计数加 1
5、
此时判断是否满足 `平衡字符串` 条件
A 里面的 R 计数等于 B 里面的 L 计数: A['R'] === B['L']
并且
A 里面的 L 计数等于 B 里面的 R 计数: A['L'] === B['R']
6、
6、1
若满足平衡条件,则
count 加 1
且 A 重置为 A = { R: 0, L: 0 }
字符串截取掉对比过的字符串 A + B
重置 B 为 B = { R: 0, L: 0 }
循环变量 index 设置为 -1,方便下次循环 index++ 时设置为 0
继续循环
6、2
若不满足,则重置 B 为 B = { R: 0, L: 0 }
继续循环
或者
力扣他人题解
1、
思考 `平衡字符串` 特性,需要一个 `分割子串` 中的 R 和 L 是相等的
使用 `出栈入栈` 的方式可以简单明了的解决这个问题
2、
遍历 `平衡字符串` ,判断第一个字符串是否是 L
若是,则入栈, stack++,加 1
若不是,则出栈,stack--,减 1
3、
这样,如果遍历的前两个字符不一样, stack 加 1,而后又减 1,此时 stack 等于 0
满足 `平衡字符串` 的条件,那么 count++ 加 1
题解
此方法是解题常规思路,算是平民解法
所以性能并不是很好,还有点啰嗦
下面给出了力扣题解中比较好的一种解法
let balancedStringSplit = function(s) {
let count = 0
let string = s
let A = {}, B = {}
for (let i = 0; i < string.length; i++) {
// 判断字符是 R 或者 L,则 A 里面的 R 或 L 属性计数加 1
if (!A[string[i]]) {
A[string[i]] = 1
} else {
A[string[i]]++
}
// 计算 A 对象中 R 和 L 的计数总和 alen
let alen = 0
Object.keys(A).forEach(key => {
alen += A[key]
})
// 用该总和长度 alen 截取 平衡字符串,得到 用来做对比的字符串 BChar
// 例如 A 中,占据 平衡字符串前两位,则需要第三和第四位与前两位做对比
let BChar = string.slice(alen, alen * 2)
// 循环 Bchar,判断字符是 R 或者 L,则 B 里面的 R 或 L 属性计数加 1
for (let c of BChar) {
if (!B[c]) {
B[c] = 1
} else {
B[c]++
}
}
// 判断是否满足平衡字符串条件
if (A['R'] === B['L'] && A['L'] === B['R']) {
count++
i = -1 // 让 i 从 0 开始,这里为 -1,经过循环 + 1 就变成 0 了
A = {}
// 字符串截取掉对比过的字符串 A + B
string = string.slice(alen * 2)
}
B = {} // 每次都要重置
}
return count
};
或者
力扣他人题解
let balancedStringSplit = function(s) {
let count = 0
let stack = 0
for (let i = 0, len = s.length; i < len; i++ ){
// 遍历 `平衡字符串` ,判断第一个字符串是否是 L
// 若是,则入栈, stack++,加 1
// 若不是,则出栈,stack--,减 1
if(s[i] === 'L') {
stack++
} else {
stack--
}
// stack 等于 0, 满足 `平衡字符串` 的条件,那么 count++ 加 1
if (stack === 0) {
count++
}
}
return count
};
备注
如果没有第四个示例,可能造成误解题意。理解为切割字符串,找出平衡子串
并且该平衡子串还是必须是 对称互斥子串。 例如 LLLRRR RL LRLR LLRLRLRR
一开始我理解的就是这样,难得当初写了 N 久,这里也一并贴上算法吧。
但是用的是暴力遍历计算,本来应该要用马拉车算法吧。但是我还没学。先这样吧
思路
1、
创建数组 A
循环 字符串 string
string[i] push 进 A 中
渐进思路 1
1、
判断 A 的长度如果等于 2
1、1
继续判断 A 的两个元素是否不一样
如果不一样,则将这两个元素从 chars 切割出去, T 存储这两个元素
如果一样,继续循环
2、
判断 A 的长度如果大于 2
2、1
继续判断 A 的长度是否是 2 的倍数
如果是,对 A 进行对半切割
然后 [0].join('') 和 [1].reverse().join('') 遍历对比是否全不相等
如果全不相等,则将这些元素从 chars 切割出去, count++, 外层循环的 index 重置为 内层循环的位置数值,等待下一个外循环 + 1,继续循环
如果不是,继续循环
最后,返回 T
渐进思路 2
1、
判断 A 的长度是否是 2 的倍数
1、1
如果是,对 A 进行对半切割
然后 [0].join('') 和 [1].reverse().join('') 遍历对比是否全不相等
若全不相等,则将这些元素从 chars 切割出去, count++, 外层循环的 index 重置为 内层循环的位置数值,等待下一个外循环 + 1,继续循环
如果不是,继续循环
最后,返回 T
解法
let balancedStringSplit = function(s) {
let A = [], count = 0
let string = s
for (let i = 0; i < string.length; i++) {
A = []
A.push(string[i])
for (let k = i + 1; k < string.length; k++) {
A.push(string[k])
let alen = A.length
// 判断 A 的长度是否是 2 的倍数
if (A.length % 2 === 0) {
let judge = true
let arr = A.slice(0, alen / 2)
let brr = A.slice(alen / 2).reverse()
// [0].join('') 和 [1].reverse().join('') 遍历对比是否全不相等
for (let n = 0; n < arr.length; n++) {
if (arr[n] === brr[n]) {
judge = false
break;
}
}
// 若全不相等,则将这些元素从 chars 切割出去, count++,
// 外层循环的 i 重置为 内层循环的位置数值
// 等待下一个外循环 + 1,继续循环
if (judge) {
i = k
// string = string.slice(k + 1)
// i = -1
count++
A = []
break;
}
}
}
}
return count
};
都读到最后了、留下个建议如何