最近刷到leetCode裏面的一道算法題,裏面有涉及到Sliding windowing算法,所以寫一篇文章稍微總結一下算法
沒有重複字符的子字符的最大長度:給一個字符串,得到沒有重複字符的最長子字符的長度
例子:
輸入:"abcabcbb"
輸出:3
解釋:由於沒有重複字符的子字符是'abc',因此長度是3數組
public class Solution {//時間複雜度高O(n3)
public int lengthOfLongestSubstring(String s) {
int n = s.length();
int ans = 0;
//遍歷全部的子字符串,記錄沒有重複字母的子字符串的最大的長度
//獲取子字符串時,使用兩個標籤,分別表明子字符串的開頭和結尾
for (int i = 0; i < n; i++)
for (int j = i + 1; j <= n; j++)
//當子字符串沒有重複字母時,ans記錄最大的長度
if (allUnique(s, i, j)) ans = Math.max(ans, j - i);
return ans;
}
//判斷該子字符串是否有重複的字母
public boolean allUnique(String s, int start, int end) {
//HashSet實現了Set接口,它不容許集合中出現重複元素。
Set<Character> set = new HashSet<>();
for (int i = start; i < end; i++) {
Character ch = s.charAt(i);
if (set.contains(ch)) return false;
set.add(ch);
}
return true;
}
}
複製代碼
時間複雜度:O(n3).bash
經過使用HashSet做爲一個滑動窗口,檢查一個字符是否已經存在於現有的子字符中只須要O(1).
滑動窗口常常做爲一個抽象的概念來處理數組/字符串問題。窗口表明着一組數據/字符串元素,經過開頭和結尾的索引來定義窗口。優化
public class Solution {//時間複雜度O(2n)
//滑動窗口算法
public int lengthOfLongestSubstring(String s) {
int n = s.length();
Set<Character> set = new HashSet<>();
int ans = 0, i = 0, j = 0;
while (i < n && j < n) {//窗口的左邊是i,右邊是j,下列算法將窗口的左右移動,截取出其中一段
// try to extend the range [i, j]
if (!set.contains(s.charAt(j))){//若是set中不存在該字母,就將j+1,至關於窗口右邊向右移動一格,左邊不動
set.add(s.charAt(j++));
ans = Math.max(ans, j - i);//記錄目前存在過的最大的子字符長度
}
else {//若是set中存在該字母,則將窗口左邊向右移動一格,右邊不動,直到該窗口中不存在重複的字符
set.remove(s.charAt(i++));
}
}
return ans;
}
}
複製代碼
時間複雜度:O(2n)。在最差的狀況下,每一個字符將會被訪問兩次ui
上面的滑動窗口算法最多須要2n的步驟,但這實際上是能被優化爲只須要n步。咱們可使用HashMap定義字符到索引之間的映射,而後,當咱們發現子字符串中的重複字符時,能夠直接跳過遍歷過的字符了。spa
public class Solution {//時間複雜度o(n)
public int lengthOfLongestSubstring(String s) {
int n = s.length(), ans = 0;
//使用hashmap記錄遍歷過的字符的索引,當發現重複的字符時,能夠將窗口的左邊直接跳到該重複字符的索引處
Map<Character, Integer> map = new HashMap<>(); // current index of character
// try to extend the range [i, j]
for (int j = 0, i = 0; j < n; j++) {//j負責向右邊遍歷,i根據重複字符的狀況進行調整
if (map.containsKey(s.charAt(j))) {//當發現重複的字符時,將字符的索引與窗口的左邊進行對比,將窗口的左邊直接跳到該重複字符的索引處
i = Math.max(map.get(s.charAt(j)), i);
}
//記錄子字符串的最大的長度
ans = Math.max(ans, j - i + 1);
//map記錄第一次遍歷到key時的索引位置,j+1,保證i跳到不包含重複字母的位置
map.put(s.charAt(j), j + 1);
}
return ans;
}
}
複製代碼
時間複雜度:O(n)code