力扣打卡(5) 二分思想:看似容易写时难... 边界控制不能少

18 篇文章 0 订阅
16 篇文章 0 订阅

9.29lc

本来想着继续刷递归 和 回溯呢: 谁知 被 二分查找吸引

简单介绍 二分: 一个有序的数组 找寻一个数字的方法

时间复杂度 log n: 优于普通的直接遍历

区别于 双指针

35. 搜索插入位置 - 力扣(LeetCode) (leetcode-cn.com)

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

34. 在排序数组中查找元素的第一个和最后一个位置 - 力扣(LeetCode) (leetcode-cn.com)

:要求复杂度 longn

上来的思路: 先找到 目标值。 然后 线性查找左右找边界 。。。 这样复杂度 为 n了

:真正的做法: 以左右边界来做文章, 我们去人为的 规定 左右边界:

找到第一个 找到最后一个 就可以了 很巧妙~~

class Solution {

    public int[] searchRange(int[] nums, int target) {
        int[] res = new int[] {-1, -1};
        res[0] = binarySearch(nums, target, true);
        res[1] = binarySearch(nums, target, false);
        return res;
    }
    //leftOrRight为true找左边界 false找右边界
    public int binarySearch(int[] nums, int target, boolean leftOrRight) {
        int res = -1;
        int left = 0, right = nums.length - 1, mid;
        while(left <= right) {
            mid = left + (right - left) / 2;
            if(target < nums[mid])
                right = mid - 1;
            else if(target > nums[mid])
                left = mid + 1;
            else {
                res = mid;
                //处理target == nums[mid]
                //控制边界问题
                if(leftOrRight)
                    right = mid - 1;
                else
                    left = mid + 1;
            }
        }
        return res;
    }
}

33. 搜索旋转排序数组 - 力扣(LeetCode) (leetcode-cn.com)

上边我们说到 二分用在 有序中:

这道题 是个旋转后的结果。 也是 部分有序的

思路: 中间值 和 左右 树 作比较 确定 有序的范围 从而进行寻找

class Solution {
    public int search(int[] nums, int target) {
         int l=0,r=nums.length-1;
              while (l<=r){
                  int mid =(l+r)/2;

                  if (nums[mid] == target){
                      return  mid;
                  }else  if (nums[mid]<nums[r]){
                      if (nums[mid] < target && target <=nums[r]){
                          l=mid+1;

                      }else {
                          r=mid-1;
                      }
                  }else {
                      if (nums[l] <= target && nums[mid] >target){
                          r =mid-1;
                       }else  {
                          l=mid+1;
                      }

                  }
              }
            return  -1;
    }
}

81. 搜索旋转排序数组 II - 力扣(LeetCode) (leetcode-cn.com)

新花样: 重复元素…

思路: 上文一样: 只不过 当

左右边界 和 中间值 相等时 记得 缩小边界

if(arr[mid] == arr[left] && arr[mid] == arr[right]){
    l++;
    r--;
}
class Solution {
    public boolean search(int[] nums, int target) {
        int n=nums.length;
           int l=0;
           int r=n-1;
   
       
        if(n == 0 ) return false;
        if(n == 1){
            return nums[0] == target;
        }
            while(l<=r){
                int mid = (l+r)/2;
                if(nums[mid] == target){
                    return true;
                } 
                // 找了半天   是中间值的 = 左 右  子树
                if(nums[l] == nums[mid] && nums[r] == nums[mid]){
                   ++l;
                   --r;
                }else if(nums[l]<=nums[mid]){
                    if(nums[l]<= target && target < nums[mid]){
                        r=mid-1;
                    }else{
                        l=mid+1;
                    }
                }else{
                    if(target <= nums[n-1] && target> nums[mid]){
                        l=mid+1;
                    }else{
                        r=mid-1;
                    }
                }
            }
            return false;
    }
}

153. 寻找旋转排序数组中的最小值 - 力扣(LeetCode) (leetcode-cn.com)

思路: 关于旋转的 题: 都可以试一下 边界 的比较~

发现和 有边界有关

class Solution {
    public int search(int[] nums, int target) {
         int l=0,r=nums.length-1;
              while (l<=r){
                  int mid =(l+r)/2;

                  if (nums[mid] == target){
                      return  mid;
                  }else  if (nums[mid]<nums[r]){
                      if (nums[mid] < target && target <=nums[r]){
                          l=mid+1;

                      }else {
                          r=mid-1;
                      }
                  }else {
                      if (nums[l] <= target && nums[mid] >target){
                          r =mid-1;
                       }else  {
                          l=mid+1;
                      }

                  }
              }
            return  -1;
    }
}

idea:

  1. 比较中间值 和 有边界 只有大小 如果大
  2. 、最小值再 右边 l=mid+1;
  3. else r=mid;

减 治 思想

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值