代码随想录 LeetCode数组篇 二分查找

这篇具有很好参考价值的文章主要介绍了代码随想录 LeetCode数组篇 二分查找。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。


# (简单)704. 二分查找

代码随想录 LeetCode数组篇 二分查找

题目链接

代码随想录 - 二分查找思路

二分查找,思路很简单,但是在while循环left和right的比较是写<=还是<,还有right=mid还是right=mid-1容易混淆

需要想清楚对区间的定义,是[left,right],还是[left,right)

代码随想录 LeetCode数组篇 二分查找

代码随想录 LeetCode数组篇 二分查找
代码随想录 LeetCode数组篇 二分查找

代码随想录 LeetCode数组篇 二分查找
代码随想录 LeetCode数组篇 二分查找

(版本一,左闭右闭版本)

class Solution {
    public int search(int[] nums, int target) {
        int left = 0;
        int right = nums.length - 1;
        int mid;
        while (left <= right) {
            mid = left + ((right-left)/2);//防止溢出
            if (nums[mid] == target) {
                return mid;
            }
            if (target > nums[mid]) {
                left = mid + 1;
            } else {
                right = mid - 1;
            }
        }
        return -1;
    }
}

(版本二,左闭右开)

class Solution {
    public int search(int[] nums, int target) {

        //避免当target小于nums[0] 或者大于 nums[nums.length-1]时 多次循环
        if (target < nums[0] || target > nums[nums.length - 1]) {
            return -1;
        }

        int left = 0;
        int right = nums.length;
        int mid;
        while (left < right) {
            mid = left + ((right - left) >> 1);
            if (nums[mid] == target) {
                return mid;
            }
            if (target > nums[mid]) {
                left = mid + 1;
            } else {
                right = mid;
            }
        }
        return -1;
    }
}

(简单)35. 搜索插入位置

题目链接

代码随想录 LeetCode数组篇 二分查找

class Solution {
    public int searchInsert(int[] nums, int target) {
        int left = 0;
        int right = nums.length - 1;
        int mid;
        while (left <= right) {
            mid = left + ((right - left) >> 1);
            if (nums[mid] == target) {
                return mid;
            }
            if (target > nums[mid]) {
                left = mid + 1;
            } else {
                right = mid - 1;
            }
        }
        return left;//right+1
    }
}

(*中等)34. 在排序数组中查找元素的第一个和最后一个位置

代码随想录 LeetCode数组篇 二分查找
题目链接

我的思路:按照传统二分查找的方式,找到等于target的数组的下标,然后向两边扩展,如果没找到直接返回[-1,-1]

代码随想录 LeetCode数组篇 二分查找

class Solution {

    public int[] searchRange(int[] nums, int target) {

        //如果数组长度是0,则不用判断
        if (nums == null || nums.length == 0) {
            return new int[]{-1, -1};
        }

        //如果target的值小于第一个元素或者大于最后一个元素,也不用判断
        if ((target < nums[0]) || (target > nums[nums.length - 1])) {
            return new int[]{-1, -1};
        }

        int res = search(nums, target);
        if (res == -1) {
            return new int[]{-1, -1};
        }
        int left = res;
        int right = res;
        while ((left >= 0) && (nums[left] == nums[res])) {
            left--;
        }
        while ((right < nums.length) && (nums[right] == nums[res])) {
            right++;
        }
        return new int[]{left + 1, right - 1};
    }

    public int search(int[] nums, int target) {
        int left = 0;
        int right = nums.length - 1;
        int mid;
        while (left <= right) {
            mid = left + ((right - left) >> 1);
            if (target == nums[mid]) {
                return mid;
            }
            if (target > nums[mid]) {
                left = mid + 1;
            } else {
                right = mid - 1;
            }
        }
        return -1;
    }
}

看了官方的解题思路,是找出数组中【第一个等于target的位置(leftIdx)】和【第一个大于target的位置减一(rightIdx)】

二分查找中

  • 寻找leftIdx即为在数组中寻找第一个大于等于 target的下标
  • 寻找rightIdx即为在数组中寻找第一个大于 target的下标,然后减一

二者的判断条件不同,为了代码的复用,定义一个函数,其中包含布尔类型的lower参数,该参数为true时,则查找第一个大于等于target的下标,该参数为false时,则查找第一个大于target的下标

最后,因为target可能不在数组中,因此需要重新校验两个下标leftIdx和rightIdx,看是否符合条件,如果符合,就返回[leftIdx,rightIdx],不符合就返回[-1,-1]
代码随想录 LeetCode数组篇 二分查找

class Solution {

