【力扣LeetCode】 1422_分割字符串的最大得分
- 第 131 篇 -
Date: 2025 - 09 - 23
Author: 郑龙浩(仟墨)
文章目录
- 【力扣LeetCode】 1422_分割字符串的最大得分
- 题目描述
- 思路
- **解题思路:前缀和算法**
- **1. 前缀和数组计算**
- **2. 计算最大得分**
- **3. 我犯的错**
- 代码
【力扣LeetCode】 1422_分割字符串的最大得分
题目描述
给你一个由若干 0 和 1 组成的字符串 s ,请你计算并返回将该字符串分割成两个 非空 子字符串(即 左 子字符串和 右 子字符串)所能获得的最大得分。
「分割字符串的得分」为左子字符串中 0 的数量加上右子字符串中 1 的数量。
思路
- 前缀和优化:避免每次分割都重新计算0和1的数量。
- 遍历所有分割点:确保找到最优解。
- 边界条件处理:特别是
i = len-1
的情况。
解题思路:前缀和算法
这道题要求我们找到一个分割点,使得左子串的0的数量 + 右子串的1的数量最大。我的思路是使用前缀和来优化计算,避免每次分割都重新遍历整个字符串。
1. 前缀和数组计算
sum0[i]
:表示字符串s[0...i]
中 0 的累计数量。sum1[i]
:表示字符串s[0...i]
中 1 的累计数量。
初始化:
- 如果
s[0] == '0'
,则sum0[0] = 1
,sum1[0] = 0
。 - 如果
s[0] == '1'
,则sum0[0] = 0
,sum1[0] = 1
。
递推计算:
- 遍历字符串
s
,从i = 1
开始:- 如果
s[i] == '0'
,则sum0[i] = sum0[i-1] + 1
,sum1[i] = sum1[i-1]
。 - 如果
s[i] == '1'
,则sum1[i] = sum1[i-1] + 1
,sum0[i] = sum0[i-1]
。
- 如果
这样,我们就能在 O(n) 的时间内计算出所有位置的前缀和。
2. 计算最大得分
我们需要遍历所有可能的分割点 i
(即左子串的最后一个字符的位置),计算:
- 左子串的0的数量 =
sum0[i-1]
- 右子串的1的数量 =
sum1[len-1] - sum1[i-1]
- 当前得分 =
sum0[i-1] + (sum1[len-1] - sum1[i-1])
然后,我们记录所有得分中的最大值。
边界情况:
i = 1
时,左子串是s[0]
,右子串是s[1...len-1]
。i = len-1
时,左子串是s[0...len-2]
,右子串是s[len-1]
。
3. 我犯的错
- 初始版本:我一开始忘了处理
i = len-1
的情况,导致某些测试用例出错。后来修正了。 - 最终版本:遍历
i
从1
到len-1
,确保所有可能的分割点都被覆盖。
代码
// 1422_分割字符串的最大得分
// Author: 郑龙浩 Date: 2025年09月21日
// 用时:23min --> 改错后29min
// 思路:明显的前缀和算法
// 我可以写两个前缀和数组,分别存储0的数量和1的数量,也就是左字符串的分数和右字符串的分数
// 然后计算出前缀和以后
// 依次对原数组进行拆分,左半边数组计算0的数量,右半边数组计算1的数量,加起来的数量即得分
// 然后每次将最大的数量(得分)存下来,最后就得除了最大的得分
#include "bits/stdc++.h"
using namespace std;class Solution {
public:int maxScore(string s) {int len = s.length(); vector <int> sum0(len), sum1(len); // 计算0的数量,计算1的数量// 计算前缀和// 计算第一位的前缀和// 若第一位是0,则sum0就+1,如果第一位是1,就sum1+1if (s[0] == '1') {sum0[0] = 0; sum1[0] = 1;} else if (s[0] == '0') {sum0[0] = 1; sum1[0] = 0;}for (int i = 1; i < len; i++) {if (s[i] == '1') { // 如果是1,就计算nums1的前缀和sum0[i] = sum0[i - 1]; sum1[i] = sum1[i - 1] + 1;} else if (s[i] == '0') { // 若是0,就计算nums0的前缀和sum0[i] = sum0[i - 1] + 1; sum1[i] = sum1[i - 1];}}// 计算从什么地方分割才能得出最大得分// i = 1是避免出现拆分成,左字符串无,右字符串是整个原字符串的清况// i 表示的是拆分的右侧字符串的第一个字符的位置,或也可以叫:左字符串最后一个字符的后边的位置int max = 0;int grade; // 存储每个方案的得分for (int i = 1; i < len; i++) { // // 刚开始忘了右边界的情况,现在补上// if (i == len - 1) grade = sum0[i] + (sum1[len - 1] - sum1[i - 1]); grade = sum0[i - 1] + (sum1[len - 1] - sum1[i - 1]);if (grade > max) max = grade;}return max;}
};
int main(void) {ios::sync_with_stdio(0);cin.tie(0); cout.tie(0);// string S = "011101";// string S = "00111";string S = "1111";Solution sol;cout << sol.maxScore(S);return 0;
}