#P3289. 第1题-园游会
-
1000ms
Tried: 319
Accepted: 137
Difficulty: 4
所属公司 :
华为
时间 :2025年6月11日-暑期实习(留学生)
-
算法标签>贪心算法
第1题-园游会
题解思路与方法
算法核心
本题等价于经典的 “Partition Labels” 问题。
核心贪心思路:对于每个字符,预先记录其在字符串中最后一次出现的位置;然后从左到右扫描,维护当前分片的区间端点 end。遇到字符 c 时,将 end 更新为 max(end, last[c])。若扫描位置 i 正好等于 end,则可在此处分割一个片段。
实现步骤
-
预处理:扫描字符串,记录每个字符的最后出现下标
last[c]。 -
分片扫描:初始化
start = 0, end = 0;遍历索引i:- 更新
end = max(end, last[s[i]]); - 若
i == end,则当前片段完成,长度为i - start + 1,将其加入结果,并令start = i + 1。
- 更新
-
返回结果列表。
复杂度分析
-
时间复杂度:
- 预处理最后出现位置需 O(n),扫描分片再次 O(n),总体 O(n)。
-
空间复杂度:
- 需额外数组/哈希表记录最后出现位置,最多 O(1)(字符集固定为 26 个),结果列表占 O(k),其中 k≤n。
代码实现
Python 实现
def partition_balloon(s):
# 记录每个字符最后出现的位置
last = {c: i for i, c in enumerate(s)}
res = []
start = end = 0
for i, ch in enumerate(s):
# 更新当前分片最远端点
end = max(end, last[ch])
if i == end:
# 分片完成,记录长度
res.append(i - start + 1)
start = i + 1
return res
if __name__ == "__main__":
import sys
# 读取输入字符串
s = sys.stdin.readline().strip()
# 获取分组结果
res = partition_balloon(s)
# 按要求格式输出列表
print(res)
Java 实现
import java.util.*;
public class Solution {
// 分组函数
public static List<Integer> partitionBalloon(String s) {
int n = s.length();
int[] last = new int[26];
// 记录每个字符最后出现的位置
for (int i = 0; i < n; i++) {
last[s.charAt(i) - 'a'] = i;
}
List<Integer> res = new ArrayList<>();
int start = 0, end = 0;
for (int i = 0; i < n; i++) {
end = Math.max(end, last[s.charAt(i) - 'a']);
if (i == end) {
res.add(i - start + 1);
start = i + 1;
}
}
return res;
}
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
// 读取输入字符串
String s = in.nextLine().trim();
in.close();
// 获取分组结果
List<Integer> res = partitionBalloon(s);
// 按要求格式输出列表
System.out.print("[");
for (int i = 0; i < res.size(); i++) {
System.out.print(res.get(i));
if (i != res.size() - 1) {
System.out.print(", ");
}
}
System.out.println("]");
}
}
C++ 实现
#include <iostream>
#include <vector>
#include <string>
using namespace std;
// 分组函数
vector<int> partitionBalloon(const string &s) {
int n = s.size();
vector<int> last(26, 0);
// 记录每个字符最后出现的位置
for (int i = 0; i < n; ++i) {
last[s[i] - 'a'] = i;
}
vector<int> res;
int start = 0, end = 0;
for (int i = 0; i < n; ++i) {
end = max(end, last[s[i] - 'a']);
if (i == end) {
res.push_back(i - start + 1);
start = i + 1;
}
}
return res;
}
int main() {
string s;
// 读取输入字符串
if (!getline(cin, s)) return 0;
vector<int> res = partitionBalloon(s);
// 按要求格式输出列表
cout << "[";
for (int i = 0; i < res.size(); ++i) {
cout << res[i];
if (i != res.size() - 1) {
cout << ", ";
}
}
cout << "]";
return 0;
}
题目内容
公司运动协会正在举办打气球游戏。打气球游戏规则如下:
墙上有一串各种颜色的气球,我们要给他尽可能多的分组,让相同颜色的气球在同一组内。
而且划分完的气球片段按顺序连接起来仍然是原始气球串
请返回一个列表表示划分完的气球片段长度,请注意,如果划分的片段有多个,各个片段之间以逗号和空格分割。
输入描述
一个字符串 s ,代表一串不同颜色的气球。字符串仅仅由小写英文字母组成,1<=s.length<=500
输出描述
一个列表,代表划分完之后的每个气球片段的长度。
样例1
输入
abcdeabl
输出
[7, 1]
说明
可以划分为"abcdeab"和"l",能保证同一颜色的气球在一个片级中,目获得的片段数量多。两个片段以逗号和空格分割。
样例2
输入
qwerwererrasdfghqccv
输出
[17, 2, 1]
说明
划分结果为"qwerwererasdfghq"、"cc"、"v"。每个颜色的气球只能出现在一个片段中。
像“qwerwererasdfghgcc”,"v" 这样的划分是错误的,因为划分的片段数不是最多的。三个片段以逗号和空格分割。
样例3
输入
eccbbbbdec
输出
[10]