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   **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`   **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   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.