Search in Rotated Sorted Array in DSA Rust - Time & Space Complexity
We want to understand how fast we can find a number in a rotated sorted list.
How does the search time grow when the list gets bigger?
Analyze the time complexity of the following code snippet.
fn search(nums: &[i32], target: i32) -> i32 {
let mut left = 0;
let mut right = nums.len() as i32 - 1;
while left <= right {
let mid = left + (right - left) / 2;
if nums[mid as usize] == target {
return mid;
}
if nums[left as usize] <= nums[mid as usize] {
if nums[left as usize] <= target && target < nums[mid as usize] {
right = mid - 1;
} else {
left = mid + 1;
}
} else {
if nums[mid as usize] < target && target <= nums[right as usize] {
left = mid + 1;
} else {
right = mid - 1;
}
}
}
-1
}
This code searches for a target number in a rotated sorted array using a modified binary search.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: The while loop that halves the search range each time.
- How many times: The loop runs until the search range is empty, roughly log base 2 of the array size.
Each step cuts the search area in half, so the number of steps grows slowly as the list grows.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | About 4 steps |
| 100 | About 7 steps |
| 1000 | About 10 steps |
Pattern observation: Doubling the list size adds only one extra step.
Time Complexity: O(log n)
This means the search time grows slowly, adding just a few more steps even if the list gets much bigger.
[X] Wrong: "Because the array is rotated, we must check every element one by one."
[OK] Correct: The modified binary search still works by deciding which half is sorted, so we don't need to check all elements.
Understanding this search shows you can adapt classic methods to tricky situations, a skill valued in problem solving.
"What if the array was not rotated but contained duplicates? How would the time complexity change?"
Practice
Solution
Step 1: Understand the array structure
A rotated sorted array is originally sorted but then rotated at some pivot, splitting it into two sorted parts.Step 2: Impact on search
This split means a normal binary search can't be applied directly because the order is disrupted at the pivot.Final Answer:
The array is split into two sorted parts, making direct binary search tricky -> Option DQuick Check:
Rotated array = two sorted parts [OK]
- Assuming the array is fully sorted without rotation
- Ignoring the pivot point in the array
- Thinking duplicates cause the main challenge
- Confusing descending order with rotation
Solution
Step 1: Analyze parameter types
Using a slice &[i32] is efficient and idiomatic for read-only array input in Rust.Step 2: Analyze return type
Returning Option<usize> allows indicating if the target was found (Some(index)) or not (None).Final Answer:
fn search(nums: &[i32], target: i32) -> Option<usize> -> Option AQuick Check:
Slice input + Option return = fn search(nums: &[i32], target: i32) -> Option<usize> [OK]
- Using Vec<i32> unnecessarily copies data
- Returning usize without Option loses 'not found' info
- Returning bool loses index information
- Returning i32 index can be ambiguous
fn search(nums: &[i32], target: i32) -> Option<usize> {
let mut left = 0;
let mut right = nums.len() - 1;
while left <= right {
let mid = (left + right) / 2;
if nums[mid] == target {
return Some(mid);
}
if nums[left] <= nums[mid] {
if nums[left] <= target && target < nums[mid] {
right = mid - 1;
} else {
left = mid + 1;
}
} else {
if nums[mid] < target && target <= nums[right] {
left = mid + 1;
} else {
right = mid - 1;
}
}
}
None
}
let arr = [4,5,6,7,0,1,2];
println!("{:?}", search(&arr, 3));Solution
Step 1: Understand the array and target
The array is [4,5,6,7,0,1,2], target is 3 which is not present in the array.Step 2: Trace the search logic
The function performs binary search on rotated array but since 3 is missing, the loop ends returning None.Final Answer:
None -> Option AQuick Check:
3 not in array = None [OK]
- Assuming target 3 is present and returning wrong index
- Confusing mid calculation causing infinite loop
- Ignoring rotation logic in conditions
- Returning Some with wrong index
fn search(nums: &[i32], target: i32) -> Option<usize> {
let mut left = 0;
let mut right = nums.len() - 1;
while left < right {
let mid = (left + right) / 2;
if nums[mid] == target {
return Some(mid);
}
if nums[left] <= nums[mid] {
if nums[left] <= target && target < nums[mid] {
right = mid - 1;
} else {
left = mid + 1;
}
} else {
if nums[mid] < target && target <= nums[right] {
left = mid + 1;
} else {
right = mid - 1;
}
}
}
None
}Solution
Step 1: Analyze loop condition
The loop uses while left < right, which misses checking when left == right, possibly skipping the last element.Step 2: Correct loop condition
Changing to while left <= right ensures all elements are checked, including when left equals right.Final Answer:
The loop condition should be while left <= right, not while left < right -> Option CQuick Check:
Loop must cover all indices [OK]
- Using < instead of <= causing missed checks
- Trying floating division for mid index
- Changing return type unnecessarily
- Making array mutable without need
Solution
Step 1: Understand duplicates impact
Duplicates can make it unclear which side is sorted because nums[left], nums[mid], nums[right] may be equal.Step 2: Modify algorithm to skip duplicates
When nums[left] == nums[mid] == nums[right], increment left and decrement right to skip duplicates and continue search.Step 3: Avoid sorting or linear search
Sorting changes array order; linear search is inefficient. Proper duplicate handling keeps binary search efficient.Final Answer:
Add extra checks to skip duplicates when nums[left] == nums[mid] == nums[right] -> Option BQuick Check:
Skip duplicates to maintain binary search [OK]
- Sorting array losing rotation info
- Using linear search losing efficiency
- Ignoring duplicates causing wrong results
- Assuming duplicates don't affect logic
Ready to prove it?
Pass the test and this pattern moves unknown
