title: Arithmetic Subarrays
slug: arithmetic-subarrays
difficulty: medium
leetcode_id: 1630
leetcode_url: https://leetcode.com/problems/arithmetic-subarrays/
categories:
  - arrays
  - hash-tables
  - sorting
patterns:
  - two-pointers

description: |
  A sequence of numbers is called **arithmetic** if it consists of at least two elements, and the difference between every two consecutive elements is the same. More formally, a sequence `s` is arithmetic if and only if `s[i+1] - s[i] == s[1] - s[0]` for all valid `i`.

  For example, these are **arithmetic** sequences:
  - `1, 3, 5, 7, 9`
  - `7, 7, 7, 7`
  - `3, -1, -5, -9`

  The following sequence is **not** arithmetic: `1, 1, 2, 5, 7`

  You are given an array of `n` integers, `nums`, and two arrays of `m` integers each, `l` and `r`, representing the `m` range queries, where the i<sup>th</sup> query is the range `[l[i], r[i]]`. All the arrays are **0-indexed**.

  Return *a list of boolean elements* `answer`, *where* `answer[i]` *is* `true` *if the subarray* `nums[l[i]], nums[l[i]+1], ..., nums[r[i]]` *can be **rearranged** to form an **arithmetic** sequence, and* `false` *otherwise*.

constraints: |
  - `n == nums.length`
  - `m == l.length`
  - `m == r.length`
  - `2 <= n <= 500`
  - `1 <= m <= 500`
  - `0 <= l[i] < r[i] < n`
  - `-10^5 <= nums[i] <= 10^5`

examples:
  - input: "nums = [4,6,5,9,3,7], l = [0,0,2], r = [2,3,5]"
    output: "[true, false, true]"
    explanation: "In the 0th query, the subarray [4,6,5] can be rearranged as [4,5,6], an arithmetic sequence with difference 1. In the 1st query, the subarray [4,6,5,9] cannot form an arithmetic sequence. In the 2nd query, the subarray [5,9,3,7] can be rearranged as [3,5,7,9], an arithmetic sequence with difference 2."
  - input: "nums = [-12,-9,-3,-12,-6,15,20,-25,-20,-15,-10], l = [0,1,6,4,8,7], r = [4,4,9,7,9,10]"
    output: "[false, true, false, false, true, true]"
    explanation: "Each query is evaluated independently to check if the subarray can be rearranged into an arithmetic sequence."

explanation:
  intuition: |
    Think of an arithmetic sequence like evenly spaced fence posts along a straight line. If you have posts at positions 3, 5, 7, 9, the spacing (common difference) is exactly 2 between each consecutive pair.

    Now imagine someone scatters those fence posts randomly on the ground. Your task is to determine: *can these posts be arranged back into a straight line with equal spacing?*

    The key insight is that in a valid arithmetic sequence:
    - The **common difference** `d` is determined by `(max - min) / (n - 1)` where `n` is the number of elements
    - Every element must be exactly `min + k*d` for some integer `k` from `0` to `n-1`
    - Each position `k` must be filled by exactly one element

    This means we can use a **set-based approach**: calculate what the common difference should be, then verify that every required value exists in the subarray. If any value is missing or duplicated unexpectedly, it's not arithmetic.

  approach: |
    For each query, we extract the subarray and check if it can form an arithmetic sequence.

    **Step 1: Extract the subarray**

    - Get the subarray `nums[l[i]:r[i]+1]` for the current query
    - Find the `min_val` and `max_val` of this subarray

    &nbsp;

    **Step 2: Calculate the expected common difference**

    - The common difference `d = (max_val - min_val) / (length - 1)`
    - If `length` is 1 or 2, it's always arithmetic (any two numbers form an arithmetic sequence)
    - If `(max_val - min_val)` is not evenly divisible by `(length - 1)`, return `false`

    &nbsp;

    **Step 3: Verify all expected values exist**

    - Create a set from the subarray elements for O(1) lookups
    - For each expected value `min_val + i*d` where `i` ranges from `0` to `length-1`:
      - Check if it exists in the set
      - If any expected value is missing, the sequence is not arithmetic

    &nbsp;

    **Step 4: Return the result**

    - If all expected values exist, return `true`
    - The set automatically handles the uniqueness requirement (since we check exact count via the calculation)

    &nbsp;

    An alternative approach is to simply **sort the subarray** and check if consecutive differences are equal. This is simpler but slightly slower at O(k log k) per query vs O(k) for the set approach.

  common_pitfalls:
    - title: Forgetting Integer Division Check
      description: |
        When calculating the common difference `d = (max - min) / (n - 1)`, you must verify that this division is exact (no remainder).

        For example, with `[1, 2, 4]`: `max = 4`, `min = 1`, `n = 3`. The expected `d = (4-1)/(3-1) = 1.5`. Since `d` is not an integer, this cannot be an arithmetic sequence of integers.

        Always check `(max - min) % (n - 1) == 0` before proceeding.
      wrong_approach: "Using floating-point division without checking remainder"
      correct_approach: "Check divisibility first, then use integer division"

    - title: Not Handling the All-Equal Case
      description: |
        When all elements are equal (e.g., `[7, 7, 7, 7]`), the common difference is `0`. This is a valid arithmetic sequence!

        The formula `d = (max - min) / (n - 1) = 0 / (n - 1) = 0` correctly handles this, but some implementations might have edge case bugs when `d = 0`.
      wrong_approach: "Special-casing when all elements are equal"
      correct_approach: "Let the formula naturally handle d = 0"

    - title: Duplicate Elements Breaking the Set Approach
      description: |
        If the subarray contains duplicates like `[1, 3, 3, 5]`, the set will have fewer elements than the original subarray length.

        However, this is implicitly handled: if there are unexpected duplicates, either the divisibility check fails or some expected value won't exist in the set.
      wrong_approach: "Forgetting to account for duplicates in set size"
      correct_approach: "The algorithm naturally rejects invalid duplicates through the verification step"

  key_takeaways:
    - "**Set for O(1) lookups**: Converting a subarray to a set enables constant-time membership checks, turning O(k^2) verification into O(k)"
    - "**Mathematical invariant**: Arithmetic sequences have a deterministic structure — once you know min, max, and length, you know exactly what values must exist"
    - "**Sorting alternative**: For simpler code, sorting the subarray and checking consecutive differences works well for small inputs"
    - "**Range query pattern**: This problem demonstrates a common pattern where you process multiple independent subarray queries"

  time_complexity: "O(m * k) where `m` is the number of queries and `k` is the average subarray length. Each query requires O(k) to extract the subarray, find min/max, and verify values."
  space_complexity: "O(k) where `k` is the maximum subarray length. We store each subarray in a set for O(1) lookups."

