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)};
}
};