560. 和為 K 的子陣列
題目連結
題目描述
程式碼實現
分析:
-
暴力:還是有點技巧的,如果單純暴力,外層fori迴圈遍歷起始下標start,內層forj迴圈遍歷末尾end,裡面還需要個迴圈,計算從i加到j,最壞會到\(O(n^3)\)。考慮固定某一個邊界,比如固定end,從end往前算。
點選檢視程式碼
class Solution { public int subarraySum(int[] nums, int k) { int count = 0; for (int i = 0; i < nums.length; i ++){ int sum = 0; for (int j = i ; j >= 0; j--) { // 暴力 從後累加, 可以用到前一次的累加結果,有點像dp揹包內迴圈遍歷順序的討論 sum += nums[j]; if (sum == k){ count++; } } } return count; } }
-
字首和,類似1.兩數之和
程式碼:
// 字首和
class Solution {
public int subarraySum(int[] nums, int k) {
int count = 0;
Map<Integer, Integer> map = new HashMap<>();
int len = nums.length;
int[] preSum = new int[len + 1];
preSum[0] = 0;
for (int i = 0; i < len; i++) {
preSum[i + 1] = preSum[i] + nums[i];
}
for (int i = 0; i < nums.length; i++){
// i 為0的時候, 就是計算 字首子陣列相加就是k的情況。
// 字首子陣列的意思就是 從陣列最開始到j的位置。[0,j]
for(int j = i; j < nums.length; j++){
// [i,j] 相加為k
if(preSum[j+1] - preSum[i] == k){
count++;
}
}
}
return count;
}
// 字首和 + 雜湊表
class Solution {
public int subarraySum(int[] nums, int k) {
int count = 0;
Map<Integer, Integer> map = new HashMap<>();
int sum = 0;
map.put(0,1); // 初始化字首和為0的次數為1, 也是一樣的到裡,當字首子陣列和為k的時候,需要計數1次
for (int i = 0; i < nums.length; i++){
// 這裡的i相當於是 字首和 解法中的j, 是右邊界,sum - (sum - k) == k, 只需要在遍歷到sum的時候
// 看看此時的sum-k裡的個數就行,也就是[left, i]中left的個數,在遍歷的過程中,map裡記錄了left的個數
sum += nums[i];
if (map.containsKey(sum - k)) {
count += map.get(sum - k);
}
map.put(sum, map.getOrDefault(sum, 0) + 1);
}
return count;
}
}
239. 滑動視窗最大值
題目連結
題目描述
程式碼實現
分析:
- 使用一個單調佇列完成,Deque來模擬單調佇列。佇列的順序是從大到小。每次滑動視窗的過程可以分解為兩個步驟:
- 左邊界元素移出:移出時只需要判斷一下是否是當前佇列前端元素(最大值),如果是就移出佇列。不是就說明移除的元素不是當前視窗的最大值,不做操作。
- 新增元素:新增元素時要判斷加進來的元素與單調佇列中的大小關係,按照約定的順序,從佇列尾部一個一個比較,佇列尾部開始,比它小的元素都彈出,直到遇到大於等於這個新進來的元素時,加入隊尾。
程式碼:
class Solution {
public int[] maxSlidingWindow(int[] nums, int k) {
Deque<Integer> stack = new LinkedList<>();
int n = nums.length;
// 初始化單調棧 棧頭->棧底: 大->小 小的並不是完全不要,而是捨去比新加進來的元素小的元素
for(int i = 0; i < k; i++){
while(!stack.isEmpty() && nums[i] > stack.peekLast()){
stack.pollLast();
}
stack.offerLast(nums[i]);
}
int[] res = new int[n-k+1];
res[0] = stack.peekFirst();
// 模擬滑動視窗
for(int i = k; i < n; i++){
// 視窗左邊界:當前需要移除視窗的元素
if(nums[i-k] == stack.peekFirst()){
stack.pollFirst();
}
// 視窗右邊新加進來的元素需要和棧內元素進行比較 這裡不能用>=,因為可能有重複元素
while(!stack.isEmpty() && nums[i] > stack.peekLast()){
stack.pollLast();
}
stack.offerLast(nums[i]);
res[i-k+1] = stack.peekFirst();
}
return res;
}
}
76. 最小覆蓋子串
題目連結
題目描述
程式碼實現
分析:
程式碼: