子串
- 子串要求連續,與子序列不同,子序列不要求連續。
和為k的字串
給你一個整數陣列 nums 和一個整數 k ,請你統計並返回 該陣列中和為 k 的子陣列的個數。
子陣列是陣列中元素的連續非空序列
- 方法
https://www.bilibili.com/video/BV1gN411E7Zx/?spm_id_from=333.337.search-card.all.click&vd_source=c1e82f2c861119afab65688242bdf6f3
1.求出字首和陣列sums[i],sum[i] = sums[i-1]+nums[i]
2.若nums[i]=10,k為6,且字首和中出現了2次4,則可以確定的是,每一個字首和為4的元素之後起到i的和即為我們想要的子串
3.藉助雜湊表,鍵為各個字首和,值為當前該字首和出現的次數
class Solution {
public int subarraySum(int[] nums, int k) {
int n = nums.length;
int[] sums = new int[n];
sums[0] = nums[0];
for (int i = 1; i < n; i++) {
sums[i] = sums[i-1] + nums[i];
}
HashMap<Integer, Integer> map= new HashMap<>();
map.put(0,1);
int count = 0;
for (int i = 0; i < n; i++) {
count+=map.getOrDefault(sums[i]-k,0);//map.getOrDefault若查詢失敗會返回預設值而不是null
map.put(sums[i],map.getOrDefault(sums[i],0)+1);
}
return count;
}
}
滑動視窗最大值
- 方法
1.維護一個單調遞減棧,即棧底為當前棧內最大的元素,且保證棧內的元素一定在當前遍歷的視窗內;
2.視窗每向後移動一次,首先要維護棧內的遞減性,然後還要將左側超出視窗外的元素在棧中移除。
將視窗外的元素移除,分為兩種情況:
a.要移除的是當前最大值,則我們要pollLast()
,移除棧底
b.要移除的不是當前最大值,說明在之前已經被彈出過。
換句話說,我們可以判斷當前棧底元素下標是否在視窗內(deque.peekLast() <= (i-k)
),若在則deque.pollLast()
,否則直接跳過。
class Solution {
public int[] maxSlidingWindow(int[] nums, int k) {
int n = nums.length;
if (n == 0) {
return new int[0];
}
int[] res = new int[n - k + 1];
Deque<Integer> deque = new LinkedList<>();
for (int i = 0; i < n; i++) {
//保證棧內從棧頂到棧底為遞增的(first為棧頂)
//peek == peekFirst
while (!deque.isEmpty() && nums[i] > nums[deque.peek()]) {
deque.pop();//pop == pollFirst
}
deque.push(i); //push == addFirst
if(i>=k){
//移除視窗外的元素
if(deque.peekLast() <= (i-k)){
deque.pollLast();
}
}
if (i >= k - 1) {
//記錄結果
res[i - k + 1] = nums[deque.peekLast()];
}
}
return res;
}
}
最小覆蓋子串
給你一個字串 s 、一個字串 t 。返回 s 中涵蓋 t 所有字元的最小子串。如果 s 中不存在涵蓋 t 所有字元的子串,則返回空字串 "" 。
注意:
對於 t 中重複字元,我們尋找的子字串中該字元數量必須不少於 t 中該字元數量。
如果 s 中存在這樣的子串,我們保證它是唯一的答案。
- 分析
前面已經做過幾道關於異位詞的題目,若只關心字串的原材料,我們可以利用一個陣列來描述一個字串的資訊。
此處若s 中的子串涵蓋 t 所有字元,則該子串的每個原材料數量一定不小於t。 - 方法
維護一個視窗,右邊界一直向後擴張,擴張到子串的每個原材料數量都不小於t,即包含t,然後再從左側縮小,每縮小一次就判斷子串是否仍然包含t,直至縮小至不包含,為避免後續有更短的包含t的子串,要繼續向後擴張至包含t,再從左側縮小,在這個同時要維護一對最終結果的左右邊界,直至左邊界或右邊界越界
class Solution {
public String minWindow(String s, String t) {
int[] count_t = count(t);
int[] count_s = new int[128];
int l = 0;
int r = -1;
int l_res = 0;
int r_res = Integer.MAX_VALUE;
while(l < s.length()){
if(has(count_s,count_t)){
if(r-l < r_res-l_res){
l_res = l;
r_res = r;
}
count_s[s.charAt(l)]--;
l++;
}else {
if(r==s.length()-1){
break;
}
r++;
count_s[s.charAt(r)]++;
}
}
return r_res==Integer.MAX_VALUE ? "" : s.substring(l_res,r_res+1);
}
public int[] count(String s){
int[] counts = new int[128];
char[] chars = s.toCharArray();
for (char c: chars) {
counts[c]++;
}
return counts;
}
public boolean has(int[] s,int[] t){
for (int i = 0; i < 128; i++) {
if(s[i]<t[i]){
return false;
}
}
return true;
}
}