二分查找 leetcode 35 69 50 74

二分从简单到中等

leetcode 35. 搜索插入位置

给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。

你可以假设数组中无重复元素。

示例 1:

输入: [1,3,5,6], 5
输出: 2

示例 2:

输入: [1,3,5,6], 2
输出: 1

示例 3:

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

示例 4:

输入: [1,3,5,6], 0
输出: 0

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/search-insert-position

java代码解答

class Solution {
    public int searchInsert(int[] nums, int target) {
        int low=0;               
        int high=nums.length-1;  
        int mid;      
        while(low<high){
            //位运算优先级低于+号,尽量不要用low+high再右移,可能low+high超过数据类型的范围
            mid=low+((high-low)>>1);   
            if(target>nums[mid]){
                low=mid+1;
            }else if(target<nums[mid]){
                high=mid-1;
            }else{
                return mid;
            }
        }
        //跳出来的时候是low和high相等的时候
        if(nums[low]<target){
            return low+1;
        }else{
            return low;
        }
    }
}

69. x 的平方根

实现 int sqrt(int x) 函数。

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

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

示例 1:

输入: 4
输出: 2

示例 2:

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

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/sqrtx

java这样硬解会超时

class Solution {
    public int mySqrt(int x) {
        int i;
        for(i=0;i*i<x;i++){
            continue;
        }
        if(i*i==x){
            return i;
        }
        return i-1;
    }
}

下面做法用到了函数,其实实际要求肯定不是想让这个

class Solution {
    public int mySqrt(int x) {
        int i =(int)Math.sqrt(x);
        return i;
    }
}

下面是错误的二分,因为数字非常大的时候,mid*mid<x始终就是true

class Solution {
   public static int mySqrt(int x) {

    int low=0;
        int high=x;
        int mid;
        while(low<high){
            mid=low+((high-low)>>1);
            if(mid*mid<x){
                low=mid+1;
            }else if(mid*mid>x){
                high=mid-1;
            }else{
                return mid;
            }
        }
        if(low*low<=x){
            return low;
        }
        else{
            return low-1;
        }
    }
}

用double避免了算不出mid*mid,虽然过了,但是真真的想法应该不是想让你这样搞

 public static int mySqrt(int x) {

        int low=0;
        int high=x;
        double mid;
        while(low<high){
            mid=low+((high-low)>>1);
            if(mid*mid<x){
                low=(int)mid+1;
            }else if(mid*mid>x){
                high=(int)mid-1;
            }else{
                return (int)mid;
            }
        }
        if(low*low<=x){
            return low;
        }
        else{
            return low-1;
        }
    }

这样做应该最合适

class Solution {
   public static int mySqrt(int x) {
       //防止x/0情况发生
       if(x==0||x==1){
           return x;
       }
        int low=0;
        int high=x;
        int mid;
        while(low<high){
            mid=low+((high-low)>>1);
            if(x/mid>mid){
                low=mid+1;
            }else if(x/mid<mid){
                high=mid-1;
            }else{
                return mid;
            }
        }
        if(low*low<=x){
            return low;
        }
        else{
            return low-1;
        }
    }
}

官方给了另一种解法

「袖珍计算器算法」是一种用指数函数 exp⁡\expexp 和对数函数 ln⁡\lnln 代替平方根函数的方法。我们通过有限的可以使用的数学函数,得到我们想要计算的结果。

我们将 x\sqrt{x}x

​ 写成幂的形式 x1/2x^{1/2}x1/2,再使用自然对数 eee 进行换底,即可得到

x=x1/2=(eln⁡x)1/2=e12ln⁡x\sqrt{x} = x^{1/2} = (e ^ {\ln x})^{1/2} = e^{\frac{1}{2} \ln x} x

​=x1/2=(elnx)1/2=e21​lnx

这样我们就可以得到 x\sqrt{x}x

​ 的值了。

注意: 由于计算机无法存储浮点数的精确值(浮点数的存储方法可以参考 IEEE 754,这里不再赘述),而指数函数和对数函数的参数和返回值均为浮点数,因此运算过程中会存在误差。例如当 x=2147395600x = 2147395600x=2147395600 时,e12ln⁡xe^{\frac{1}{2} \ln x}e21​lnx 的计算结果与正确值 463404634046340 相差 10−1110^{-11}10−11,这样在对结果取整数部分时,会得到 463394633946339 这个错误的结果。

因此在得到结果的整数部分 ans\textit{ans}ans 后,我们应当找出 ans\textit{ans}ans 与 ans+1\textit{ans} + 1ans+1 中哪一个是真正的答案。

作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/sqrtx/solution/x-de-ping-fang-gen-by-leetcode-solution/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

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

作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/sqrtx/solution/x-de-ping-fang-gen-by-leetcode-solution/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

