A problem reminding that O(2*Log(N)) is equal to O(Log(N))
Problem is by Leetcode: "Find First and Last Position of Element in Sorted Array", right here: https://leetcode.com/problems/find-first-and-last-position-of-element-in-sorted-array/description/
Given an array of integers
Given an array of integers
nums
sorted in ascending order, find the starting and ending position of a given target
value.
Your algorithm's runtime complexity must be in the order of O(log n).
If the target is not found in the array, return
[-1, -1]
.
Example 1:
Input: nums = [5,7,7,8,8,10]
, target = 8
Output: [3,4]
Example 2:
Input: nums = [5,7,7,8,8,10]
, target = 6
Output: [-1,-1]
The problem is looking for a Log(N) solution, but there are two values being asked for - the lower left, and the upper right. The way to find each one is to do a variation of binary search. And for each value, just run the algorithm twice for a O(2*Log(N)), which is the same as O(Log(N)). Code is below, cheers, Marcelo.
public class Solution { public int[] SearchRange(int[] nums, int target) { int[] retVal = new int[2]; if (nums == null || nums.Length == 0) { retVal[0] = -1; retVal[1] = -1; return retVal; } //Leftmost int e1 = -1; int left = 0; int right = nums.Length - 1; while (left <= right) { int mid = (left + right) / 2; if (nums[mid] == target && (mid == 0 || nums[mid - 1] < target)) { e1 = mid; break; } else if (nums[mid] >= target) right = mid - 1; else left = mid + 1; } //Rightmost int e2 = -1; left = 0; right = nums.Length - 1; while (left <= right) { int mid = (left + right) / 2; if (nums[mid] == target && (mid == nums.Length - 1 || nums[mid + 1] > target)) { e2 = mid; break; } else if (nums[mid] > target) right = mid - 1; else left = mid + 1; } retVal[0] = e1; retVal[1] = e2; return retVal; } }
Ha, in C++ it's so easy to cheat :)
ReplyDeleteclass Solution {
public:
vector searchRange(vector& nums, int target) {
int startIdx = -1;
int endIdx = -1;
auto start = lower_bound(nums.cbegin(), nums.cend(), target);
if (start != nums.cend() && *start == target) {
startIdx = distance(nums.cbegin(), start);
}
auto end = upper_bound(nums.cbegin(), nums.cend(), target) - 1;
if (end != nums.cend() && *end == target) {
endIdx = distance(nums.cbegin(), end);
}
return {startIdx, endIdx};
}
};
a non-cheating answer in C++ is below:
Deleteclass Solution {
private:
int findFirst(const vector& nums, int target) const {
int left = 0;
int right = nums.size()-1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (nums[mid] < target) {
left = mid + 1;
} else {
right = mid - 1;
}
}
return left < nums.size() && nums[left] == target ? left : -1;
}
int findLast(const vector& nums, int target) const {
int left = 0;
int right = nums.size()-1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (nums[mid] > target) {
right = mid - 1;
} else {
left = mid + 1;
}
}
return right >= 0 && nums[right] == target ? right : -1;
}
public:
vector searchRange(vector& nums, int target) {
if (nums.empty()) return {-1, -1};
return {findFirst(nums, target), findLast(nums, target)};
}
};