#P2724. 第3题-字符串数组权值
-
1000ms
Tried: 47
Accepted: 4
Difficulty: 6
所属公司 :
阿里
时间 :2025年3月22日-阿里淘天(开发岗)
-
算法标签>字符串
第3题-字符串数组权值
题解
题面描述
给定一个长度为 n 的字符串数组,每个字符串由若干个小写字母组成。定义一个字符串数组的权值为最长连续相同字符串的区间长度。现在小红想知道,若恰好删除一段连续非空区间,剩下的字符串数组的权值最大是多少。
思路
这道题的核心思路是,对于每个字符串,首先判断是否每个字符都相同。如果是,直接输出字符串长度减一。如果不是,则通过遍历字符串,记录每个字符连续出现的区间长度。接着,使用哈希表保存每个字符的连续区间信息,排序后选取最大的两个区间长度来合并,从而得到删除某段区间后的最大权值。最后输出每个字符串的最大权值。
-
每个字符的连续区间处理:
- 对每个字符串,首先检查是否每个字符都相同。如果是,删除一个字符后,权值就是字符串的长度减一。
-
分段计数:
- 如果字符串中的字符不完全相同,我们将字符串划分为多个连续相同字符的区间。例如,对于字符串
"aabbbaa",可以划分为三个区间:"aa","bbb","aa"。
- 如果字符串中的字符不完全相同,我们将字符串划分为多个连续相同字符的区间。例如,对于字符串
-
合并前后区间:
- 对于每个字符的所有区间,检查是否可以通过删除某段区间来合并前后相同字符的区间,从而得到更大的连续区间。
-
优化:
- 通过哈希表存储每个字符的所有区间长度,并对每个字符的区间按从大到小的顺序进行排序。然后选择合并两个最大的区间。
C++
#include <iostream>
#include <string>
#include <unordered_map>
#include <vector>
#include <algorithm>
using namespace std;
int main() {
int n;
cin >> n; // 输入字符串的个数
int max_length = 0; // 存储最终的最大长度
while (n--) {
string s;
cin >> s; // 输入一个字符串
// 如果字符串中每个字符都相同,那么答案就是字符串的长度减去1
if (s.size() == count(s.begin(), s.end(), s[0])) {
max_length = max(max_length, (int)s.size() - 1);
continue; // 跳过当前字符串,进入下一个字符串
}
int current_len = 0; // 当前字符段的长度
unordered_map<char, vector<int>> char_segments; // 用于存储每个字符出现的连续段的长度
// 遍历字符串中的每个字符
for (int i = 0; i < s.size(); ++i) {
if (i == 0 || s[i] == s[i - 1]) { // 如果当前字符与前一个字符相同,增加当前字符段长度
current_len++;
} else {
// 如果字符段结束,保存字符段长度
char_segments[s[i - 1]].push_back(current_len);
current_len = 1; // 重置当前字符段长度
}
}
// 处理字符串的最后一段
char_segments[s[s.size() - 1]].push_back(current_len);
// 对每个字符的连续段进行处理
for (auto& pair : char_segments) {
sort(pair.second.rbegin(), pair.second.rend()); // 按长度从大到小排序
if (pair.second.size() == 1) {
// 如果只有一个连续段,取它的长度
max_length = max(max_length, pair.second[0]);
} else {
// 如果有多个连续段,取前两个段的和
max_length = max(max_length, pair.second[0] + pair.second[1]);
}
}
}
cout << max_length << endl; // 输出最终结果
return 0;
}
Python
def main():
n = int(input()) # 输入字符串的个数
max_length = 0 # 存储最终的最大长度
for _ in range(n):
s = input() # 输入一个字符串
# 如果字符串中每个字符都相同,那么答案就是字符串的长度减去1
if len(s) == s.count(s[0]):
max_length = max(max_length, len(s) - 1)
continue # 跳过当前字符串,进入下一个字符串
current_len = 0 # 当前字符段的长度
char_segments = {} # 用于存储每个字符出现的连续段的长度
# 遍历字符串中的每个字符
for i in range(len(s)):
if i == 0 or s[i] == s[i - 1]: # 如果当前字符与前一个字符相同,增加当前字符段长度
current_len += 1
else:
# 如果字符段结束,保存字符段长度
if s[i - 1] not in char_segments:
char_segments[s[i - 1]] = []
char_segments[s[i - 1]].append(current_len)
current_len = 1 # 重置当前字符段长度
# 处理字符串的最后一段
if s[-1] not in char_segments:
char_segments[s[-1]] = []
char_segments[s[-1]].append(current_len)
# 对每个字符的连续段进行处理
for lengths in char_segments.values():
lengths.sort(reverse=True) # 按长度从大到小排序
if len(lengths) == 1:
# 如果只有一个连续段,取它的长度
max_length = max(max_length, lengths[0])
else:
# 如果有多个连续段,取前两个段的和
max_length = max(max_length, lengths[0] + lengths[1])
print(max_length) # 输出最终结果
if __name__ == "__main__":
main()
Java
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt(); // 输入字符串的个数
int maxLength = 0; // 存储最终的最大长度
while (n-- > 0) {
String s = scanner.next(); // 输入一个字符串
// 如果字符串中每个字符都相同,那么答案就是字符串的长度减去1
if (s.length() == countChar(s, s.charAt(0))) {
maxLength = Math.max(maxLength, s.length() - 1);
continue; // 跳过当前字符串,进入下一个字符串
}
int currentLen = 0; // 当前字符段的长度
Map<Character, List<Integer>> charSegments = new HashMap<>(); // 用于存储每个字符出现的连续段的长度
// 遍历字符串中的每个字符
for (int i = 0; i < s.length(); ++i) {
if (i == 0 || s.charAt(i) == s.charAt(i - 1)) { // 如果当前字符与前一个字符相同,增加当前字符段长度
currentLen++;
} else {
// 如果字符段结束,保存字符段长度
charSegments.putIfAbsent(s.charAt(i - 1), new ArrayList<>());
charSegments.get(s.charAt(i - 1)).add(currentLen);
currentLen = 1; // 重置当前字符段长度
}
}
// 处理字符串的最后一段
charSegments.putIfAbsent(s.charAt(s.length() - 1), new ArrayList<>());
charSegments.get(s.charAt(s.length() - 1)).add(currentLen);
// 对每个字符的连续段进行处理
for (Map.Entry<Character, List<Integer>> entry : charSegments.entrySet()) {
List<Integer> segments = entry.getValue();
segments.sort(Comparator.reverseOrder()); // 按长度从大到小排序
if (segments.size() == 1) {
// 如果只有一个连续段,取它的长度
maxLength = Math.max(maxLength, segments.get(0));
} else {
// 如果有多个连续段,取前两个段的和
maxLength = Math.max(maxLength, segments.get(0) + segments.get(1));
}
}
}
System.out.println(maxLength); // 输出最终结果
scanner.close();
}
// 统计某个字符在字符串中出现的次数
private static int countChar(String s, char c) {
int count = 0;
for (int i = 0; i < s.length(); i++) {
if (s.charAt(i) == c) {
count++;
}
}
return count;
}
}
题目内容
小红拿到一个长度为n的字符串数组,每个字符串由若干个小写字母组成。
定义一个字符串数组的权值为最长连续相同字符串的区间长度。
小红想知道,若恰好删除一段连续非空区间,剩下的字符串数组的权值最大是多少。
输入描述
第一行一个整数n(2≤n≤105),表示字符串数组的长度。
接下来n 行,每行一个字符串,保证仅由小写字母组成。
保证所有字符串的长度之和不超过106。
输出描述
一个整数,表示删除一段连续非空区间后,剩下的字符串数组的权值最大是多少。
样例1
输入
3
aab
qwq
aab
输出
2