
문제 링크: https://leetcode.com/problems/longest-substring-without-repeating-characters/
주어진 문자열에서 문자가 중복되지 않는 최대 길이 문자열의 길이를 반환하는 문제이다.
Bruteforce 방법부터 시작하자면, 당연히 주어진 문자열로 만들 수 있는 모든 substring에 대해 Repeating Characters가 있는지 검사해야 한다.
모든 substring을 check하기 위해 for loop 두 개를 사용하여, 바깥 loop의 i는 0부터 n-1(n은 문자열의 길이)까지, 안쪽 loop의 j는 i+1부터 n까지 순회하도록 한다.
이 때, 사실 만들 수 있는 모든 문자열에 대해 check하려면 길이가 1인 문자열도 포함해야 하므로 j는 i+1부터 시작할 건지, i부터 시작할 건지 고민을 해야 한다.
ex) testcase가 bbbbb인 경우, longest substring without repeating characters는 길이가 1이므로 j를 i부터 순회 시킨다.
만든 substring에 대해 중복된 문자가 존재하는지 검사한다.
문자 중복 체크엔 HashSet을 사용할 수 있다.
→ 중복된 문자가 존재하지 않는다면, maxLength를 갱신한다.
class Solution {
public int lengthOfLongestSubstring(String s) {
if(s.length() <= 1) return s.length();
int maxLength=0;
for(int i=0; i<s.length()-1; i++) {
for(int j=i; j<s.length(); j++) {
if(allUnique(s, i, j)) maxLength = Math.max(maxLength, j-i+1);
}
}
return maxLength;
}
boolean allUnique(String s, int start, int end) {
Set<Character> set = new HashSet<>();
for(int i=start; i<=end; i++) {
if(set.contains(s.charAt(i))) return false;
set.add(s.charAt(i));
}
return true;
}
}
O(n^3)의 시간복잡도로 만들 수 있는 모든 문자열을 check하고 있으므로 결과는 TLE 다.
이전의 풀이에선 만들 수 있는 모든 문자열에 대해 체크했고, 모든 문자열에 대해 HashSet을 생성하여 문자열의 처음부터 끝까지 검사했다. 이 부분을 optimize 할 수 있다.
class Solution {
Set<Character> set = new HashSet<>();
public int lengthOfLongestSubstring(String s) {
if(s.length() <= 1) return s.length();
int maxLength=0;
for(int i=0; i<s.length()-1; i++) {
set.add(s.charAt(i));
for(int j=i; j<s.length(); j++) {
if(j!=i && set.contains(s.charAt(j))) break;
maxLength = Math.max(maxLength, j-i+1);
set.add(s.charAt(j));
}
set.clear();
}
return maxLength;
}
}
class Solution {
public int lengthOfLongestSubstring(String s) {
if(s.length() <= 1) return s.length();
Set<Character> set = new HashSet<>();
int i=0;
int j=0;
int maxLength=0;
while(i<s.length() && j<s.length()) {
if(!set.contains(s.charAt(j))) {
set.add(s.charAt(j++));
maxLength = Math.max(maxLength, j-i);
}
else set.remove(s.charAt(i++));
}
return maxLength;
}
}
class Solution {
public int lengthOfLongestSubstring(String s) {
int maxLength = 0;
Map<Character, Integer> map = new HashMap<>();
int slow = 0;
int fast = 0;
while(fast < s.length()) {
char c = s.charAt(fast);
if(map.containsKey(c)) {
slow = Math.max(map.get(c)+1, slow);
}
map.put(c, fast);
fast++;
maxLength = Math.max(maxLength, fast-slow);
}
return maxLength;
}
}
HashMap으로 문자열의 index를 저장해놓으면,while문으로 slow를 중복되는 문자까지 옮기지 않고 바로 옮길 수 있음.
주의!
HashMap에 저장된 index값이 현재 slow index보다 앞에 있을 수 있으니 Math.max로 더 뒤로 옮겨주기
