title: Check if Array Is Sorted and Rotated
slug: check-if-array-is-sorted-and-rotated
difficulty: easy
leetcode_id: 1752
leetcode_url: https://leetcode.com/problems/check-if-array-is-sorted-and-rotated/
categories:
  - arrays
patterns:
  - two-pointers

description: |
  Given an array `nums`, return `true` *if the array was originally sorted in non-decreasing order, then rotated **some** number of positions (including zero)*. Otherwise, return `false`.

  There may be **duplicates** in the original array.

  **Note:** An array `A` rotated by `x` positions results in an array `B` of the same length such that `B[i] == A[(i+x) % A.length]` for every valid index `i`.

constraints: |
  - `1 <= nums.length <= 100`
  - `1 <= nums[i] <= 100`

examples:
  - input: "nums = [3,4,5,1,2]"
    output: "true"
    explanation: "[1,2,3,4,5] is the original sorted array. You can rotate the array by x = 2 positions to begin on the element of value 3: [3,4,5,1,2]."
  - input: "nums = [2,1,3,4]"
    output: "false"
    explanation: "There is no sorted array once rotated that can make nums."
  - input: "nums = [1,2,3]"
    output: "true"
    explanation: "[1,2,3] is the original sorted array. You can rotate the array by x = 0 positions (i.e. no rotation) to make nums."

explanation:
  intuition: |
    Think of rotation like taking a deck of cards that's in order and cutting it somewhere in the middle — you move the top portion to the bottom. The cards are still in order within each portion, but there's exactly **one place** where the sequence "breaks" (where the bottom of the cut meets the top).

    In a sorted-then-rotated array, you'll see the numbers increasing (or staying the same for duplicates), then suddenly **drop** to a smaller value, then continue increasing again. For example, `[3,4,5,1,2]` goes up from 3→4→5, then drops to 1, then continues up from 1→2.

    The key insight is: **a valid rotated sorted array can have at most one "breakpoint"** — one place where `nums[i] > nums[i+1]`. If you find two or more such breakpoints, the array couldn't have come from rotating a sorted array.

    There's one subtle catch: we also need to check the **wrap-around** from the last element back to the first. If the array was rotated (not just sorted), the last element should be ≤ the first element to complete the "circle" back to sorted order.

  approach: |
    We solve this by **counting inversions** (places where the order breaks):

    **Step 1: Initialise a counter**

    - `inversions`: Set to `0` to count how many times the sequence breaks

    &nbsp;

    **Step 2: Scan for breakpoints in the array**

    - Iterate through indices `0` to `n-1`
    - For each index `i`, compare `nums[i]` with `nums[(i+1) % n]`
    - Using modulo `% n` handles the wrap-around comparison (last element vs first)
    - If `nums[i] > nums[(i+1) % n]`, increment `inversions`

    &nbsp;

    **Step 3: Return the result**

    - If `inversions <= 1`, return `true` — the array is a valid rotated sorted array
    - If `inversions > 1`, return `false` — too many breakpoints to be a rotation

    &nbsp;

    This works because a sorted array has zero inversions, and rotating it introduces exactly one inversion at the rotation point. The wrap-around check using modulo ensures we verify the circular property.

  common_pitfalls:
    - title: Forgetting the Wrap-Around Check
      description: |
        A common mistake is only checking adjacent pairs without considering the wrap-around from the last element to the first.

        For example, `[2,3,1]` has one inversion (3→1), but we also need to verify that `1 <= 2` (last to first) for it to be a valid rotation. Using `(i+1) % n` automatically handles this by including the last-to-first comparison in our loop.
      wrong_approach: "Only check nums[i] > nums[i+1] for i < n-1"
      correct_approach: "Use modulo to include the wrap-around: nums[i] > nums[(i+1) % n]"

    - title: Off-by-One in Loop Bounds
      description: |
        If you iterate `i` from `0` to `n-2` (exclusive of the last element) and then separately check the wrap-around, you might miss edge cases or double-count.

        The cleaner approach is to iterate `i` from `0` to `n-1` and always use modulo arithmetic. This uniformly handles all comparisons including the wrap-around.
      wrong_approach: "Separate logic for internal pairs and wrap-around"
      correct_approach: "Single loop with modulo for uniform handling"

    - title: Confusing "Rotated" with Unsorted
      description: |
        The problem specifically asks about arrays that were **sorted then rotated**. An array like `[2,1,3,4]` has one inversion (2→1), but checking the wrap-around (4→2) reveals a second inversion. Two inversions means it's not a valid rotated sorted array.

        Always count all inversions including the circular wrap-around before deciding.

  key_takeaways:
    - "**Rotation creates exactly one breakpoint**: A sorted array rotated `k` positions has exactly one place where `nums[i] > nums[i+1]`"
    - "**Modulo for circular arrays**: Using `(i+1) % n` is a clean way to handle wrap-around comparisons in circular/rotated array problems"
    - "**Count inversions pattern**: Counting how many times a property is violated helps validate structural constraints"
    - "**Foundation for binary search**: Understanding rotated sorted arrays is key to problems like 'Search in Rotated Sorted Array'"

  time_complexity: "O(n). We traverse the array once, checking each adjacent pair including the wrap-around."
  space_complexity: "O(1). We only use a single counter variable regardless of input size."

solutions:
  - approach_name: Count Inversions
    is_optimal: true
    code: |
      def check(nums: list[int]) -> bool:
          n = len(nums)
          inversions = 0

          # Check all adjacent pairs including wrap-around (last to first)
          for i in range(n):
              # Use modulo to wrap index back to 0 after last element
              if nums[i] > nums[(i + 1) % n]:
                  inversions += 1

              # Early exit: more than one inversion means not valid
              if inversions > 1:
                  return False

          # Valid if at most one inversion (rotation point)
          return True
    explanation: |
      **Time Complexity:** O(n) — Single pass through the array with early exit optimisation.

      **Space Complexity:** O(1) — Only one integer counter used.

      We iterate through all elements, comparing each to its next neighbor (with wrap-around handled by modulo). A valid rotated sorted array has at most one "drop" point. The early exit when we find a second inversion provides a minor optimisation.

  - approach_name: Find Pivot and Verify
    is_optimal: false
    code: |
      def check(nums: list[int]) -> bool:
          n = len(nums)
          pivot = -1

          # Find the rotation pivot (where sequence breaks)
          for i in range(n - 1):
              if nums[i] > nums[i + 1]:
                  # Found a breakpoint
                  if pivot != -1:
                      # Second breakpoint found - not valid
                      return False
                  pivot = i

          # If no pivot found, array is fully sorted (rotation by 0)
          if pivot == -1:
              return True

          # Verify wrap-around: last element should be <= first
          return nums[n - 1] <= nums[0]
    explanation: |
      **Time Complexity:** O(n) — Single pass to find pivot, then O(1) wrap-around check.

      **Space Complexity:** O(1) — Only storing the pivot index.

      This approach explicitly finds the pivot point (rotation boundary) and then verifies the wrap-around condition separately. While correct, it's slightly more verbose than the modulo approach. The logic is: find at most one breakpoint in the array body, then confirm the circular property holds.
