713-乘積小于K的子數(shù)組-雙指針的妙用

題目

核心思路

對(duì)于求K相關(guān)的子數(shù)組,一種比較常用的方法是計(jì)算前綴和(積),然后通過雙指針來做,不過這道題給的數(shù)的范圍最大的積為1000^50000,實(shí)在是太大了,難以實(shí)行,官方題解給出了一種轉(zhuǎn)化為log函數(shù)相加來防溢出,不過不好理解,若想了解還請(qǐng)看官方題解 713-官解點(diǎn)這里

下面來講解另一種類似的解法,同樣是雙指針,因?yàn)轭}目給出了數(shù)組元素為正整數(shù),故當(dāng)前乘積 product 乘以/除以一個(gè)數(shù)是單調(diào)的,可以使用滑動(dòng)窗口來解題。一個(gè)指針left標(biāo)記窗口左端,right標(biāo)記窗口的右端,乘積大于等于K時(shí),用乘積除以nums[left],然后使得left向前移;若乘積小于K,計(jì)算 left 到 right 滿足條件的子數(shù)組的個(gè)數(shù)即可。大體思路清楚了,還剩下一點(diǎn)就是求 left 到 right 的子數(shù)組的個(gè)數(shù)待解決,我們通過下圖來理解。

我們假設(shè)right之前是沒訪問過的,上圖狀態(tài)即:乘積小于K,且right對(duì)應(yīng)的元素之前沒訪問過。而為了保證每一個(gè)right都是一般的,故right前的元素都假設(shè)之前訪問過,計(jì)算過子數(shù)組的個(gè)數(shù)了,只用計(jì)算包含right的元素的子數(shù)組的個(gè)數(shù)即可。通過圖中圈出的不同顏色,left = 0, right = 4, 子數(shù)組個(gè)數(shù) count = 5 = right - left + 1,這就是所求的公式,不過乍一看總會(huì)感覺容易重復(fù),我們考慮乘積大于等于K時(shí)的情況來驗(yàn)證。
right 向右移,乘積為 4 ^ 6 大于等于K了,故需要將left右移,而右移之后,由于right是未曾訪問過的元素,故圖中圈出的子數(shù)組都是沒有重復(fù)的 right - left + 1 個(gè),所以得到的公式就是通用表達(dá)式,乘積小于K時(shí)都可以進(jìn)行計(jì)算,無論是正常遍歷小于還是left右移之后小于都是滿足條件的。有了思路,有了公式,便可以據(jù)此給出代碼。

完整代碼

public int numSubarrayProductLessThanK(int[] nums, int k) {
        if (k <= 1)
            return 0;
        int count = 0;
        int left = 0, right = 0, n = nums.length;
        int product = 1;//存儲(chǔ)當(dāng)前滑動(dòng)窗口的乘積
        for (; right < n; right++) {
            product *= nums[right];
            while (product >= k)
                product /= nums[left++];
            count += right - left + 1;
        }
        return count;
    }

代碼比較簡潔,不過其中的求每個(gè)滑動(dòng)窗口的子數(shù)組個(gè)數(shù)公式 right - left + 1 不是很好發(fā)現(xiàn),需要仔細(xì)研究。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容