I am taking a course to prepare for coding interviews and how it works is I try a problem then the solution is presented.
Question: Given a string, find the length of the longest substring, which has all distinct characters.
Example: Input: String="aabccbb" Output: 3 Explanation: The longest substring with distinct characters is "abc".
I was wondering if there is any reason to use a HashMap and not an ArrayList on this problem? I will show both solutions and I was wondering if mine is wrong for any reason or if it is inefficient?
My solution works and the output matches (3,2,3). That's why I am wondering if I am doing anything wrong because their solution seems so much more complex than needed?
My Solution:
import java.util.*;
class NoRepeatSubstring {
public static int findLength(String str) {
// TODO: Write your code here
List<Character> charList = new ArrayList<Character>();
int maxLength = 0;
for(int windowEnd = 0; windowEnd < str.length(); windowEnd ) {
while(charList.contains(str.charAt(windowEnd))) {
charList.remove(0);
}
charList.add(str.charAt(windowEnd));
if(charList.size() > maxLength) {
maxLength = charList.size();
}
}
return maxLength;
}
public static void main(String[] args) {
System.out.println("Length of the longest substring: " NoRepeatSubstring.findLength("aabccbb"));
System.out.println("Length of the longest substring: " NoRepeatSubstring.findLength("abbbb"));
System.out.println("Length of the longest substring: " NoRepeatSubstring.findLength("abccde"));
}
}
Their Solution:
import java.util.*;
class NoRepeatSubstring {
public static int findLength(String str) {
int windowStart = 0, maxLength = 0;
Map<Character, Integer> charIndexMap = new HashMap<>();
// try to extend the range [windowStart, windowEnd]
for (int windowEnd = 0; windowEnd < str.length(); windowEnd ) {
char rightChar = str.charAt(windowEnd);
// if the map already contains the 'rightChar', shrink the window from the beginning so that
// we have only one occurrence of 'rightChar'
if (charIndexMap.containsKey(rightChar)) {
// this is tricky; in the current window, we will not have any 'rightChar' after its previous index
// and if 'windowStart' is already ahead of the last index of 'rightChar', we'll keep 'windowStart'
windowStart = Math.max(windowStart, charIndexMap.get(rightChar) 1);
}
charIndexMap.put(rightChar, windowEnd); // insert the 'rightChar' into the map
maxLength = Math.max(maxLength, windowEnd - windowStart 1); // remember the maximum length so far
}
return maxLength;
}
public static void main(String[] args) {
System.out.println("Length of the longest substring: " NoRepeatSubstring.findLength("aabccbb"));
System.out.println("Length of the longest substring: " NoRepeatSubstring.findLength("abbbb"));
System.out.println("Length of the longest substring: " NoRepeatSubstring.findLength("abccde"));
}
}
CodePudding user response:
charList.contains(str.charAt(windowEnd))
is O(n) while charIndexMap.containsKey(rightChar)
is (usually) O(1).
charList.contains
goes through the whole list to check if the character is in the list.
charIndexMap.containsKey
hashes the character/key, which is constant in time.
(It would be even faster to use an array of booleans with a fixed size of 2^8 (=the number of possible characters) and use the character as index into the array. That would be guaranteed to be O(1) and would also be faster with small strings since no time is wasted on computing hashes.)
CodePudding user response:
ArrayList's contains method is O(N) but of HashMap is mostly O(1). Infact you dont even need to use a HashMap here , even HashSet will do.