目录
1.二分查找(Leetcode 704)
2.搜索插入位置( LeetCode 35 )
3.寻找峰值(LeetCode 162)
4.旋转数组的最小数字(BM21)
5.总结
1.二分查找(Leetcode 704)
给定一个 n
个元素有序的(升序)整型数组 nums
和一个目标值 target
,写一个函数搜索 nums
中的 target
,如果目标值存在返回下标,否则返回 -1
。
示例 1:
输入:nums
= [-1,0,3,5,9,12],target
= 9 输出: 4 解释: 9 出现在nums
中并且下标为 4
示例 2:
输入:nums
= [-1,0,3,5,9,12],target
= 2 输出: -1 解释: 2 不存在nums
中因此返回 -1
class Solution {
public int search(int[] nums, int target) {
int left=0;
int right=nums.length-1;
//while(left < right): 这个条件会在 left 和 right 相邻时停止循环。
//因此,当 left 和 right 相邻时,如果目标值恰好在 right 位置,循环将结束而不会进行最后一次检查。
//所以要写left<=right
while(left<=right){
int mid=left+(right-left)/2;
if(nums[mid]==target){
return mid;
}else if(nums[mid]<target){
left=mid+1;
}else if(nums[mid]>target){
right=mid-1;
}
}
return -1;
}
}
2.搜索插入位置( LeetCode 35 )
https://leetcode.cn/problems/search-insert-position/description/
给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。
请必须使用时间复杂度为 O(log n)
的算法。
示例 1:
输入: nums = [1,3,5,6], target = 5 输出: 2
示例 2:
输入: nums = [1,3,5,6], target = 2 输出: 1
示例 3:
输入: nums = [1,3,5,6], target = 7 输出: 4
和上一题相比,多了一步查找不到target插入,观察退出循环时:
因此,代码只是在二分查找的基础上多了一步返回到left下标。
class Solution {
public int searchInsert(int[] nums, int target) {
int left=0;
int right=nums.length-1;
//while(left < right): 这个条件会在 left 和 right 相邻时停止循环。
//因此,当 left 和 right 相邻时,如果目标值恰好在 right 位置,循环将结束而不会进行最后一次检查。
//所以要写left<=right
while(left<=right){
int mid=left+(right-left)/2;
if(nums[mid]==target){
return mid;
}else if(nums[mid]<target){
left=mid+1;
}else if(nums[mid]>target){
right=mid-1;
}
}
return left;
}
}
3.寻找峰值(LeetCode 162)
https://leetcode.cn/problems/find-peak-element/description/
峰值元素是指其值严格大于左右相邻值的元素。
给你一个整数数组 nums
,找到峰值元素并返回其索引。数组可能包含多个峰值,在这种情况下,返回 任何一个峰值 所在位置即可。
你可以假设 nums[-1] = nums[n] = -∞
。
你必须实现时间复杂度为 O(log n)
的算法来解决此问题
示例 1:
输入:nums = [1,2,3,1]
输出:2
解释:3 是峰值元素,你的函数应该返回其索引 2。
示例 2:
输入:nums = [1,2,1,3,5,6,4]
输出:1 或 5
解释:你的函数可以返回索引 1,其峰值元素为 2;
或者返回索引 5, 其峰值元素为 6。
class Solution {
public int findPeakElement(int[] nums) {
int left=0;
int right=nums.length-1;
while(left<right){
int mid=left+(right-left)/2;
if(nums[mid]<nums[mid+1]){
left=mid+1;
}else{
right=mid;
}
}
return left;
}
}
4.旋转数组的最小数字(BM21)
https://www.nowcoder.com/practice/9f3231a991af4f55b95579b44b7a01ba?tpId=295&tqId=23269&ru=/exam/oj&qru=/ta/format-top101/question-ranking&sourceUrl=%2Fexam%2Foj
有一个长度为 n 的非降序数组,比如[1,2,3,4,5],将它进行旋转,即把一个数组最开始的若干个元素搬到数组的末尾,变成一个旋转数组,比如变成了[3,4,5,1,2],或者[4,5,1,2,3]这样的。请问,给定这样一个旋转数组,求数组中的最小值。
数据范围:1≤n≤100001≤n≤10000,数组中任意元素的值: 0≤val≤100000≤val≤10000
要求:空间复杂度:O(1)O(1) ,时间复杂度:O(logn)O(logn)
示例1
输入:[3,4,5,1,2]
复制返回值:1
示例2
输入:[3,100,200,3]
复制返回值:3
import java.util.*;
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param nums int整型一维数组
* @return int整型
*/
public int minNumberInRotateArray (int[] nums) {
int left=0;
int right=nums.length-1;
while(left<right){
int mid=left+(right-left)/2;
if(nums[mid]>nums[right]){
left=mid+1;
}else if(nums[mid]<nums[right]){
right=mid;
}else{
right--;
}
}
return nums[left];
}
}
5.总结
利用二分查找的分治策略,提高查找效率。
对于特定结构(如有序或旋转数组)的优化,减少时间复杂度到 O(logn)
动态调整搜索范围,依据当前状态决定下一步的方向。
二分查找(Leetcode 704):在有序数组中,通过二分查找快速定位目标值的索引。每次将搜索范围缩小一半,直到找到目标或范围为空。
搜索插入位置( LeetCode 35 ):在有序数组中,利用二分查找确定目标值的插入位置。通过比较目标值和中间值,调整搜索范围来找到插入点,保持数组有序。
寻找峰值(LeetCode 162):寻找局部峰值(比相邻元素大的元素)。通过二分查找逐步缩小范围,根据中间元素与其相邻元素的关系调整搜索方向,找到峰值。
旋转数组的最小数字(BM21):在旋转排序数组中,通过二分查找找到最小值。比较中间值与左右端点值,调整搜索范围以找到最小值,利用旋转数组的特点来决定方向。