# 資訊 :::info - Question: 2444. Count Subarrays With Fixed Bounds - From: Leetcode Daily Challenge 2024.03.31 - Difficulty: Hard ::: --- # 目錄 :::info [TOC] ::: --- # 題目 You are given an integer array `nums` and two integers `minK` and `maxK`. A **fixed-bound subarray** of `nums` is a subarray that satisfies the following conditions: - The minimum value in the subarray is equal to `minK`. - The maximum value in the subarray is equal to `maxK`. Return the number of fixed-bound subarrays. A **subarray** is a contiguous part of an array. > Example 1: :::success * Input: `nums = [1,3,5,2,7,5]`, `minK = 1`, `maxK = 5` * Output: 2 * Explanation: The fixed-bound subarrays are `[1,3,5]` and `[1,3,5,2]`. ::: > Example 2: :::success * Input: `nums = [1,1,1,1]`, `minK = 1`, `maxK = 1` * Output: 10 * Explanation: Every subarray of nums is a fixed-bound subarray. There are 10 possible subarrays. > Constraints: :::success * 2 <= `nums.length` <= 105 * 1 <= `nums[i]`, `minK`, `maxK` <= 106 ::: --- # 解法 ## 概念 難了這次,昨天還說自己是 sliding window 大師,結果今天直接撞牆,看到題目還以為多一個 pointer 可以解出來,不過看起來是有一些東西沒考慮到,sliding window week 應該結束了,下次再碰到這邊的題目要來思考怎麼樣可以生出好且完整的測資! 這次就是看 [solution](https://leetcode.com/problems/count-subarrays-with-fixed-bounds/solutions/3256543/awesome-logic-beginner-friendy-code-in-python) 解出來的,還滿酷的想法,畢竟我為了想這個做法列了一張表一一對應去看所有情況,發現他說的是真的!Divide and Conquer 果真很重要! 來說膝下這題的解法:首先會需要三個 pointer,分別指到最新的 `minK` index、`maxK` index、還有超出範圍的 `bad` 的 index,這三個 index 一開始都指到 -1,代表還沒遇到,而設成 -1 對於解答不受影響,可以看下面表格對應說明。 接著會迭代走訪 `nums` 裡面每一個 element,只要遇到 minK、maxK、或是 bad 就會更改 pointer 的值,至於 ans 怎麼新增,會以 min(minIndex,maxIndex) - bad 的值判斷,如果大於 0 就代表有心區間可以新增,那就把算出來的區間數加上去,否則代表沒有區間可以新增,就會是 +0,當然我沒把 +0 寫出來就是了 : ),這部分詳細可以看表格,表格有把所有情況寫出來 | Situation | min<br>Index | max<br>Index | bad | Result | 計算過程 | `ans` 往上加 | | :-- | :-- | :-- | :-- | :-- | :-- | :-- | | 目前只遇到 `(minK, maxK)` 區間內的數字 | -1 | -1 | -1 | 沒有東西可以加 | (-1)-(-1)| 0 | | 遇到 `minK` 而已 | V | -1 | -1 | 沒有東西可以加 | (-1)-(-1) | 0 | | 遇到 `minK` 而已 | -1 | V | -1 | 沒有東西可以加 | (-1)-(-1) | 0 | | 遇到超出範圍的 | -1 | -1 | V | 沒有東西可以加 | (-1)-(-1) | 0 | | 合法 interval<br>從頭開始有包含這段的都可以 | 大 | 小 | -1 | `[(0:小):(大:i)]` | 小+1 | 小+1 | | 合法 interval<br>從頭開始有包含這段的都可以 | 小 | 大 | -1 | `[(0:小):(大:i)`] | 小+1 | 小+1 | | 不合法 interval<br>少了 `maxK` | 大 | -1 | 小 | 沒有東西可以加 | -1-小 | 0 | | 不合法 interval<br>少了 `maxK` | 小 | -1 | 大 | 沒有東西可以加 | -1-小 | 0 | | 不合法 interval<br>少了 `minK` | -1 | 大 | 大 | 沒有東西可以加 | -1-小 | 0 | | 不合法 interval<br>少了 `minK` | -1 | 小 | 小 | 沒有東西可以加 | -1-小 | 0 | | 合法 interval<br>從 bad 之後開始有包含這段都行 | 大 | 中 | 小 | `[(小:中):(大:i)]` | 中-小| 中-小 | | 不合法 interval<br>`bad` 是程咬金 | 大 | 小 | 中 | 沒有東西可以加 | 小-中 | 0 | | 合法 interval<br>從 bad 之後開始有包含這段都行 | 中 | 大 | 小 | `[(小:中):(大:i)]` | 中-小 | 中-小 | | 不合法 interval<br>`bad` 是程咬金 | 中 | 小 | 大 | 沒有東西可以加 | 小-大 | 0 | | 不合法 interval<br>`bad` 是程咬金 | 小 | 大 | 中 | 沒有東西可以加 | 小-中 | 0 | | 不合法 interval<br>`bad` 是程咬金 | 小 | 中 | 大 | 沒有東西可以加 | 小-大 | 0 | 這邊最後有一個要回答的問題,會不會有重新計算的區間?因為新的一輪如果 interval 都沒有改變,不就代表會重新計算?這個答案當然是 No,因為上面柿子的計算只有在計算個數,當 pointer 沒有改變,代表該輪數字出現在 (`minkK`,`maxK`) 區間內,等於這輪計算的是到該輪數字的 subarray,並沒有多算! ## 程式碼 ```python= class Solution: def countSubarrays(self, nums: List[int], minK: int, maxK: int) -> int: ans = 0 minIndex = -1 maxIndex = -1 bad = -1 for i in range(len(nums)): if nums[i] == minK: minIndex = i if nums[i] == maxK: maxIndex = i if nums[i] < minK or nums[i] > maxK: bad = i tmp = min( minIndex, maxIndex ) - bad if tmp > 0: ans += tmp return ans ``` --- # 複雜度 ## 時間複雜度 就是走過 `nums`,所以是 $O(n)$ ![TimeComplexity20240331](https://hackmd.io/_uploads/BkJi8wI1C.png =80%x) ## 空間複雜度 空間其實也指又記錄這三個 pointer 和一點點其他 variable,所以是 $O(1)$ ![SpaceComplexity20240331](https://hackmd.io/_uploads/ryVhUvI1A.png =80%x) # Congratulations! > 拿到三月的 streak badge 了! ![image](https://hackmd.io/_uploads/BkEF8P8J0.png =80%x)