加载中...
1221-分割平衡字符串(Split a String in Balanced Strings)
发表于:2021-12-03 | 分类: 简单
字数统计: 1.9k | 阅读时长: 7分钟 | 阅读量:

原文链接: https://leetcode-cn.com/problems/split-a-string-in-balanced-strings

英文原文

Balanced strings are those that have an equal quantity of 'L' and 'R' characters.

Given a balanced string s, split it in the maximum amount of balanced strings.

Return the maximum amount of split balanced strings.

 

Example 1:

Input: s = "RLRRLLRLRL"
Output: 4
Explanation: s can be split into "RL", "RRLL", "RL", "RL", each substring contains same number of 'L' and 'R'.

Example 2:

Input: s = "RLLLLRRRLR"
Output: 3
Explanation: s can be split into "RL", "LLLRRR", "LR", each substring contains same number of 'L' and 'R'.

Example 3:

Input: s = "LLLLRRRR"
Output: 1
Explanation: s can be split into "LLLLRRRR".

Example 4:

Input: s = "RLRRRLLRLL"
Output: 2
Explanation: s can be split into "RL", "RRRLLRLL", since each substring contains an equal number of 'L' and 'R'

 

Constraints:

  • 1 <= s.length <= 1000
  • s[i] is either 'L' or 'R'.
  • s is a balanced string.

中文题目

在一个 平衡字符串 中,'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' 。

 

提示:

  • 1 <= s.length <= 1000
  • s[i] = 'L' 或 'R'
  • s 是一个 平衡 字符串

通过代码

高赞题解

基本分析

题目确保了 s 为一个平衡字符串,即可以分割成若干个 LR 子串。

一个合法的 LR 子串满足 L 字符和 R 字符数量相等,常规检查一个字符串是否为合格的 LR 子串可以使用 $O(n)$ 的遍历方式,可以使用记录前缀信息的数据结构,而对于成对结构的元素统计,更好的方式是转换为数学判定,使用 1 来代指 L 得分,使用 -1 来代指 R 得分。

那么一个子串为合格 LR 子串的充要条件为 **整个 LR 子串的总得分为 $0$**。

这种方式最早应该在 (题解) 301. 删除无效的括号 详细讲过,可延伸到任意的成对结构元素统计题目里去。


贪心

回到本题,题目要求分割的 LR 子串尽可能多,直观上应该是尽可能让每个分割串尽可能短。

我们使用「归纳法」来证明该猜想的正确性。

首先题目数据保证给定的 s 本身是合法的 LR 子串,假设从 $[0…a]$ 可以从 s 中分割出 长度最小LR 子串,而从 $[0…b]$ 能够分割出 长度更大LR 子串(即 a <= b )。

image.png

我们来证明起始时(第一次分割)将「从 b 分割点将 s 断开」调整为「从 a 分割点将 s 断开」结果不会变差:

  1. b 点首次分割调整为从 a 点首次分割,两种分割形式分割点两端仍为合法 LR 子串,因此不会从“有解”变成“无解”;

  2. b 分割后的剩余部分长度小于从 a 分割后的剩余部分,同时由 b 分割后的剩余部分会被由 a 分割后的剩余部分所严格覆盖,因此「对 a 分割的剩余部分再分割所得的子串数量」至少 与「从 b 点分割的剩余部分再分割所得的子串数量」相等(不会变少)。

image.png

至此,我们证明了对于首次分割,将任意合格分割点调整为最小分割点,结果不会变得更差(当 a < b 时还会更好)。

同时,由于首次分割后的剩余部分仍为合格的 LR 子串,因此归纳分析所依赖的结构没有发生改变,可以将上述的推理分析推广到每一个决策的回合(新边界)中。

至此,我们证明了只要每一次都从最小分割点进行分割,就可以得到最优解。

代码:

[]
class Solution { public int balancedStringSplit(String s) { char[] cs = s.toCharArray(); int n = cs.length; int ans = 0; for (int i = 0; i < n; ) { int j = i + 1, score = cs[i] == 'L' ? 1 : -1; while (j < n && score != 0) score += cs[j++] == 'L' ? 1 : -1; i = j; ans++; } return ans; } }
  • 时间复杂度:$O(n)$
  • 空间复杂度:调用 toCharArray 会拷贝新数组进行返回(为遵循 String 的不可变原则),因此使用 toCharArray 复杂度为 $O(n)$,使用 charAt 复杂度为 $O(1)$

其他「相信科学系列(贪心)」相关内容

不然发现,「贪心题」虽然大多数代码简单,但难度通常为「中等 / 困难」。

因为「贪心题」重点在于证明(特别在面试环节),只 AC 不证明的最大弊端在于:简单的条件修改后,选手根本无法回答原做法是否还是正确。

因此「AC 并证明」才是正确的、科学的做「贪心题」的态度,而不是因为「不会证明 / 看不懂证明」而选择放弃证明,甚至对证明嗤之以鼻。

对于贪心题证明,大多数人可能会经历如下几个阶段:

「没意识到需要证明」->「意识到需要证明,但不会并看不懂证明」->「看得懂证明,但是证明不出来」->「能自己给出证明」

其中第一步到第二步的距离,比最后两步距离加起来还要远。

我猜这才是大多数人不谈「证明」的理由(ta 没走出第一步),而非「证明」不重要。

题目 题解 难度 推荐指数
11. 盛最多水的容器 LeetCode 题解链接 中等 🤩🤩🤩🤩🤩
45. 跳跃游戏 II LeetCode 题解链接 中等 🤩🤩🤩🤩
179. 最大数 LeetCode 题解链接 中等 🤩🤩🤩🤩
561. 数组拆分 I LeetCode 题解链接 简单 🤩🤩🤩🤩
765. 情侣牵手 LeetCode 题解链接 困难 🤩🤩🤩
781. 森林中的兔子 LeetCode 题解链接 中等 🤩🤩🤩🤩
881. 救生艇 LeetCode 题解链接 中等 🤩🤩🤩🤩
995. K 连续位的最小翻转次数 LeetCode 题解链接 困难 🤩🤩🤩
1221. 分割平衡字符串 LeetCode 题解链接 简单 🤩🤩🤩🤩
1707. 与数组中元素的最大异或值 LeetCode 题解链接 困难 🤩🤩🤩
1713. 得到子序列的最少操作次数 LeetCode 题解链接 困难 🤩🤩🤩🤩🤩
1833. 雪糕的最大数量 LeetCode 题解链接 中等 🤩🤩🤩🤩🤩
1846. 减小和重新排列数组后的最大元素 LeetCode 题解链接 中等 🤩🤩🤩🤩🤩
1877. 数组中最大数对和的最小值 LeetCode 题解链接 中等 🤩🤩🤩🤩🤩

注:以上目录整理来自 wiki,任何形式的转载引用请保留出处。


最后

如果有帮助到你,请给题解点个赞和收藏,让更多的人看到 ~ (“▔□▔)/

统计信息

通过次数 提交次数 AC比率
77974 92391 84.4%

提交历史

提交时间 提交结果 执行时间 内存消耗 语言
上一篇:
1226-哲学家进餐(The Dining Philosophers)
下一篇:
1222-可以攻击国王的皇后(Queens That Can Attack the King)
本文目录
本文目录