solutions:
  - approach_name: Set-Based Verification
    is_optimal: true
    code: |
      def check_arithmetic_subarrays(nums: list[int], l: list[int], r: list[int]) -> list[bool]:
          def is_arithmetic(arr: list[int]) -> bool:
              n = len(arr)
              # Any sequence of length 1 or 2 is arithmetic
              if n <= 2:
                  return True

              min_val, max_val = min(arr), max(arr)

              # All elements are equal — valid arithmetic sequence with d=0
              if min_val == max_val:
                  return True

              # Check if common difference would be an integer
              if (max_val - min_val) % (n - 1) != 0:
                  return False

              # Calculate the common difference
              d = (max_val - min_val) // (n - 1)

              # Use a set for O(1) lookups
              num_set = set(arr)

              # Check that all expected values exist
              for i in range(n):
                  expected = min_val + i * d
                  if expected not in num_set:
                      return False

              return True

          # Process each query
          result = []
          for i in range(len(l)):
              # Extract subarray for this query
              subarray = nums[l[i]:r[i] + 1]
              result.append(is_arithmetic(subarray))

          return result
    explanation: |
      **Time Complexity:** O(m * k) — For each of `m` queries, we do O(k) work to extract the subarray, find min/max, build the set, and verify all expected values.

      **Space Complexity:** O(k) — We create a set of size `k` for each subarray.

      This approach leverages the mathematical property that an arithmetic sequence is fully determined by its min, max, and length. We verify by checking that every expected value exists in O(1) time using a set.

  - approach_name: Sorting
    is_optimal: false
    code: |
      def check_arithmetic_subarrays(nums: list[int], l: list[int], r: list[int]) -> list[bool]:
          def is_arithmetic(arr: list[int]) -> bool:
              # Sort the array to get elements in order
              sorted_arr = sorted(arr)
              n = len(sorted_arr)

              # Any sequence of 1 or 2 elements is arithmetic
              if n <= 2:
                  return True

              # Calculate the common difference from first two elements
              d = sorted_arr[1] - sorted_arr[0]

              # Check all consecutive pairs have the same difference
              for i in range(2, n):
                  if sorted_arr[i] - sorted_arr[i - 1] != d:
                      return False

              return True

          # Process each query
          result = []
          for i in range(len(l)):
              subarray = nums[l[i]:r[i] + 1]
              result.append(is_arithmetic(subarray))

          return result
    explanation: |
      **Time Complexity:** O(m * k log k) — Sorting dominates at O(k log k) per query.

      **Space Complexity:** O(k) — Sorting requires O(k) space.

      This is the most intuitive approach: sort the subarray and verify that all consecutive differences are equal. While slightly slower than the set-based approach, it's simpler to understand and implement. For the given constraints (`n, m <= 500`), both approaches are efficient enough.
