Link to the problem
The problem is here: https://leetcode-cn.com/problems/find-first-and-last-position-of-element-in-sorted-array/
Problem description
The problem is very straightforward. Given a sorted array (ascending) nums and a number target, find the starting and the ending position of target.
Idea
This is a very typical problem that can be solved by using binary search.
Binary search
The boundary conditions are essentially important for a bug-free binary search algorithm. My method is to figure out the loop invariant and then strictly follow that invariant. There could be some corner cases that violate the loop invariant at the very beginning. We should handle those cases carefully.
Implementation
STL
The c++ standard library actually provides [std::lower_bound](https://www.cplusplus.com/reference/algorithm/lower_bound/) and [std::upper_bound](https://www.cplusplus.com/reference/algorithm/upper_bound/), which can be used to solve this problem directly.
lower_boundis to find the first element >= target (not less than)upper_boundis to find the first element > target (strictly greater)
DIY
This is my implementation:
class Solution {// return the position of first element >= target; -1 if no such elementint lower_bound(const vector<int> &nums, const int target) {// handle special corner casesif (nums.empty() || nums.back() < target) {return -1;}if (nums[0] >= target) {return 0;}int i = 0, j = nums.size() - 1;// loop inv: nums[i] < target and nums[j] >= targetwhile (i < j - 1) {if (nums[i] >= target || nums[j] < target) {return -1;}int mid = (i + j) / 2;if (nums[mid] < target) {i = mid;} else {j = mid;}}return j >= 0 && nums[j] >= target ? j : -1;}// return the position of the first element > target; -1 if no such elementint upper_bound(const vector<int> &nums, const int target) {// handle special corner casesif (nums.empty() || nums.back() <= target) {return -1;}if (nums[0] > target) {return 0;}int i = 0, j = nums.size() - 1;// loop inv: nums[i] <= target and nums[j] > targetwhile (i < j - 1) {if (nums[i] > target || nums[j] <= target) {return -1;}int mid = (i + j) / 2;if (nums[mid] <= target) {i = mid;} else {j = mid;}}return j >= 0 && nums[j] > target ? j : -1;}public:vector<int> searchRange(vector<int>& nums, int target) {int n = nums.size();int i = 0, j = n - 1;vector<int> res(2, -1);auto lb = this->lower_bound(nums, target);auto ub = this->upper_bound(nums, target);if (lb == -1 || nums[lb] != target) {// can not find target} else {res[0] = lb;res[1] = ub == -1 ? n - 1 : ub - 1;}return res;}};
Possible refinement:
- Can use template-programming to reuse code.
