算法

算法思想

二分查找

 public int binarySearch(int key, int[] nums) {
        int left = 0;
        int right = nums.length - 1;

        while (left <= right) {
            int mid = left + (right - left)/2;    //<1>

            if (key == nums[mid]){
                return mid;       //找到了
            }

            if (key < nums[mid]){
                right = mid - 1;
            }else{
                left = mid + 1;
            }
        }
        return -1;   //没找到
}

算法时间复杂度

       O(logN)

计算mid

      不要使用mid=(left + right)/2这种方式去计算mid,因为left+right可能会导致加法溢出,应该使用mid=left + (right - left)/2;

计算right

      当循环条件为 left <= right时,则 right = mid - 1;因为如果 right = mid,会出现循环无法退出的情况,例如 left = 1,right = 1,此时 mid 也等于 1,如果此时继续执行 right = mid,那么就会无限循环。

      当循环条件为 left < right时,则 right = mid。因为如果 right = mid - 1,会错误跳过查找的数,例如对于数组 [1,2,3],要查找 1,最开始 left = 0,right = 2,mid = 1,判断 key < arr[mid] 执行 right = mid - 1 = 0,此时循环退出,直接把查找的数跳过了;

返回值

       在循环条件为 left<= right 的情况下,循环退出时 left 总是比 right 大 1,并且 left 是将 key 插入 nums 中的正确位置。例如对于 nums = {0,1,2,3},key = 4,循环退出时 left = 4,将 key 插入到 nums 中的第 4 个位置就能保持 nums 有序的特点;

       在循环条件为 left < right 的情况下,循环退出时 l 和 h 相等;

       如果只是想知道 key 存不存在,在循环退出之后可以直接返回 -1 表示 key 不存在于 nums 中;

算法例题解析

LeetCode 69:x的平方根

       实现 int sqrt(int x) 函数。计算并返回 x 的平方根,其中 x 是非负整数。由于返回类型是整数,结果只保留整数的部分,小数部分将被舍去;

示例 1:
    输入: 4
    输出: 2
示例 2:
    输入: 8
    输出: 2
    说明: 8 的平方根是 2.82842..., 由于返回类型是整数,小数部分将被舍去;

       一个数x的开方根sqrt一定是在 0 ~ x 之间,并且满足 sqrt = x / sqrt;

       所以,可以利用二分查找在 0 ~ x 之间查找 sqrt;

       对于 x = 8,它的开方是 2.82842...,最后应该返回 2 而不是 3;在循环条件为 left <= right 并且循环退出时,right总是比 left小1,也就是说 right = 2,left= 3,因此最后的返回值应该为 right 而不是 left;

     public int mySqrt(int x) {
        if (x <= 1){
            return x;    //x是非负整数
        }

        int left = 1, right = x;

        while (left <= right) {
            int mid = left + (right - left) / 2;
            
            int sqrt = x / mid;
            
            if (sqrt == mid){
                return mid;       //求得结果
            }
            
            if (sqrt < mid){
                right = mid - 1; //sqrt < mid ,说明mid*mid > x,应该把mid变小
            }else{
                left = mid + 1;
            }
        }
        return right;
    }

LeetCode 441:排列硬币

       你总共有n枚硬币,你需要将它们摆成一个阶梯形状,第k行就必须正好有k枚硬币。给定一个数字 n,找出可形成完整阶梯行的总行数;

       n 是一个非负整数,并且在32位有符号整型的范围内;

示例 1:
    n = 5
    硬币可排列成以下几行:
    ¤
    ¤ ¤
    ¤ ¤

    因为第三行不完整,所以返回2.
示例 2:
    n = 8
    硬币可排列成以下几行:
    ¤
    ¤ ¤
    ¤ ¤ ¤
    ¤ ¤

    因为第四行不完整,所以返回3.

       第 i 行摆 i 个,统计能够摆的行数;

       n 个硬币能够摆的行数 row 在 0 ~ n 之间,并且满足 n = row * (row + 1) / 2,因此可以利用二分查找在 0 ~ n 之间查找 row;

       对于 n = 8,它能摆的行数 row = 3,这是因为最后没有摆满的那一行不能算进去,因此在循环退出时应该返回 h;

public int arrangeCoins(int n) {
    int l = 0, h = n;
    while (l <= h) {
        int mid = l + (h - l) / 2;
        long x = mid * (mid + 1) / 2;
        if (x == n) return mid;
        else if (x < n) l = mid + 1;
        else h = mid - 1;
    }
    return h;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值