    public int[] searchRange(int[] nums, int target) {

        //如果数组长度是0,则不用判断
        if (nums == null || nums.length == 0) {
            return new int[]{-1, -1};
        }

        //如果target的值小于第一个元素或者大于最后一个元素,也不用判断
        if ((target < nums[0]) || (target > nums[nums.length - 1])) {
            return new int[]{-1, -1};
        }

        int leftIdx = search(nums, target, true);
        int rightIdx = search(nums, target, false) - 1;

        if (leftIdx >= 0 && rightIdx < nums.length && leftIdx <= rightIdx && nums[leftIdx] == target && nums[rightIdx] == target) {
            return new int[]{leftIdx, rightIdx};
        }
        return new int[]{-1, -1};

    }

    public int search(int[] nums, int target, boolean lower) {
        int left = 0;
        int right = nums.length - 1;
        int mid;
        int ans = nums.length;
        while (left <= right) {
            mid = left + ((right - left) >> 1);

            //说明当前的mid所在的值比target大,需要缩小范围
            //找leftIdx,如果target小于nums[mid],缩小范围
            //如果target==nums[mid],也要缩小范围,但是会记录mid
            //找rightIdx,只要target<nums[mid],缩小范围
            if (target < nums[mid] || (lower && target == nums[mid])) {
                right = mid - 1;
                ans = mid;
            } else {
                //找rightIdx,只要target < nums[mid] 不成立
                //也就是target=nums[mid]或者target>nums[mid] left都会变化
                left = mid + 1;
            }
        }
        return ans;
    }
}

(简单,常见面试题)69. x的平方根

代码随想录 LeetCode数组篇 二分查找
我的思路,将x的值赋给tmp,将tmp不断除以2

记录下面两个数,在这两个数之间使用二分查找:

  1. 使得tmp^2小于x的最大的tmp值
  2. 使得tmp^2大于x的最小的tmp值
class Solution {
    public int mySqrt(int x) {
        if (x == 0 || x == 1) {
            return x;
        }

        int pre = x;
        int tmp = x / 2;
        while (tmp > x / tmp) { //原来是 tmp * tmp > x
            pre = tmp;
            tmp /= 2;
        }

        if (tmp == x / tmp) { //原来是 tmp * tmp == x 
            return tmp;
        }

        //pre和tmp之间找到答案,缩小范围
        return search(x, tmp, pre);
    }

    public int search(int x, int tmp, int pre) {
        int left = tmp;
        int right = pre;
        int mid;
        int ans = tmp;
        while (left <= right) {
            mid = left + ((right - left) >> 1);
            if (mid == x / mid) { //原来是 mid * mid == x
                return mid;
            }
            if (mid > x / mid) { // 原来是mid * mid > x
                right = mid - 1;
            } else {
                ans = mid;
                left = mid + 1;
            }
        }
        return ans;
    }
}

官网解答,笔记:

在不使用 x \sqrt{x} x 函数的情况下,得到x的平方根的整数部分。一般的思路有以下几种:

  • 通过其它的数学函数代替平方根函数得到精确结果,取整数部分作为答案
  • 通过数学方法得到近似结果,直接作为答案

方法一 袖珍计算器算法

【袖珍计算器算法】是一种用指数函数exp和对数函数ln代替平方根函数的方法。通过有限的、可以使用的数学函数,得到想要的结果。

代码随想录 LeetCode数组篇 二分查找
当x=2147395600时, e 1 2 ln ⁡ x e^{\frac{1}{2}\ln x} e21lnx​的计算结果与正确值46340相差 1 0 − 11 10^{-11} 1011,这样在对结果取整数部分时,会得到46339这个错误结果。

因此,在得到结果的整数部分ans后,应该找出ans与ans+1中哪一个是真正的答案。

class Solution {
    public int mySqrt(int x) {
        if (x == 0 || x == 1) {
            return x;
        }
        int ans = (int) Math.exp(0.5 * Math.log(x));
        return (long) (ans + 1) * (ans + 1) > x ? ans : ans + 1;
    }
}

方法二 二分查找

由于x平方根的整数部分ans是满足 k 2 ≤ x k^2 \leq x k2x的最大k值,因此可以对k进行二分查找,从而得到答案

二分查找的下界是1,上界可以粗略的=地设定为x。在二分查找中的每一步中,我们只需要比较中间元素mid的平方与x的大小关系,并通过比较的结果调整上下界的范围。由于我们所有的运算都是整数运算,所以,不会存在误差,因此在得到最终的答案ans后,也就不需要再去尝试ans+1了。

class Solution {
    public int mySqrt(int x) {
        if (x == 0 || x == 1) {
            return x;
        }
        int left = 1;
        int right = x;
        int mid;
        int ans = -1;
        while (left <= right) {
            mid = left + ((right - left) >> 1);
            if ((long) mid * mid == x) {
                return mid;
            }
            if ((long) mid * mid < x) {
                ans = mid;
                left = mid + 1;
            } else {
                right = mid - 1;
            }
        }
        return ans;
    }
}

(简单) 367. 有效的完全平方数

代码随想录 LeetCode数组篇 二分查找
二分查找

