704. Binary Search
Given an array of integers nums which is sorted in ascending order, and an integer target, write a function to search target in nums. If target exists, then return its index. Otherwise, return -1.
You must write an algorithm with O(log n) runtime complexity.
题目解析:
- 时间复杂度要求为O(log n),很可能是二分查找
- 数组为排序数组,这是二分查找的必要条件
代码
class Solution {
public int search(int[] nums, int target) {
int left = 0, right = nums.length - 1;
while (left <= right) {
int mid = (right - left) / 2 + left;
if (nums[mid] == target) {
return mid;
} else if (nums[mid] < target) {
left = mid + 1;
} else {
right = mid -1;
}
}
return -1;
}
}
27. Remove Element
Given an integer array nums and an integer val, remove all occurrences of val in nums in-place. The order of the elements may be changed. Then return the number of elements in nums which are not equal to val.
Consider the number of elements in nums which are not equal to val be k, to get accepted, you need to do the following things:
- Change the array
numssuch that the firstkelements ofnumscontain the elements which are not equal toval. The remaining elements ofnumsare not important as well as the size ofnums. - Return
k.
题目解析:
in-place移除元素,加上保留前k个元素,所以很可能就是元素替换- 两个元素通过下标进行替换,双指针就非常合适
代码
class Solution {
public int removeElement(int[] nums, int val) {
int slow = 0;
for (int fast = 0; fast < nums.length; fast++) {
if (nums[fast] != val) {
nums[slow++] = nums[fast];
}
}
return slow;
}
}
35. Search Insert Position
Given a sorted array of distinct integers and a target value, return the index if the target is found. If not, return the index where it would be if it were inserted in order.
You must write an algorithm with O(log n) runtime complexity.
题目解析:
- 本题与查找目标值类似,都是用二分查找
- 需要额外考虑当数组中不存在目标值时插入的小标位置:
- 当目标值小于数组最小值时:退出循环时left为0不变,left位置即为插入位置
- 当目标值大于数组最大值时:退出循环时left=right+1,left位置即为插入位置
- 当目标值大于最小值并且小于最大值时:一定会出现left = right - 1, 此时计算出mid为left, 值小于target,也就是说下一轮left = mid + 1 = right,值大于target, 所以left位置为插入位置
- 综上,当数组中不存在目标元素是,返回left即可
代码
class Solution {
public int searchInsert(int[] nums, int target) {
int left = 0, right = nums.length - 1;
while (left <= right) {
int mid = (right - left) / 2 + left;
if (nums[mid] < target) {
left = mid + 1;
} else if (nums[mid] > target) {
right = mid - 1;
} else {
return mid;
}
}
return left;
}
}
34. Find First and Last Position of Element in Sorted Array
Given an array of integers nums sorted in non-decreasing order, find the starting and ending position of a given target value.
If target is not found in the array, return [-1, -1].
You must write an algorithm with O(log n) runtime complexity.
题解:
- 采用左闭右闭区间的方式找到target,本题的target有两个,可以分别找出是第一次出现的目标值和最后一次出现的目标值
- 当
nums[mid] == target,- 如果
left == right,说明已经到达左端点或者右端点,直接返回left - 如果
left != right,且目标为左端点时:right = mid,使得中点左移,直到左端点 - 如果
left != right,且目标为右端点时:left = mid,使得中点右移,直到有端点
- 如果
- 注意当使用
left = mid的时候,如果right = mid+1,那么下一次计算mid还是等于left,这就导致了死循环,所以当目标为求右端点时,计算中点的方式需要变一下:int mid = (right - left + 1) / 2 + left;,可以保证当left和right相差为1时,mid等于right,从而避免死循环。
代码中两个方法
findFirstElement()和findLastElement()重复代码较多,也可以合成一个方法。
代码
class Solution {
public int[] searchRange(int[] nums, int target) {
int left = findFirstElement(nums, target);
int right = findLastElement(nums, target);
return new int[]{left, right};
}
public int findFirstElement(int[] nums, int target) {
int left = 0, right = nums.length - 1;
while (left <= right) {
int mid = (right - left) / 2 + left;
if (nums[mid] < target) {
left = mid + 1;
} else if (nums[mid] > target) {
right = mid - 1;
} else {
if (left == right) {
return left;
}
right = mid;
}
}
return -1;
}
public int findLastElement(int[] nums, int target) {
int left = 0, right = nums.length - 1;
while (left <= right) {
int mid = (right - left + 1) / 2 + left;
if (nums[mid] < target) {
left = mid + 1;
} else if (nums[mid] > target) {
right = mid - 1;
} else {
if (left == right) {
return left;
}
left = mid;
}
}
return -1;
}
}
总结
- 熟悉 根据 左闭右开,左闭右闭 两种区间规则 写出来的二分法。
- 二分查找的变形
- 求插入元素的下标(目标元素不存在数据中时)
- 求第一次出现和最后一次出现的下标