1.題目描述
把字符串 s 看作是 “abcdefghijklmnopqrstuvwxyz” 的無限環繞字符串,所以 s 看起來是這樣的:
"...zabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcd...." .
現在給定另一個字符串 p 。返回 s 中 唯一 的 p 的 非空子串 的數量 。
示例 1:
輸入: p = "a"
輸出: 1
解釋: 字符串 s 中只有一個"a"子字符。
示例 2:
輸入: p = "cac"
輸出: 2
解釋: 字符串 s 中的字符串“cac”只有兩個子串“a”、“c”。.
示例 3:
輸入: p = "zab"
輸出: 6
解釋: 在字符串 s 中有六個子串“z”、“a”、“b”、“za”、“ab”、“zab”。
2.思路
2.1 代碼
題目要求在字符串中找到連續子數組個數,其實就是在遍歷數組時,求以當前字符結尾的連續子串長度,然后再把數組中每一位對應的子串長度加起來求和便是最終答案。這里一下幾點需要注意:
- 重復字符的問題。出現重復字符時,對比子串長度,以最長的為結果,并最終結果只計算一次;
- 題目使用環形字符串,因此當遍歷到 a 時,如果前一位是 z ,那么就需要在前一位基礎上繼續往下算,即子串長度繼續加 1;
- 當當前位與前一位不連續時,這個時候子串長度應當從 1 開始重新計算
以 “zab” 為例進行說明:
- 遍歷 i=0 時,此時以 z 為結尾的連續子串只有 z ,因此統計個數為 1(z);
- 遍歷 i=1 時,此時以 a 為結尾的連續子串為 za,因為是環形數組,所以 z 之后應該繼續從 a 開始,此時統計個數為2(a,za);
- 遍歷 i=2 時,此時以 b為結尾的連續子串為 zab,因此統計個數為3(b,ab,zab);
- 最后將三個字符對應的最長子串個數加起來等于 6 ,便是最終答案。
再以 “aabb” 為例說明存在重復字符時的處理過程:
- 遍歷 i=0 時,此時以 a 為結尾的連續子串只有 a ,因此統計個數為 1(a);
- 遍歷 i=1 時,此時以 a 為結尾的連續子串為 a,此時子串個數為 1 ,但是因為前面出現過 a ,兩個子串個數都是 1 ,因此以 a 為結尾的連續子串個數為 1(a);
- 遍歷 i=2 時,此時以 b為結尾的連續子串為 ab,因此統計個數為2(b,ab);
- 遍歷 i=3 時,此時以 b 為結尾的連續子串為 b,長度為 1(b),但是前面出現過一次 b,因此選擇兩個子串中個數較大的作為以 b 結尾的子串,最終結果為 2;
- 遍歷完成得到最終答案是 3。
代碼中使用一 26 位的數組存放各個字符子串長度,count 統計子串長度,當不連續時,count 重置為 1,代碼如下:
class Solution {
public int findSubstringInWraproundString(String p) {
char[] chars = p.toCharArray();
int[] tmp = new int[26];
tmp[chars[0] - 'a'] = 1;
int count = 1;
for (int i = 1; i < chars.length; i++) {
if (chars[i] == chars[i - 1] + 1 || (chars[i] == 'a' && chars[i - 1] == 'z')) {
count++;
} else {
count = 1;
}
tmp[chars[i] - 'a'] = Math.max(count, tmp[chars[i] - 'a']);
}
int ans = 0;
for (int i = 0; i < 26; i++) {
ans += tmp[i];
}
return ans;
}
}
2.2 測試結果
通過測試
測試結果
3.總結
- 題目轉換為求以字符結尾的連續子串長度更容易解答
- 使用 tmp 數組統計每一位字符為結尾的連續子數組個數
- 當存在不連續的時候,count 重置為 1
- 這道題其實挺難的,主要很容易陷入慣性思維,從頭開始往后迭代進行字符判斷,但是一旦把思維轉換過來后所有問題都迎刃而解了