class Solution {
    public boolean isPerfectSquare(int num) {
        if (num == 1) {
            return true;
        }
        int left = 1;
        int right = num;
        int mid;
        while (left <= right) {
            mid = left + ((right - left) >> 1);
            if ((long) mid * mid == num) {
                return true;
            }
            if ((long) mid * mid < num) {
                left = mid + 1;
            } else {
                right = mid - 1;
            }
        }
        return false;
    }
}

当然还可以使用内置的库函数

根据完全平方数的性质,只需要判断num的平方根x是否为整数即可。

class Solution {
    public boolean isPerfectSquare(int num) {
        int x = (int) Math.sqrt(num);
        return x * x == num;
    }
}

还有暴力法

如果num为完全平方数,那么一定存在正整数x满足x * x = num。于是,可以从1开始遍历所有的正整数,一直遍历到46340即可,因为 2 31 − 1 ≈ 46340 \sqrt{2^{31}-1} \approx 46340 2311 46340文章来源地址https://www.toymoban.com/news/detail-430917.html

class Solution {
    public boolean isPerfectSquare(int num) {
        if (num == 1) {
            return true;
        }
        for (int i = 2; i <= 46340; i++) {
            if (i * i > num) {
                break;
            }
            if (i * i == num) {
                return true;
            }
        }
        return false;
    }
}

到了这里,关于代码随想录 LeetCode数组篇 二分查找的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【代码随想录算法第一天| 704.二分查找 27.移除元素】

    题目链接:二分查找 文章讲解:代码随想录.二分查找 视频讲解:手把手带你撕出正确的二分法 | 二分查找法 | 二分搜索法 | LeetCode:704. 二分查找_哔哩哔哩_bilibili 二分前提:有序数组,数组中无重复元素 方法:结合数组的特征,可以为左闭右闭区间[0, 数组长度-1],或者左

    2024年02月16日
    浏览(45)
  • 【代码随想录 | Leetcode | 第四天】数组 | 螺旋矩阵 | 59

    欢迎来到小K的Leetcode|代码随想录|专题化专栏,今天将为大家带来螺旋矩阵的分享 ✨ 给你一个正整数 n ,生成一个包含 1 到 n 2 所有元素,且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix 。 示例 1: 示例 2: 提示: 思路: 本类型题目其实都不涉及什么算法,就是模拟

    2024年02月16日
    浏览(48)
  • 【代码随想录 | Leetcode | 第四天】数组 | 螺旋矩阵 | 59-54

    欢迎来到小K的Leetcode|代码随想录|专题化专栏,今天将为大家带来螺旋矩阵的分享 ✨ 给你一个正整数 n ,生成一个包含 1 到 n 2 所有元素,且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix 。 示例 1: 示例 2: 提示: 思路: 本类型题目其实都不涉及什么算法,就是模拟

    2024年02月16日
    浏览(46)
  • 代码随想录Day1 | 数组01- leetcode 704、27

    题目链接:二分查找 关键问题:         - 边界(left、right)、当前查找值(middle)                 - target大于当前查找值 -- 当前查找区域的右边,更改区间left                 - target小于当前查找值 -- 当前查找区域的左边,更改区间right                 - middle的计

    2024年02月16日
    浏览(47)
  • 【代码随想录-Leetcode第六题:209. 长度最小的子数组】

    给定一个含有 n 个正整数的数组和一个正整数 target 。 找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl+1, …, numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0 。 参考【代码随想录】 示例 1: 示例 3: 提示: 1 = target = 109 1 = nums.length

    2024年02月12日
    浏览(43)
  • 代码随想录第6天| 哈希表理论基础 ,LeetCode242.有效的字母异位词,LeetCode349. 两个数组的交集,LeetCode202. 快乐数,LeetCode1. 两数之和

    哈希表(散列表)理论基础 : 哈希表是根据关键码的值而直接进行访问的数据结构。 直白来讲其实数组就是一张哈希表。   什么时候想到用哈希法, 当我们遇到了要快速判断一个元素是否出现集合里的时候,就要考虑哈希法 。 当我们遇到了要快速判断一个元素是否出现集

    2024年02月10日
    浏览(65)
  • 代码随想录Leetcode70. 爬楼梯

            空间复杂度为O(N),如果想要优化空间复杂度,则只用三个变量进行状态转移也可以,参考 代码随想录 Leetcode509. 斐波那契数-CSDN博客

    2024年02月19日
    浏览(82)
  • 代码随想录Leetcode 343. 整数拆分

            dp[i]表示i所能拆分的最大乘积,则dp[i] 与dp[i - 1]的递推公式是:                 max( 1~n * dp[n ~ 1])

    2024年02月21日
    浏览(85)
  • 代码随想录 Leetcode18. 四数之和

            不行了,今天做了太多n数之和要吐了,太恶心了,一堆剪枝,去重太恶心人了。最后还是照着卡哥的改

    2024年01月17日
    浏览(94)
  • 代码随想录 Leetcode763. 划分字母区间

    2024年02月21日
    浏览(120)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包