力扣二分查找

本文通过四个力扣题目,详细介绍了二分查找在不同问题中的应用:1. 在有序数组中查找目标值;2. 计算非负整数的平方根;3. 在循环有序数组中找到大于目标字母的最小字母;4. 在有序数组中找到唯一的单一元素。每个问题都附有思路解析,展示二分查找的灵活性和效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

704 二分查找

1.要求

给定一个 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

提示:

你可以假设 nums 中的所有元素是不重复的。
n 将在 [1, 10000]之间。
nums 的每个元素都将在 [-9999, 9999]之间。

2.思路

二分查找也称为折半查找,每次都能将查找区间减半,这种折半特性的算法时间复杂度为 O(logN)

class Solution {
    public int search(int[] nums, int target) {
        int low=0;
        int high=nums.length;
        while(low<high){
            int mid=low+(high-low)/2;
            // System.out.println(mid);
            if(nums[mid]==target){
                return mid;
            }else if(nums[mid]<target){
                low=mid+1;
            }else{
                high=mid;
            }
        }
        return -1;
        
    }
}

69 x 的平方根

1.要求

实现 int sqrt(int x) 函数。

计算并返回 x 的平方根,其中 x 是非负整数。

由于返回类型是整数,结果只保留整数的部分,小数部分将被舍去。

示例 1:

输入: 4
输出: 2
示例 2:

输入: 8
输出: 2
说明: 8 的平方根是 2.82842…,
由于返回类型是整数,小数部分将被舍去。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/sqrtx
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
2.思路
平方的数肯定小于等于这个数的一半,然后利用2分法,寻找一个这个数;

class Solution {
    public int mySqrt(int x) {
        if (x <= 1) {
        return x;
      }
    int l = 1, h = x;
    while (l <= h) {
        int mid = l + (h - l)/2;
        int sqrt = x / mid;
        if (sqrt == mid) {
            return mid;
        } else if (mid > sqrt) {
            h = mid - 1;
        } else {
            l = mid + 1;
        }
    }
    return h;
        
    }
}

744 寻找比目标字母大的最小字母

1.要求

给定一个只包含小写字母的有序数组letters 和一个目标字母 target,寻找有序数组里面比目标字母大的最小字母。

数组里字母的顺序是循环的。举个例子,如果目标字母target = ‘z’ 并且有序数组为 letters = [‘a’, ‘b’],则答案返回 ‘a’。

示例:

输入:
letters = [“c”, “f”, “j”]
target = “a”
输出: “c”

输入:
letters = [“c”, “f”, “j”]
target = “c”
输出: “f”

输入:
letters = [“c”, “f”, “j”]
target = “d”
输出: “f”

输入:
letters = [“c”, “f”, “j”]
target = “g”
输出: “j”

输入:
letters = [“c”, “f”, “j”]
target = “j”
输出: “c”

输入:
letters = [“c”, “f”, “j”]
target = “k”
输出: “c”
注:

letters长度范围在[2, 10000]区间内。
letters 仅由小写字母组成,最少包含两个不同的字母。
目标字母target 是一个小写字母。

2.思路

因为有序,所以2分查找,寻找到一个临界点这个点,如果这个临界点到了最右边,说明全都比它小,所以取第一个字符返回,反之则取小的那个临界点(或者大的临界点+1);

class Solution {
    public char nextGreatestLetter(char[] letters, char target) {
        int n = letters.length;
        int l = 0, h = n - 1;
        while (l <= h) {
            int m = l + (h - l) / 2;
            if (letters[m] <= target) {
                l = m + 1;
            } else {
                h = m - 1;
            }
        }
        return l < n ? letters[l] : letters[0];

    }
}

540有序数组中的单一元素

1.要求

给定一个只包含整数的有序数组,每个元素都会出现两次,唯有一个数只会出现一次,找出这个数。

示例 1:

输入: [1,1,2,3,3,4,4,8,8]
输出: 2
示例 2:

输入: [3,3,7,7,10,11,11]
输出: 10
注意: 您的方案应该在 O(log n)时间复杂度和 O(1)空间复杂度中运行。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/single-element-in-a-sorted-array
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

2.思路

