題目:
給你一個字符串 S、一個字符串 T,請在字符串 S 裏面找出:包含 T 所有字符的最小子串。
示例:
輸入: S = "ADOBECODEBANC", T = "ABC"
輸出: "BANC"
說明:
- 如果 S 中不存這樣的子串,則返回空字符串
""
。 - 如果 S 中存在這樣的子串,我們保證它是唯一的答案。
前兩天準備答辯的事情,加上兩道題目自己剛好做過,所以又咕咕了兩天,以後把博客補上,那個啥馬拉車算法一直不是很懂。
今天的題也是沒自己做出來,看了提示一之後知道用滑動窗口解,最開始用的是C寫,本地調試沒問題,但是LeetCode老是報堆棧溢出錯誤,估計是在截取字符串上的錯誤,後面用Java寫好了,但是在如何判斷窗口包含T所有字符的最小字串上寫的特別爛,用的是Hashmap,效率奇差。後面看了看官方的題解,這讓我想到幾天前的自己,可以用數組表示的來用Hashmap存儲,這一點就會讓效率特別低,因爲查字符串的ASCII碼就知道用128個數就能記錄題目的所有字符了,這裏用數組存儲明顯更好,而官方題解對於如何判斷窗口包含T所有字符的最小字串感覺也一般,後面就在題解裏邊找,下面貼一個我覺得寫的最好的
代碼:
class Solution {
public static String minWindow(String s, String t) {
//用來統計t中每個字符出現次數
int[] needs = new int[128];
//用來統計滑動窗口中每個字符出現次數
int[] window = new int[128];
for (int i = 0; i < t.length(); i++) {
needs[t.charAt(i)]++;
}
int left = 0;
int right = 0;
String res = "";
//目前有多少個字符
int count = 0;
//用來記錄最短需要多少個字符。
int minLength = s.length() + 1;
while (right < s.length()) {
char ch = s.charAt(right);
window[ch]++;
if (needs[ch] > 0 && needs[ch] >= window[ch])
count++;
//移動到不滿足條件爲止
while (count == t.length()) {
ch = s.charAt(left);
if (needs[ch] > 0 && needs[ch] >= window[ch])
count--;
if (right - left + 1 < minLength) {
minLength = right - left + 1;
res = s.substring(left, right + 1);
}
window[ch]--;
left++;
}
right++;
}
return res;
}
}
這個的判決條件做的很高明,自己寫過之後就知道必須處理多餘字符的情況,第一個“needs[ch] > 0 && needs[ch]”,第一個是大於零時爲了排除s含有但t不含有的字符, 第二個是爲了防止窗口裏含有的字母數大與t的字符數,s=abbcd,t=bcd時的b字符; 兩個判斷都是爲了排除多餘字符,防止窗口並沒有t中的所有字母提前進入while循環,第二個“needs[ch] > 0 && needs[ch]”也類似。
運行結果:
今天是失敗的一天,過一段時間再回頭看看