static double log(double a)
返回的自然对数(以 e为底) double值。
static double exp(double a)
返回欧拉的数字 e提高到一个 double价值。 应该意思就是求指数

50. Pow(x, n)

实现 pow(x, n) ,即计算 x 的 n 次幂函数(即,xn)。

示例 1:

输入:x = 2.00000, n = 10
输出:1024.00000

示例 2:

输入:x = 2.10000, n = 3
输出:9.26100

示例 3:

输入:x = 2.00000, n = -2
输出:0.25000
解释:2-2 = 1/22 = 1/4 = 0.25

提示:

-100.0 < x < 100.0
-231 <= n <= 231-1
-104 <= xn <= 104

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/powx-n

java解答

快速幂,其实发现如果用递归思路非常明显,用迭代思路就没那么好看了,但是两个都可以,想明白了就都一样

/*
快速幂加递归
递归三步 递归的思路解决  找子问题 找终止条件 写递归条件*/
/*
快速幂加递归
递归三步 递归的思路解决  找子问题 找终止条件 写递归条件*/
class Solution {
    public double myPow(double x, int n) {
        if(n==0||x==1){
            return 1;
        }
        if(x==0){
            return 0;
        }
        //就是这句话没有导致数组越界了
        if (n == Integer.MIN_VALUE) return myPow(x, n + 1) / x;
        if(n<0){
            return 1/kmFun(x,-n);
        }
        return kmFun(x,n);
    }
    double kmFun(double x,int n){
        终止条件
        if(n==1){
            return x;
        }
        
        if(n%2!=0){
             //奇数的时候
            double mid=kmFun(x,n/2);
            return mid*mid*x;    
        } 
        //如果是偶数,再递归
        double mid=kmFun(x,n/2);
        return mid*mid;
    }
}

74 . 搜索二维矩阵

题目内容

编写一个高效的算法来判断 m x n 矩阵中,是否存在一个目标值。该矩阵具有如下特性:

每行中的整数从左到右按升序排列。
每行的第一个整数大于前一行的最后一个整数。

示例 1:
在这里插入图片描述

输入:matrix = [[1,3,5,7],[10,11,16,20],[23,30,34,60]], target = 3
输出:true

示例 2:
在这里插入图片描述

输入:matrix = [[1,3,5,7],[10,11,16,20],[23,30,34,60]], target = 13
输出:false

提示:

m == matrix.length
n == matrix[i].length
1 <= m, n <= 100
-104 <= matrix[i][j], target <= 104

通过次数89,098
提交次数216,622

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/search-a-2d-matrix

java解答 虽然解法时间0ms,但是感觉能把二维矩阵变成一维数组,然后二分,这样效果说不定更好

/*
两次二分,找到中间的*/

class Solution {
    public boolean searchMatrix(int[][] matrix, int target) {
        //先二分找到所在行
        //行数
        int m=matrix.length;
        //列数
        int n=matrix[0].length;

        //二分找到行
        int left=0;
        int right=m-1;
         
        while(left<right){
        	//除二换成位运算也蛮好的,但记得优先级,加括号
            int mid=left+(right-left)/2;
            if(target>matrix[mid][n-1]){
                left=mid+1;
            }else if(target<matrix[mid][n-1]){
                //这里只能等于mid,肯定不能mid-1,否则正确的行就会变没
                right=mid;
            }else{
                return true;
            }
        }
        //此时后出来的left就是确定的行
        int hang=left;
        left=0;
        right=n-1;
        while(left<right){
            int mid=left+(right-left)/2;
            if(target>matrix[hang][mid]){
                left=mid+1;
            }else if(target<matrix[hang][mid]){
                //这里只能等于mid,肯定不能mid-1,否则正确的行就会变没
                right=mid;
            }else{
                return true;
            }
        }
        //防止只有一个的时候
        if(matrix[hang][left]==target){
            return true;
        }
        return false;  
    }
}

一次二分实现

/*
一次二分*/

class Solution {
    public boolean searchMatrix(int[][] matrix, int target) {
        //先二分找到所在行
        //行数
        int m=matrix.length;
        //列数
        int n=matrix[0].length;

        //二维数组转化一维数组,然后再二分查找,效率会更高
        int left=0;
        int right=m*n-1;
        while(left<right){
            //除二换成位运算也蛮好的,但记得优先级,加括号
            int mid=left+((right-left)>>1);
            if(target>matrix[mid/n][mid%n]){
                left=mid+1;
            }else if(target<matrix[mid/n][mid%n]){
                //这里只能等于mid,肯定不能mid-1,否则正确的行就会变没
                right=mid;
            }else{
                return true;
            }
        }
        if(target==matrix[left/n][left%n]){
            return true;
        }  
        return false;  
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值