1.暴力破解两个循环;但是循环自增2,比较前后两个数是否满足;
2 2分查找,偶数位置总是一个新的数,如果,不等后一个数,证明单数一定出现在前边,反之如果相等证明证明此前的数都正常,开始找后边的数。

class Solution {
    public int singleNonDuplicate(int[] nums) {
        int l=0;
        int h=nums.length-1;
        while(l<h){
            int mid=l+(h-l)/2;
            if(mid%2==1){
                mid--;
            }
            if(nums[mid]==nums[mid+1]){
                l=mid+2;
            }else{
                h=mid;
            }
        }
        return nums[l];
        
    }
}

153. 寻找旋转排序数组中的最小值

1.要求

假设按照升序排序的数组在预先未知的某个点上进行了旋转。

( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。

请找出其中最小的元素。

你可以假设数组中不存在重复元素。

示例 1:

输入: [3,4,5,1,2]
输出: 1
示例 2:

输入: [4,5,6,7,0,1,2]
输出: 0

2.思路

2.分查找方式

class Solution {
    public int findMin(int[] nums) {
        int l=0;
        int h=nums.length-1;
        while(l<h){
            int mid=l+(h-l)/2;
            if( nums[mid]<nums[h]){
                 h=mid;
            }else{
               l=mid+1;
            }
        }
        return nums[l];
        
    }
}

链接:https://leetcode-cn.com/problems/binary-search
https://github.com/CyC2018/CS-Notes/blob/master/notes/Leetcode%20%E9%A2%98%E8%A7%A3%20-%20%E4%BA%8C%E5%88%86%E6%9F%A5%E6%89%BE.md

### LeetCode 二分查找完整代码实现 对于给定的有序数组 `nums` 和目标值 `target`,可以通过经典的二分查找算法来定位目标值的位置。以下是完整的 Java 实现: ```java public class Solution { public int search(int[] nums, int target) { int left = 0; int right = nums.length - 1; while (left <= right) { int mid = (right - left) / 2 + left; // 计算中间索引以防止溢出 if (target == nums[mid]) { // 找到目标返回其索引 return mid; } else if (target < nums[mid]) { // 目标小于中间值,在左半部分继续查找 right = mid - 1; } else if (target > nums[mid]) { // 目标大于中间值,在右半部分继续查找 left = mid + 1; } } return -1; // 如果未找到则返回-1表示不存在该元素 } } ``` 此段代码展示了如何通过调整左右边界逐步缩小搜索范围直到找到目标或者确认目标不在列表中的过程[^2]。 为了进一步扩展应用,考虑一些变体问题如第一个错误版本或是在已排序数组中寻找两个数之和等于特定值的情况也可以采用类似的逻辑框架并做适当修改以适应具体需求[^3]。 #### 寻找左侧边界的二分查找题目要求找出某个条件成立的第一个位置时,则需要对上述标准形式稍作改动以便于处理这类情形: ```java int binarySearchLeftBound(int[] nums, int target){ int left = 0 , right = nums.length ; while(left<right){ int mid=(right-left)/2+left; if(nums[mid]==target) right=mid ;// 不立即返回而是收缩右侧边界尝试更早出现的目标 else if(nums[mid]<target) left=mid+1;// 继续向右探索更大的可能解空间 else if(nums[mid]>target) right=mid ;// 收缩右侧排除不可能区域 } if(left==nums.length || nums[left]!=target)// 检查越界以及最终结果验证 return -1 ; return left ; } ``` 这段代码实现了在存在重复项的情况下也能准确定位最左边匹配项的功能[^4]。 #### 应用于 Two Sum II 的解决方案 针对输入为升序排列数组求两数之和的问题,可以利用双指针加二分的思想快速得到答案: ```java public int[] twoSum(int[] numbers, int target) { for (int i = 0; i < numbers.length; ++i) { int low = i + 1, high = numbers.length - 1; while (low <= high) { int mid = (high - low) / 2 + low; if (numbers[mid] == target - numbers[i]) return new int[]{i + 1, mid + 1}; else if (numbers[mid] > target - numbers[i]) high = mid - 1; else low = mid + 1; } } throw new IllegalArgumentException("No solution"); } ``` 这里采用了固定一个数值作为基准再用另一个循环配合二分的方式高效解决问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值