题目:
题解一:
- 求出每个字母最后一次出现的索引
- 从左向右遍历,如果当前字母是最后一次出现,就进行分割
public List<Integer> partitionLabels(String s) {
if (s == null || s.length() == 0) {
return new ArrayList<>();
}
int[] lastArr = new int[26];
for (int i = 0; i < s.length(); i++) {
lastArr[s.charAt(i) - 'a'] = i;
}
List<Integer> list = new ArrayList<>(s.length());
int start = 0,end = 0;
for (int i = 0; i < s.length(); i++) {
end = Math.max(end, lastArr[s.charAt(i) - 'a']);
if (i == end) {
list.add(end - start + 1);
start = end + 1;
end = 0;
}
}
return list;
}
时间复杂度:O(n)
题解二:合并区间
- 求出每个字母第一次和最后一次出现的索引,记作区间[start,end]
- 所有区间按照左边界排序
- 合并相互重叠的区间
public List<Integer> partitionLabels(String s) {
if (s == null || s.length() == 0) {
return new ArrayList<>();
}
int[][] partitions = findPartitions(s);
Arrays.sort(partitions, Comparator.comparingInt(x -> x[0]));
int preLeft = partitions[0][0];
int preRight = partitions[0][1];
List<Integer> list = new ArrayList<>();
for (int[] partition : partitions) {
if (partition[0] > preRight) {
list.add(preRight-preLeft+1);
preLeft = partition[0];
}
preRight = Math.max(partition[1], preRight);
}
// 添加最后一个区间
list.add(preRight-preLeft+1);
return list;
}
public int[][] findPartitions(String s) {
int count = 0;
int[][] hash = new int[26][2];
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (hash[c - 'a'][0] == 0) {
hash[c - 'a'][0] = i+1;
count++;
}
hash[c - 'a'][1] = i+1;
}
int index = 0;
int[][] res = new int[count][2];
for (int[] ints : hash) {
if (ints[0] == 0 && ints[1] == 0) {
continue;
}
res[index][0] = ints[0];
res[index][1] = ints[1];
index++;
}
return res;
}
时间复杂度:O(n)