leetcode 第713題 乘積小於K的子數組 python解法

leetcode 第713題 乘積小於K的子數組 python解法

題目解析

在這裏插入圖片描述
開始拿到這個題目的時候,我首先想到的是用動態規劃來求解,建立一個二位數組dp,其中dp[i][j]代表的是數組中下標爲i到j所有的數累乘的結果,狀態轉移方程也比較好些,兩層循環。外層循環遍歷整個數組,內層循環遍歷外層循環的值到數組最後一位的所有值。dp[i][j] = dp[i][j-1] * nums[j] (j爲內層遍歷的值)。
這樣很快就寫出來了,但是提交時(嘣,瞎卡拉卡)— 空間超了限制,因爲有二維數組的存在,所以當給的數組很大時,很容易超過空間限制。
後面我看了一下狀態轉移方程,當前位置的值只與前面一個位置的值有關,而且每個位置的數只會被用過一次,所以完全可以不用建立二維數組,直接用一個臨時變量來存儲前一個位置的數,這樣空間就降到了常數級別。即用post = prev*nums[j],然後判斷post是否大於k,如果大於等於k,立刻結束內層循環。後來又想了一下改進的方法,就是在內層遍歷的時,先直接從當前位置向後累乘,直到乘積大於等於k時,結束內層循環。最後將結束的位置j減去剛開始的位置i,並將最後的結果加上返回值ret中(即ret+=j-i)。
就這樣我又提交了(嘣,瞎卡拉卡)— 時間超了限制,有一個測試用例裏全部都是1,而且很多。1作爲因數比較特別。所以我就想先將所以的連續1記錄下來,即在外層循環中判斷連續1的個數,假設有ones個連續1,那麼這些1首先能夠組成的連續1的數組個數爲(ones+1)xones / 2,這個數直接加上返回數組ret上,然後繼續向後遍歷。如果前面有連續1的存在,那麼在前面的基礎上做如下操作(j-i)x(ones+1),這樣就把前面1的作用算上了。
這麼寫最後終於通過了測試,但是還是比較慢,只超過了一半的提交。
我又看了前面運行比較快的解答,豁然開朗,覺得自己寫的就是shit。解法如下:
首先在外層循環中將數組的數累乘,每做一乘法後,先判斷乘積是否大於k,如果小於k,在返回數組上直接加上該位置的與前面數組成數組的個數(假設當前位置爲j,第一個因數的位置爲i,那麼當前位置能夠組成的連續數組個數爲j-i+1。如果乘積大於等於k,那麼先除去第一個因數,並將i加1,如果仍然大於等於k,繼續去除第一個因數(就是i代表的數)。直到乘積小於k或i==j(說明這個數nums[j]就是大於k的),返回外層循環,繼續上面的操作。

源碼

動態規劃

class Solution(object):
    def numSubarrayProductLessThanK(self, nums, k):
        """
        :type nums: List[int]
        :type k: int
        :rtype: int
        """
        n = len(nums)
        ret = 0
        dp = [[nums[i] if i == j else 0 for i in range(n)] for j in range(n)]
        for i in range(n):
            if dp[i][i] < k:
                ret += 1
            for j in range(i+1, n):
                dp[i][j] = dp[i][j-1] * dp[j][j]
                ret += 1 if dp[i][j] < k else 0
        return ret

改進動態規劃,並對連續1進行處理

class Solution(object):
    def numSubarrayProductLessThanK(self, nums, k):
        """
        :type nums: List[int]
        :type k: int
        :rtype: int
        """
        ret = 0
        if k > 1:
            n = len(nums)
            ones = 0
            for i in range(n):
                if nums[i] == 1 and i < n:
                    ones += 1
                    continue
                if ones != 0:
                    ret += (1 + ones) * ones // 2
                if nums[i] < k:
                    product = 1
                    j = i
                    while j < n and product * nums[j] < k:
                        product *= nums[j]
                        j += 1
                    ret += (j - i) * (ones + 1) if ones != 0 else j - i
                ones = 0
            if ones != 0:
                ret += (1 + ones) * ones // 2
        return ret

別人寫的,最快

class Solution(object):
    def numSubarrayProductLessThanK(self, nums, k):
        """
        :type nums: List[int]
        :type k: int
        :rtype: int
        """
        ret, product, prev = 0, 1, 0
        n = len(nums)
        for i in range(n):
            product *= nums[i]
            while product >= k and prev <= i:
                product //= nums[prev]
                prev += 1
            ret += i - prev + 1
        return ret

寫的很亂,今天臘月二十九,有點心不在焉。

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章