# Question

Formatted question description: https://leetcode.ca/all/81.html

There is an integer array nums sorted in non-decreasing order (not necessarily with distinct values).

Before being passed to your function, nums is rotated at an unknown pivot index k (0 <= k < nums.length) such that the resulting array is [nums[k], nums[k+1], ..., nums[n-1], nums[0], nums[1], ..., nums[k-1]] (0-indexed). For example, [0,1,2,4,4,4,5,6,6,7] might be rotated at pivot index 5 and become [4,5,6,6,7,0,1,2,4,4].

Given the array nums after the rotation and an integer target, return true if target is in nums, or false if it is not in nums.

You must decrease the overall operation steps as much as possible.

Example 1:

Input: nums = [2,5,6,0,0,1,2], target = 0
Output: true


Example 2:

Input: nums = [2,5,6,0,0,1,2], target = 3
Output: false


Constraints:

• 1 <= nums.length <= 5000
• -104 <= nums[i] <= 104
• nums is guaranteed to be rotated at some pivot.
• -104 <= target <= 104

Follow up: This problem is similar to Search in Rotated Sorted Array, but nums may contain duplicates. Would this affect the runtime complexity? How and why?

# Algorithm

In the previous problem “Search in Rotated Sorted Array,” there were no repeated values, so we could follow the rule that if the number in the middle is less than the rightmost number, the right half is ordered, and if the number is greater than the rightmost number, the left half is ordered.

However, if there are repeated values, there are two situations to consider: [3 1 1] and [1 1 3 1]. In these situations, when the middle value is equal to the rightmost value, the target value 3 could be either on the left or on the right.

If the target value is on the right, we simply move the rightmost value to the left and continue the loop. If it is still the same, we continue to move until we reach a different value. After that, we can use the same method as in “Search in Rotated Sorted Array” to find the target value.

# Code

• 
public class Search_in_Rotated_Sorted_Array_II {

// time: O(1)
// space: O(N)
public class Solution {
public boolean search(int[] nums, int target) {

if (nums == null || nums.length == 0) {
return false;
}

int i = 0; // left pointer
int j = nums.length - 1; // right pointer

while(i <= j) {
int mid = (i + j) / 2;

if (nums[mid] == target) {
return true;
}

// @note: if (nums[0] <= nums[mid]) {
if (nums[i] <= nums[mid]) { // left half ordered, right half not ordered

// if (target <= nums[mid]) {
if (nums[i] <= target && target <= nums[mid]) {
j = mid;
} else {
i++;
}
} else { // right half ordered, left half not ordered

// if (target <= nums[mid]) {
if (nums[mid] <= target && target <= nums[j]) {
i = mid;
} else {
j--;
}
}
}

return false;
}

}
}

############

class Solution {
public boolean search(int[] nums, int target) {
int l = 0, r = nums.length - 1;
while (l <= r) {
int mid = (l + r) >>> 1;
if (nums[mid] == target) return true;
if (nums[mid] < nums[r] || nums[mid] < nums[l]) {
if (target > nums[mid] && target <= nums[r])
l = mid + 1;
else
r = mid - 1;
} else if (nums[mid] > nums[l] || nums[mid] > nums[r]) {
if (target < nums[mid] && target >= nums[l])
r = mid - 1;
else
l = mid + 1;
} else
r--;
}
return false;
}
}

• // OJ: https://leetcode.com/problems/search-in-rotated-sorted-array-ii/
// Time: average O(logN), worst O(N)
// Space: O(1)
class Solution {
int findStart(vector<int> &A) {
int L = 0, R = A.size() - 1;
while (L + 1 < R) {
if (A[L] < A[R]) return L;
int M = (L + R) / 2;
if (A[M] > A[R]) L = M + 1;
else if (A[M] < A[R] || (A[M] == A[R] && A[L] > A[R])) R = M;
else {
int k = L;
while (k < R && A[L] == A[k]) ++k;
if (k == R) return L;
if (A[k] < A[L]) return k;
L = k + 1;
}
}
return A[L] < A[R] ? L : R;
}
public:
bool search(vector<int>& A, int T) {
if (A.empty()) return false;
int start = findStart(A), N = A.size(), L = 0, R = N - 1;
while (L <= R) {
int M = (L + R) / 2, mid = (start + M) % N;
if (A[mid] == T) return true;
if (A[mid] < T) L = M + 1;
else R = M - 1;
}
return false;
}
};

• class Solution:
def search(self, nums: List[int], target: int) -> bool:
if not nums:
return False

i = 0  # left pointer
j = len(nums) - 1  # right pointer

while i <= j:
mid = (i + j) // 2

if nums[mid] == target:
return True

if nums[i] <= nums[mid]:  # left half ordered, right half not ordered
if nums[i] <= target <= nums[mid]:
j = mid
else:
i += 1
else:  # right half ordered, left half not ordered
if nums[mid] <= target <= nums[j]:
i = mid
else:
j -= 1

return False

############

class Solution: # OJ passed
def search(self, nums: List[int], target: int) -> bool:
l, r = 0, len(nums) - 1
while l <= r:
mid = (l + r) >> 1
if nums[mid] == target:
return True
if nums[mid] < nums[r] or nums[mid] < nums[l]:
if target > nums[mid] and target <= nums[r]:
l = mid + 1
else:
r = mid - 1
elif nums[mid] > nums[l] or nums[mid] > nums[r]:
if target < nums[mid] and target >= nums[l]:
r = mid - 1
else:
l = mid + 1
else:
r -= 1
return False


• func search(nums []int, target int) bool {
l, r := 0, len(nums)-1
for l < r {
mid := (l + r) >> 1
if nums[mid] > nums[r] {
if nums[l] <= target && target <= nums[mid] {
r = mid
} else {
l = mid + 1
}
} else if nums[mid] < nums[r] {
if nums[mid] < target && target <= nums[r] {
l = mid + 1
} else {
r = mid
}
} else {
r--
}
}
return nums[l] == target
}

• function search(nums: number[], target: number): boolean {
let [l, r] = [0, nums.length - 1];
while (l < r) {
const mid = (l + r) >> 1;
if (nums[mid] > nums[r]) {
if (nums[l] <= target && target <= nums[mid]) {
r = mid;
} else {
l = mid + 1;
}
} else if (nums[mid] < nums[r]) {
if (nums[mid] < target && target <= nums[r]) {
l = mid + 1;
} else {
r = mid;
}
} else {
--r;
}
}
return nums[l] === target;
}