문제링크: https://leetcode.com/problems/partition-labels/
문자열을 최대한 나누되 같은 문자는 같은 구역에 존재하도록 하는 partition을 구하는 문제다.
문자열을 처음부분부터 최대한 한 구역에 포함시키는 쪽으로 접근하였다. ababcbacadefegdehijhklij
의 경우 처음에 a
가 포함된 부분을 포함해 문제의 조건을 만족(같은 문자는 한 구역에 있어야 한다)하기 위해선 마지막 a
가 있는 곳까지 포함시켜야한다. a
가 있는 곳까지 탐색하는 중간에 b
와 c
를 만나는 경우 이 또한 마지막 b
와 c
를 포함시키는 구간까지 와야한다. 따라서 어떤 문자를 만났을 경우에 그 문자가 마지막으로 존재하는 index를 알아야하며 이를 처음에 한번 O(n)
의 탐색을 통해 HashTable
로 만들 수 있다.
이후 다시 처음으로 돌아가 한 구간을 최소한으로 정의하기 위해 같은 문자를 포함하는 index
까지 탐색하고나면 가장 작은 분할 구역을 greedy하게 얻을 수 있고 이 방식을 반복하면 결과를 얻을 수 있다.
마지막 index
를 저장하는 indexMap
을 만든다.indexMap
을 완성한다.start
는 구역이 시작하는 곳 -1, end
는 구역이 끝나는 곳이다.indexMap
을 통해 end
를 갱신한다.(최소한 end
까지는 한 구역에 포함되어야 한다)end === i
인 경우 가장 작은 한 구역이 완성된 것으로 그 크기를 end - start
로 구해 result
에 추가하고 start
를 i
로 갱신한다.(다음 구역의 시작위치 -1)result
를 반환한다.var partitionLabels = function(s) {
// 문자가 중복되지 않도록 최대로 나누기
// greedy with map
const indexMap = {}; // letter => maxIndex
for (let i = 0; i < s.length; i++) {
indexMap[s[i]] = i;
}
const result = [];
let start = -1;
let end = 0;
for (let i = 0; i < s.length; i++) {
end = Math.max(end, indexMap[s[i]]);
if (end === i) {
result.push(end - start);
start = i;
}
}
return result;
};
indexMap
을 만드는데 O(n)
, greedy하게 구역을 나누는데 O(n)
총 O(n)
의 시간복잡도가 필요하고 문자의 개수는 최대 26개로 O(1)
의 공간복잡도가 필요하다.
1번 방식의 indexMap을 charCode - 97 => last index 로 매핑시킨 26사이즈 배열로 조금 업그레이드 할 수 있다.
var partitionLabels = function(s) {
// 문자가 중복되지 않도록 최대로 나누기
// Greedy with map
const indexMap = []; // letter code - 97 => last index
for (let i = 0; i < s.length; i++) {
indexMap[s.charCodeAt(i) - 97] = i;
}
const result = [];
let start = -1;
let end = 0;
for (let i = 0; i < s.length; i++) {
end = Math.max(end, indexMap[s.charCodeAt(i) - 97]);
if (end === i) {
result.push(end - start);
start = i;
}
}
return result;
};