LeetCode – Longest Substring Without Repeating Characters (Java)
Given a string, find the length of the longest substring without repeating characters. For example, the longest substring without repeating letters for "abcabcbb" is "abc", which the length is 3. For "bbbbb" the longest substring is "b", with the length of 1.
https://discuss.leetcode.com/topic/68976/sliding-window-algorithm-template-to-solve-all-the-leetcode-substring-search-problem
X.
https://leetcode.com/articles/longest-substring-without-repeating-characters/
https://discuss.leetcode.com/topic/4083/shortest-o-n-dp-solution-with-explanations
the basic idea is, keep a hashmap which stores the characters in string as keys and their positions as values, and keep two pointers which define the max substring. move the right pointer to scan through the string , and meanwhile update the hashmap. If the character is already in the hashmap, then move the left pointer to the right of the same character last found. Note that the two pointers can only move forward.
Given a string, find the length of the longest substring without repeating characters. For example, the longest substring without repeating letters for "abcabcbb" is "abc", which the length is 3. For "bbbbb" the longest substring is "b", with the length of 1.
https://discuss.leetcode.com/topic/68976/sliding-window-algorithm-template-to-solve-all-the-leetcode-substring-search-problem
public int lengthOfLongestSubstring(String s) {
Map<Character, Integer> map = new HashMap<>();
int begin = 0, end = 0, counter = 0, d = 0;
while (end < s.length()) {
// > 0 means repeating character
//if(map[s.charAt(end++)]-- > 0) counter++;
char c = s.charAt(end);
map.put(c, map.getOrDefault(c, 0) + 1);
if(map.get(c) > 1) counter++;
end++;
while (counter > 0) {
//if (map[s.charAt(begin++)]-- > 1) counter--;
char charTemp = s.charAt(begin);
if (map.get(charTemp) > 1) counter--;
map.put(charTemp, map.get(charTemp)-1);
begin++;
}
d = Math.max(d, end - begin);
}
return d;
}
X.
https://leetcode.com/articles/longest-substring-without-repeating-characters/
The above solution requires at most 2n steps. In fact, it could be optimized to require only n steps. Instead of using a set to tell if a character exists or not, we could define a mapping of the characters to its index. Then we can skip the characters immediately when we found a repeated character.
The reason is that if have a duplicate in the range with index , we don't need to increase little by little. We can skip all the elements in the range and let to be directly.
https://discuss.leetcode.com/topic/8232/11-line-simple-java-solution-o-n-with-explanationhttps://discuss.leetcode.com/topic/4083/shortest-o-n-dp-solution-with-explanations
the basic idea is, keep a hashmap which stores the characters in string as keys and their positions as values, and keep two pointers which define the max substring. move the right pointer to scan through the string , and meanwhile update the hashmap. If the character is already in the hashmap, then move the left pointer to the right of the same character last found. Note that the two pointers can only move forward.
I think there is no need to update
longest
evey time
public int lengthOfLongestSubstring(String s) {
if (s.length()==0) return 0;
HashMap<Character, Integer> map = new HashMap<Character, Integer>();
int max=0;
for (int i=0, j=0; i<s.length(); ++i){
if (map.containsKey(s.charAt(i))){
j = Math.max(j,map.get(s.charAt(i))+1);
}
map.put(s.charAt(i),i);
max = Math.max(max,i-j+1);
}
return max;
}
https://discuss.leetcode.com/topic/5781/my-accepted-o-n-java-solution
https://discuss.leetcode.com/topic/1914/my-o-n-solution/2
public int lengthOfLongestSubstring(String s) {
int n = s.length();
if (n == 0) return 0;
int start = 0;
int max = 0;
Map<Character, Integer> lastSeens = new HashMap<Character, Integer>();
for (int i = 0; i < n; i++) {
Integer lastSeen = lastSeens.get(s.charAt(i));
if (lastSeen != null) {
if (lastSeen >= start) {
max = Math.max(max, i - start);
start = lastSeen + 1;
}
}
lastSeens.put(s.charAt(i), i);
}
max = Math.max(max, n - start);
return max;
}
https://discuss.leetcode.com/topic/27794/simple-java-solution public int lengthOfLongestSubstring(String s) {
Map<Character,Integer> indices = new HashMap<Character,Integer>();
int max = 0;
int start = -1;
int end = 0;
for(end=0; end < s.length(); end++){
char c = s.charAt(end);
if(indices.containsKey(c)){
int newstart = indices.get(c);
start = Math.max(start,newstart);
}
max = Math.max(length,end-start);
indices.put(c,end);
}
return max;
}
X. Use int[256]https://discuss.leetcode.com/topic/1914/my-o-n-solution/2
public int lengthOfLongestSubstring(String s) {
int[] occ = new int[256];
int max = 0, counter = 0, start = 1;
for (int i=0; i < s.length(); i++){
char ch = s.charAt(i);
if (occ[ch] >= start){
counter -= occ[ch] - start + 1;
start = occ[ch] + 1;
}
occ[ch] = i+1;
max = Math.max(max, ++counter);
}
return max;
}
https://discuss.leetcode.com/topic/26483/o-n-time-o-1-space-solution-using-kadane-s-algo-in-java
Idea is that, while we traverse form left to right if we see a character at position j is a duplicate of a character at a position i < j on the left then we know that we can't start the substring from i anymore. So, we need to start a new substring from i+1 position. While doing this we also need to update the length of current substring and start of current substring. Important part of this process is to make sure that we always keep the latest position of the characters we have seen so far.
public int lengthOfLongestSubstring(String s) {
int lastIndices[] = new int[256];
for(int i = 0; i<256; i++){
lastIndices[i] = -1;
}
int maxLen = 0;
int curLen = 0;
int start = 0;
int bestStart = 0;
for(int i = 0; i<s.length(); i++){
char cur = s.charAt(i);
if(lastIndices[cur] < start){
lastIndices[cur] = i;
curLen++;
}
else{
int lastIndex = lastIndices[cur];
start = lastIndex+1;
curLen = i-start+1;
lastIndices[cur] = i;
}
if(curLen > maxLen){
maxLen = curLen;
bestStart = start;
}
}
return maxLen;
}
https://discuss.leetcode.com/topic/22048/my-easy-solution-in-java-o-n
We can also use int[256] to store the index.
http://www.zrzahid.com/longest-sub-string-with-no-duplicate-chars/
X. Using HashSet
https://leetcode.com/discuss/60645/share-my-java-solution-using-hashset
http://www.lifeincode.net/programming/leetcode-longest-substring-without-repeating-characters/
http://comproguide.blogspot.com/2014/09/longest-substring-with-unique-characters.html
http://www.programcreek.com/2013/02/leetcode-longest-substring-without-repeating-characters-java/
https://discuss.leetcode.com/topic/22048/my-easy-solution-in-java-o-n
public int lengthOfLongestSubstring(String s) {
int[] mOccur = new int[256];
int maxL = 0;
for(int i = 0, j = 0; i < s.length(); ++i){
char ch = s.charAt(i);
++mOccur[ch];
while(mOccur[ch] > 1){
--mOccur[s.charAt(j++)];
}
maxL = Math.max(maxL, i - j + 1);
}
return maxL;
}
http://n00tc0d3r.blogspot.com/2013/04/longest-substring-without-repeating.html public int lengthOfLongestSubstring(String s) {
int maxLen = 0;
int start = 0, end = 0;
// a map mapping a char to its prior index in s
HashMap<Character, Integer> map = new HashMap<Character, Integer>();
while (end < s.length()) {
char cur = s.charAt(end);
if (map.containsKey(cur) && map.get(cur) >= start) {
// hit a recurrence
maxLen = Math.max(maxLen, end-start);
start = map.get(cur) + 1;
}
map.put(cur, end++);
}
maxLen = Math.max(maxLen, end-start);
return maxLen;
}
http://ajeetsingh.org/2013/11/10/given-a-string-find-maximum-size-of-a-sub-string-in-which-no-duplicate-character-present/We can also use int[256] to store the index.
public
static
int
find(String source){
int
window =
0
;
int
start =
0
;
int
i =
0
;
HashMap<Character, Integer> map =
new
HashMap<Character, Integer>();
while
( i < source.length()){
if
(map.containsKey(source.charAt(i))){
int
currentWindow = i-start;
if
(window < currentWindow){
window = currentWindow;
}
start = map.get(source.charAt(i)) +
1
;
//no need map.clear();
}
if
(i+
1
== source.length()){
int
currentWindow = i-start +
1
;
if
(window < currentWindow){
window = currentWindow;
}
return
window;
}
map.put(source.charAt(i), i);
i++;
}
return
0
;
}
http://www.zrzahid.com/longest-sub-string-with-no-duplicate-chars/
public static int lengthOfLongestNonrepeatedSubstring(String s) { int lastIndices[] = new int[256]; for(int i = 0; i<256; i++){ lastIndices[i] = -1; } int maxLen = 0; int curLen = 0; int start = 0; int bestStart = 0; for(int i = 0; i<s.length(); i++){ char cur = s.charAt(i); if(lastIndices[cur] < start){ lastIndices[cur] = i; curLen++; } else{ int lastIndex = lastIndices[cur]; start = lastIndex+1; curLen = i-start+1; lastIndices[cur] = i; } if(curLen > maxLen){ maxLen = curLen; bestStart = start; } } return maxLen; }
X. Using HashSet
https://leetcode.com/discuss/60645/share-my-java-solution-using-hashset
- Time complexity : . In the worst case each character will be visited twice by and .
- Space complexity : . Same as the previous approach. We need space for the sliding window, where is the size of the
Set
. The size of the Set is upper bounded by the size of the string and the size of the charset/alphabet .
The idea is use a hash set to track the longest substring without repeating characters so far, use a fast pointer j to see if character j is in the hash set or not, if not, great, add it to the hash set, move j forward and update the max length, otherwise, delete from the head by using a slow pointer i until we can put character j to the hash set.
public int lengthOfLongestSubstring(String s) {
int i = 0, j = 0, max = 0;
Set<Character> set = new HashSet<>();
while (j < s.length()) {
if (!set.contains(s.charAt(j))) {
set.add(s.charAt(j++));
max = Math.max(max, set.size());
} else { /// this runs multiple times
set.remove(s.charAt(i++));
}
}
return max;
}http://www.lifeincode.net/programming/leetcode-longest-substring-without-repeating-characters/
http://comproguide.blogspot.com/2014/09/longest-substring-with-unique-characters.html
http://www.programcreek.com/2013/02/leetcode-longest-substring-without-repeating-characters-java/
public int lengthOfLongestSubstring(String s) {
if (s.length() <= 1)
return s.length();
int prev = 0;
boolean[] letter = new boolean[256];
int max = 0;
for (int i = 0; i < s.length(); i++) {
if (!letter[s.charAt(i)])
letter[s.charAt(i)] = true;
else {
while (s.charAt(prev) != s.charAt(i)) {
letter[s.charAt(prev)] = false;
prev++;
}
prev++;
}
max = Math.max(max, i - prev + 1);
}
return max;
}
http://www.geeksforgeeks.org/length-of-the-longest-substring-without-repeating-characters/
How can we can look up if a character had existed in the substring instantaneously? The answer is using a simple table to store the characters that have appeared.
http://leetcode.com/2011/05/longest-substring-without-repeating-characters.html
X. Brute Force - O(1) space
LeetCode – Longest Substring Without Repeating Characters (Java) O(n^3)
https://medium.com/@xingren14/3-longest-substring-without-repeating-characters-5e01bc265098
This solution uses extra space to store the last indexes of already visited characters. The idea is to scan the string from left to right, keep track of the maximum length Non-Repeating Character Substring (NRCS) seen so far. Let the maximum length be max_len. When we traverse the string, we also keep track of length of the current NRCS using cur_len variable. For every new character, we look for it in already processed part of the string (A temp array called visited[] is used for this purpose). If it is not present, then we increase the cur_len by 1. If present, then there are two cases:
a) The previous instance of character is not part of current NRCS (The NRCS which is under process). In this case, we need to simply increase cur_len by 1.
b) If the previous instance is part of the current NRCS, then our current NRCS changes. It becomes the substring staring from the next character of previous instance to currently scanned character. We also need to compare cur_len and max_len, before changing current NRCS (or changing cur_len).
b) If the previous instance is part of the current NRCS, then our current NRCS changes. It becomes the substring staring from the next character of previous instance to currently scanned character. We also need to compare cur_len and max_len, before changing current NRCS (or changing cur_len).
int
longestUniqueSubsttr(
char
*str)
{
int
n =
strlen
(str);
int
cur_len = 1;
// To store the lenght of current substring
int
max_len = 1;
// To store the result
int
prev_index;
// To store the previous index
int
i;
int
*visited = (
int
*)
malloc
(
sizeof
(
int
)*NO_OF_CHARS);
/* Initialize the visited array as -1, -1 is used to indicate that
character has not been visited yet. */
for
(i = 0; i < NO_OF_CHARS; i++)
visited[i] = -1;
/* Mark first character as visited by storing the index of first
character in visited array. */
visited[str[0]] = 0;
/* Start from the second character. First character is already processed
(cur_len and max_len are initialized as 1, and visited[str[0]] is set */
for
(i = 1; i < n; i++)
{
prev_index = visited[str[i]];
/* If the currentt character is not present in the already processed
substring or it is not part of the current NRCS, then do cur_len++ */
if
(prev_index == -1 || i - cur_len > prev_index)
cur_len++;
/* If the current character is present in currently considered NRCS,
then update NRCS to start from the next character of previous instance. */
else
{
/* Also, when we are changing the NRCS, we should also check whether
length of the previous NRCS was greater than max_len or not.*/
if
(cur_len > max_len)
max_len = cur_len;
cur_len = i - prev_index;
}
visited[str[i]] = i;
// update the index of current character
}
// Compare the length of last NRCS with max_len and update max_len if needed
if
(cur_len > max_len)
max_len = cur_len;
free
(visited);
// free memory allocated for visited
return
max_len;
}
http://leetcode.com/2011/05/longest-substring-without-repeating-characters.html
int lengthOfLongestSubstring(string s) {
int n = s.length();
int i = 0, j = 0;
int maxLen = 0;
bool exist[256] = { false };
while (j < n) {
if (exist[s[j]]) {
maxLen = max(maxLen, j-i);
while (s[i] != s[j]) {
exist[s[i]] = false;
i++;
}
i++;
j++;
} else {
exist[s[j]] = true;
j++;
}
}
maxLen = max(maxLen, n-i);
return maxLen;
}
public static int lengthOfLongestSubstring3(String s) {
int max = 0;
HashSet<Character> set = new HashSet<Character>();
int candidateStartIndex = 0;
for (int iter = 0; iter < s.length(); ++iter) {
char c = s.charAt(iter);
if (set.contains(c)) {
max = Math.max(max, iter - candidateStartIndex);
while (s.charAt(candidateStartIndex) != s.charAt(iter)) {
set.remove(s.charAt(candidateStartIndex));
candidateStartIndex++;
}
candidateStartIndex++;
} else {
set.add(c);
}
}
max = Math.max(max, s.length() - candidateStartIndex);
return max;
}
X. Brute Force - O(1) space
The idea is pretty simple. We iterate thru the list once and we keep a pointer of where the current longest possible substring starts. During the iteration, we check if this last character is contained in the current substring. If so, move the ptr to the first index of the char at the string +1. Everytime we will compare and keep the max value up to date.
public int lengthOfLongestSubstring(String s) {
if (s.length() <= 1) return s.length();
int max = 1;
int ptr = 0;
for (int i = 1; i< s.length(); i++) {
// find the first occurence of the char after index ptr
int index = s.indexOf(s.charAt(i), ptr);
if (index < i) { // it means that it is contained in s.substring(ptr, i)
ptr = index + 1;
}
max = Math.max(max, i - ptr + 1);
}
return max;
}
LeetCode – Longest Substring Without Repeating Characters (Java) O(n^3)
public static int lengthOfLongestSubstring(String s) { char[] arr = s.toCharArray(); int pre = 0; HashMap<Character, Integer> map = new HashMap<Character, Integer>(); for (int i = 0; i < arr.length; i++) { if (!map.containsKey(arr[i])) { map.put(arr[i], i); } else { pre = pre > map.size() ? pre : map.size(); i = map.get(arr[i]); map.clear(); } } return Math.max(pre, map.size()); } |
不是一道难题但是有两个值得注意的坑
- 如果用map统计并不重复的char的话,然后选择遇到重复字符就clear map再重置index的话,会超时,因为有大量重复操作
- 添加辅助的start指针,长度用i和start之间的差来计算。 这样做就不会超时了。要注意的是start 的重置logic,每当遇到重复字符的时候,start不一定是要设成当前重复字符的原index的下一个,而是要看当前的start和这个index+1谁更大,因为有可能index+1会小于当前的start这样会造成错误。
- 最后记得收尾,比较s.length-start的长度是否更长