[英]Finding the Length of the Longest Substring without repeating characters
我對這個算法有一個整體的了解,但是 Math.max 是如何被用來輸出正確的子字符串的呢?
檢查重復功能實際上是如何檢查每個單獨字符的匹配項?
public class Solution {
public int lengthOfLongestSubstring(String s) {
int n = s.length();
int res = 0;
for(int i = 0; i < n; i++){
for(int j = i; j < n; j++){
if(checkRepetition(s,i,j)){
res = Math.max(res, j - i + 1);
}
}
}
return res;
}
private boolean checkRepetition(String s,int start,int end){
int []chars = new int [128];
for(int i = start; i <= end; i++){
char c = s.charAt(i);
chars[c]++;
if(chars[c] > 1){
return false;
}
}
return true;
}
}
您當前的蠻力解決方案會生成每個子字符串的索引,然后檢查它是否包含重復的字符。
通過這樣做,您將多次重復相同的計算。 我們可以只執行一次檢查,然后重復使用結果,而不是一遍又一遍地重新訪問字符串的相同部分。
我不知道這個挑戰中的輸入是否有一些限制,但是創建一個長度為128
的數組似乎很可疑,因為它超出了數字和小寫/大寫英文字母的范圍。 如果您在控制台字符上打印,比如說0
、 10
和127
,您將不會在控制台上看到任何有意義的內容。
並且總體時間復雜度是二次O(n ^ 2) (考慮到方法checkRepetition()
的時間復雜度是恆定的,因為它最多可以執行128
次迭代)。
這個問題可以在線性時間O(n)內解決。
它不需要任何假設。 下面介紹的算法基於評論中提供的@Andrey B. Panfilov的建議。
為了找到最長的不包含與子字符串一起重復的字符的子字符串,我們需要遍歷給定的字符串並為當前的非重復子字符串存儲先前遇到的字符。 為此,我們可以使用HashSet
(表示為seen
)。
我們還需要維護一個指向當前子字符串開頭的索引(表示為left
)。
在迭代時,我們試圖將每個新字符合並到當前子字符串中,如果seen.add()
將返回false
,這意味着我們遇到了重復項,這意味着我們已經完成了之前的子字符串。 現在我們需要將left
索引向右移動,以便將一個索引定位到當前子字符串末尾(在索引right
處)的字符之前出現的位置之外。 在移動left
索引時,我們還必須從集合中刪除相應的字符str.charAt(left)
。
為了存儲非重復子串的最大長度,我們需要維護一個變量,該變量必須在每次迭代結束時更新。
這就是它的實現方式:
public static int lengthOfLongestSubstring(String str) {
Set<Character> seen = new HashSet<>();
int left = 0;
int maxSub = 0;
for(int right = 0; right < str.length(); right++) {
char next = str.charAt(right);
if (!seen.add(next)) {
while (str.charAt(left) != next) {
seen.remove(str.charAt(left++));
}
left++;
}
maxSub = Math.max(right + 1 - left, maxSub);
}
return maxSub;
}
main()
public static void main(String[] args) {
System.out.println(lengthOfLongestSubstring("")); // 0
System.out.println(lengthOfLongestSubstring("a")); // 1
System.out.println(lengthOfLongestSubstring("aa")); // 1
System.out.println(lengthOfLongestSubstring("abc")); // 3
System.out.println(lengthOfLongestSubstring("abccb")); // 3
System.out.println(lengthOfLongestSubstring("abccfghijklhl")); // 8
}
輸出:
0 // ""
1 // "a"
1 // "aa"
3 // "abc"
3 // "abccb"
8 // "abccfghijklhl"
但是如何使用 Math.max 輸出正確的子字符串?
Math.max 僅用於獲取最大長度而不是子字符串本身。 要獲得最大長度的子字符串,您需要創建一個字符串變量並相應地更新它:
if (j-i+1 > res) {
res = j-i+1
maxString = s.subsring(i, j+1)
}
檢查重復功能實際上是如何檢查每個單獨字符的匹配項?
看看int[] chars = new int[128]
和chars[c]++
第二部分增加字符在字符串中出現的次數。
例如,在您的輸入字符串中,假設字符“z”出現兩次,然后位置 122 處的chars
數組遞增,因為字符“z”相當於 ascii 表中的整數 122。 因此,如果 chars[122] > 1,則重復 'z'。 簡單的。 這就是下一個區塊
if(chars[c] > 1){
return false;
}
是在做。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.