1. 程式人生 > 程式設計 >JavaScript陣列及非陣列物件的深淺克隆詳解原理

JavaScript陣列及非陣列物件的深淺克隆詳解原理

給你一個整數陣列 nums 和一個整數 k。

如果某個 連續 子陣列中恰好有 k 個奇數數字,我們就認為這個子陣列是「優美子陣列」。

請返回這個陣列中「優美子陣列」的數目。

示例 1:

輸入:nums = [1,1,2,1,1], k = 3
輸出:2
解釋:包含 3 個奇數的子陣列是 [1,1,2,1] 和 [1,2,1,1] 。
示例 2:

輸入:nums = [2,4,6], k = 1
輸出:0
解釋:數列中不包含任何奇數,所以不存在優美子陣列。
示例 3:

輸入:nums = [2,2,2,1,2,2,1,2,2,2], k = 2
輸出:16

提示:

1 <= nums.length <= 50000
1 <= nums[i] <= 10^5
1 <= k <= nums.length

解法一:

首先假設陣列中有k個奇數,且陣列的左右兩端都是奇數,比如陣列1,2,2,1,1,k=3,這樣的陣列中,肯定只有1個子陣列滿足題意條件。即陣列本身。

現在考慮在陣列兩端新增一些偶數,比如2,1,2,2,1,1,2,k=3。這樣的陣列可以有4個子陣列滿足題意。即分別加上左邊的0,1個偶陣列成子陣列,加上右邊的0,1個偶陣列成子陣列。

觀察可以得知,在這種條件下,陣列中優美子陣列的個數為(左邊偶數個數+1)*(右邊偶數個數+1)

考慮更一般的情況,我們可以記錄一下陣列中每個奇數的縫隙直接插了多少個偶數。設陣列中奇數總個數為n,則有陣列even[],even[0]表示陣列最左端的偶數個數,even[1]表示第一個奇數和第二個奇數之間的偶數個數,even[n]表示陣列最後一個奇數右端的偶數個數。則第i個奇數左端有even[i-1]個偶數,第i+k個奇數右端有even[k]偶數。迴圈遍歷even陣列即得答案。

點選檢視程式碼
class Solution {
public:
    int numberOfSubarrays(vector<int>& nums, int k) {
        vector<int> even;
        int evenCount = 0, res = 0;
        for(int i = 0; i < nums.size(); i++)
        {
            if(nums[i] % 2)
            {
                even.push_back(evenCount);
                evenCount = 0;
                if(i == nums.size() - 1) even.push_back(evenCount);
            }
            else if(i == nums.size() - 1){
                evenCount++;
                even.push_back(evenCount);
            }
            else    
                evenCount++;
                
        }

        for(int i = 0; i + k < even.size(); i++)
        res += (even[i] + 1) * (even[i + k] + 1);
        
        return res;
    }
};

解法二:

這是leetcode官方的解法,用到字首和的思想。官方解釋很難懂,我的理解是,維護一個變數odd,存放到目前位置i為止陣列中出現奇數的個數。開一個cnt[]陣列,記錄陣列中奇數個數為odd的次數。比如,現在遍歷到nums[i],到i位置的奇數個數為odd,那麼我們就讓odd+1。i這個位置為終點時有多少子陣列滿足優美的條件呢?應該是cnt[odd - k](注意檢查odd - k>=0)。

點選檢視程式碼
class Solution {
public:
    int numberOfSubarrays(vector<int>& nums, int k) {
        vector<int> cnt(nums.size() + 1, 0);
        int odd = 0, res = 0;
        cnt[0] = 1;
        for(int i = 0; i < nums.size(); i++)
        {
            odd += (nums[i] & 1); 
            res += (odd - k >= 0) ? cnt[odd - k] : 0;
            cnt[odd] += 1;
        }
        return res;
    }
};

兩種解法時間複雜度都為o(n)。空間複雜度都為o(n)。下圖中提交時間較早的是解法一。