二分查找
简介
记录一下自己刷题的历程以及代码,会尽量把在本地测试包含main
函数的完整代码贴上,以及一些注释掉的输出语句。写题过程中参考了 代码随想录。会附上一些个人的思路,如果有错误,可以在评论区提醒一下。
704.二分查找
原题链接
right = nums.length - 1;
是一种闭区间的写法,左右下标都在数组范围内,此时while
循环中需要加上=
,否则会在nums = [5],target = 5
的情况下报错。
java
class Solution {
public int search(int[] nums, int target){
if(target<nums[0] || target>nums[nums.length-1]){
return -1;
}
int left = 0;
int right = nums.length - 1;
int mid = 0;
while(left <= right){
//System.out.println("left:" + left + " mid:" + mid + " right:" + right);
mid = (left + right) / 2;
if(target > nums[mid]) {
left = mid + 1;
}else if(target < nums[mid]){
right = mid - 1;
}else{
return mid;
}
}
return -1;
}
}
public class main {
public static void main(String[] args) {
Solution solution = new Solution();
int[] nums = new int[]{-1,0,3,5,9,12};
int target = 9;
System.out.println(solution.search(nums,target));
}
}
35. 搜索插入位置
总共四种情况
①找到元素,返回middle
找不到元素,循环正常退出,此时有right = left-1
②在所有元素之前,此时left = 0;right = -1
target需要插入0,即left的位置
③在两个元素中间,此时nums[left]>target;nums[right]<target
target需要插入left的位置
④在所有元素之后,此时right=nums.length()-1;left=nums.length()
target需要插入left的位置
java
class Solution {
public int searchInsert(int[] nums, int target) {
int left = 0;
int right = nums.length - 1;
int mid = 0;
while(left <= right){
mid = (left + right) / 2;
//System.out.println("left:" + left + " mid:" + mid + " right:" + right);
if(target > nums[mid]) {
left = mid + 1;
}else if(target < nums[mid]){
right = mid - 1;
}else{
return mid;
}
}
return left;
}
}
public class main {
public static void main(String[] args) {
Solution solution = new Solution();
int[] nums = new int[]{1,3};
int target = 0;
System.out.println(solution.searchInsert(nums,target));
}
}
34. 在排序数组中查找元素的第一个和最后一个位置
方法一:找到nums[mid] == target
时在mid左右继续查找相等的值,在二分查找的代码上增加一些功能即可,但是当连续的数字过多时容易将复杂度退到O(n)
,相当于遍历的复杂度。可以通过这道题,但是时间复杂度较高。
方法二:分别寻找左右边界,左边界指向 该元素第一个位置之前的元素,右边界指向最后一个位置之后的元素。
例如找左边界:nums[mid] == target
时也要把范围划到mid左边,因为我们需要找的是target的边界
java
int left = 0;
int right = nums.length - 1;
int leftBorder = -2;
while(left <= right){
if(target > nums[mid]) {
left = mid + 1;
}else if(target < nums[mid]){
right = mid - 1;
leftBorder = right;
}else if(target == nums[mid]){
right = mid - 1;
leftBorder = right;
}
}
查找左右边界的函数内部的判断语句是由上面的判断语句三种情况合并而成,结果如下:
java
class Solution {
public int[] searchRange(int[] nums, int target) {
int leftBorder = searchLeft(nums, target);
int rightBorder = searchRight(nums, target);
if(leftBorder == -2 || rightBorder == -2) return new int[]{-1 ,-1};
if(rightBorder - leftBorder > 1) return new int[]{leftBorder + 1,rightBorder - 1};
return new int[]{-1 ,-1};
}
public int searchLeft(int[] nums, int target){
int left = 0;
int right = nums.length - 1;
int leftBorder = -2;
while(left <= right){
int mid = (left + right) / 2;
if(target > nums[mid]) {
left = mid + 1;
}else{
right = mid - 1;
leftBorder = right;
}
}
return leftBorder;
}
public int searchRight(int[] nums, int target){
int left = 0;
int right = nums.length - 1;
int rightBorder = -2;
while(left <= right){
int mid = (left + right) / 2;
if(target < nums[mid]) {
right = mid - 1;
}else{
left = mid + 1;
rightBorder = left;
}
}
return rightBorder;
}
}
public class main {
public static void main(String[] args) {
Solution solution = new Solution();
int[] nums = new int[]{2, 2};
int target = 3;
int[] array = solution.searchRange(nums,target);
for (int i = 0; i < array.length; i++) {
System.out.print(array[i] + " ");
}
}
}