持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第26天,点击查看活动详情
题目链接:1422. 分割字符串的最大得分
题目描述
给你一个由若干 0 和 1 组成的字符串 s ,请你计算并返回将该字符串分割成两个 非空 子字符串(即 左 子字符串和 右 子字符串)所能获得的最大得分。
「分割字符串的得分」为 左 子字符串中 0 的数量加上 右 子字符串中 1 的数量。
提示:
- 字符串
s仅由字符'0'和'1'组成。
示例 1:
输入:s = "011101"
输出:5
解释:
将字符串 s 划分为两个非空子字符串的可行方案有:
左子字符串 = "0" 且 右子字符串 = "11101",得分 = 1 + 4 = 5
左子字符串 = "01" 且 右子字符串 = "1101",得分 = 1 + 3 = 4
左子字符串 = "011" 且 右子字符串 = "101",得分 = 1 + 2 = 3
左子字符串 = "0111" 且 右子字符串 = "01",得分 = 1 + 1 = 2
左子字符串 = "01110" 且 右子字符串 = "1",得分 = 2 + 1 = 3
示例 2:
输入: s = "00111"
输出: 5
解释: 当 左子字符串 = "00" 且 右子字符串 = "111" 时,我们得到最大得分 = 2 + 3 = 5
示例 3:
输入: s = "1111"
输出: 3
整理题意
题目给定一个字符串 s,仅包含字符 0 和 1,让我们将字符串分为两段,保证两段字符串不为空,且是连续的两段,也就是将字符串一分为二,然后需要使得左边的字符串中字符 0 的个数加上右边字符串中字符 1 的个数总和最大。
解题思路分析
这种分割题目,我们要想到 枚举 分割点的方法,由于题目要求两段字符串不为空,那么分割点不能是一头一尾,因为切分后的字符串至少包含一个字符。
考虑完枚举分割点后我们来考虑如何快速计算左边字符串中 0 的个数和右边字符串中 1 的个数:由于字符串中仅包含字符 0 和 1,那么我们仅需统计其中一个字符的个数,然后用总的数量减去即可得到另一个字符的个数。
具体实现
- 首先统计字符串中字符
1的总个数sum1; - 然后从左到右枚举分割点,在遍历的同时记录前缀中字符
1的个数pre1; - 那么我们可以通过当前位置和前缀中字符
1的个数计算出左边字符串中字符0的个数; - 在通过字符串中
1的总个数sum1和前缀中字符1的个数,计算得到右边字符串中字符1的个数; - 那么我们仅需在枚举过程中维护
sum1 - pre1 + (i - pre1 + 1)的最大值即可。
复杂度分析
- 时间复杂度:,其中
n是字符串s的长度。需要遍历字符串两次。 - 空间复杂度:,仅需常数空间。
代码实现
class Solution {
public:
int maxScore(string s) {
// 统计字符 '1' 的总数量
int sum1 = 0;
for(char &c : s) if(c == '1') sum1++;
// ans 记录最大得分,pre1 前缀字符 '1' 的数量
int ans = 0, pre1 = 0;
int n = s.length();
// 枚举分割位置,因为非空,所以到 n - 2
for(int i = 0; i < n - 1; i++){
if(s[i] == '1') pre1++;
// 利用前缀字符 '1' 的数量和总的字符 '1' 的数量以及 i 来计算当前得分
ans = max(ans, sum1 - pre1 + (i - pre1 + 1));
}
return ans;
}
};
总结
- 该题的核心思想在于 枚举分割点,其次在于利用字符总个数和前缀字符个数进行数学计算答案即可。
- 测试结果:
结束语
生活中许多事情看似无法做到,其实是因为我们被自己的预判吓倒。真正让我们为难的不是事物本身,而是我们那颗尚未开始就已经退缩的心。把大目标分解为小任务,一步步去完成,只要你用心浇灌,梦想自会开花结果。新的一天,加油!