---
# System prepended metadata

title: 2444. Count Subarrays With Fixed Bounds
tags: [queue, leetcode, sliding window, monotonic queue]

---

# 資訊

:::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)
