每日一題 和為k的連續子陣列 字首和與滑窗

2021-10-06 04:33:07 字數 2591 閱讀 3929

2020/05/15 每日一題

對於要求連續子陣列的題目,靈活使用字首和和滑窗的方法。特點在於,字首和是否遞增。

題目需要注意幾個關鍵點,陣列元素是既有正數又有負數的且要求是連續的子陣列

陣列元素既有正數又有負數隱含了意思,陣列不是單調的。因此不適合用滑動視窗的方法。**滑窗特點是,固定了左邊界以後,右邊界找到了乙個可行解以後,右邊界再靠右邊的更大的區間肯定不存在目標值,所以才將左邊界繼續向右滑。**在這道題裡顯然沒有這個性質。

其次,這裡的連續子陣列的限制給了我們採用字首和的空間。我們儲存字首和進行比較即可。

要求presum[i]-k = presum[j]也就是存在[j+1,i]這個子區間的和為k。

class

solution

:def

subarraysum

(self, nums: list[

int]

, k:

int)

->

int:

## 看到陣列中有連續子陣列,因此考慮字首和的思路

dic = collections.defaultdict(

int)

dic[0]

=1sum_ =

0 ans =

0for num in nums:

sum_ += num

if sum_ - k in dic:

ans += dic[sum_-k]

# 這裡需要注意,先判斷再存入當前的數值。否則可能出現問題

和上面題目很相似的題目,但是特點在於上一題是查詢到特定的數值即可。這道題目的要求是得到被k整除。因此我們雖然採用字首和的思路,但是記錄的並不是字首和,而是字首和對k取餘的結果。

注意負數的同餘,-2%6 = 4,這裡不需要額外的處理。

class

solution

:def

subarraysdivbyk

(self, a: list[

int]

, k:

int)

->

int:

# dic儲存被5除完的餘數

這道題目就存在顯著的不同了,首先要求的了是正整數,也就是實現了字首和是單調的。但是要求查詢的難度變大了,需要找出小於某一數值的字首和,所以再採用字首和的思路就複雜度增加了,每次需要遍歷所有的字首和,才能找全符合小於的數字。

但是我們知道了單調的特性,就可以採用滑動視窗的方法,固定左側,每次向右側擴張。如果超過了,就移動左側邊界。

兩個細節:

如何統計合理解?採用right-left+1,也就是固定了右側時,我們可以移動左側界,得到的全都是合理解。

移動左側邊界的方法。我們需要每次移動左側邊界最多移動到大於右側乙個,這樣可以幫助右側處理掉某乙個元素自身就大於bar的情況。

class

solution

:def

numsubarrayproductlessthank

(self, nums: list[

int]

, k:

int)

->

int:

# 對於這種單調增的序列,可以採用滑動視窗的方法

n =len(nums)

right =

0 left =

0 cur =

1 ans =

0for right, num in

enumerate

(nums)

: cur *= num

while cur>=k and left<=right:

cur /= nums[left]

left +=

1 ans += right-left+

1return ans

letcode每日一題 分割陣列為連續子串行

題目描述如下 對於陣列中的元素 x,如果存在乙個子串行以 x 1 結尾,則可以將 x加入該子串行中。將 x 加入已有的子串行總是比新建 乙個只包含 x 的子串行更優,因為前者可以將乙個已有的子串行的長度增加 1,而後者新建乙個長度為 1 的子串行,而題 目要求分割成的子串行的長度都不小於 3,因此應...

leetcode每日一題5 15和為K的子陣列

給定乙個整數陣列和乙個整數 k,你需要找到該陣列中和為 k 的連續的子陣列的個數。示例 1 輸入 nums 1,1,1 k 2 輸出 2 1,1 與 1,1 為兩種不同的情況。說明 陣列的長度為 1,20,000 陣列中元素的範圍是 1000,1000 且整數 k 的範圍是 1e7,1e7 思路 這...

字首和 和為k的連續子陣列

給定乙個整數陣列和乙個整數k,你需要找到該陣列中和為k的連續的子陣列的個數。示例輸入 nums 1,1,1 k 2 輸出 2 1,1 與 1,1 為兩種不同的情況。此題暴力法則為求出每一段連續的子陣列的和,然後遍歷這些和求出和為k的陣列個數 一段連續的數必然有乙個左邊界和乙個右邊界,所以只要列舉所有...