https://labuladong.github.io/algo/2/19/52/
https://labuladong.github.io/algo/1/9/
https://github.com/youngyangyang04/leetcode-master/blob/master/problems/0704.%E4%BA%8C%E5%88%86%E6%9F%A5%E6%89%BE.md

基础理论

https://github.com/youngyangyang04/leetcode-master/blob/master/problems/0704.%E4%BA%8C%E5%88%86%E6%9F%A5%E6%89%BE.md
适用场景:

  1. 数组有序
  2. 无重复元素(如果有重复元素),元素下标可能不是唯一

框架:

  1. //arr为排序数组
  2. ============== 递归实现 ==================
  3. function Binary_search(arr,beigin,end,target){
  4. if(beigin>end) {
  5. return false
  6. }
  7. var mid = Math.floor((left+right)/2)
  8. if(arr[mid] == target){
  9. return true
  10. }
  11. if(arr[mid]<target){
  12. return Binary_search(arr,begin,mid-1,target)
  13. }
  14. if(arr[mid]>target){
  15. return Binary_search(arr,begin+1,end,target)
  16. }
  17. }
  18. ============== 循环实现 ==================
  19. function Binary_search(arr,target){
  20. var begin =0;
  21. var end=arr.length-1;
  22. while(begin<end){
  23. var mid = Math.floor((left+right)/2)
  24. if(target == arr[mid]){
  25. return true
  26. }
  27. if(target > arr[mid]){
  28. begin = mid+1
  29. }
  30. if(target >arr[mid]){
  31. end = mid-1
  32. }
  33. }
  34. }
  1. // (版本一)左闭右闭区间
  2. /**
  3. * @param {number[]} nums
  4. * @param {number} target
  5. * @return {number}
  6. */
  7. /**
  8. var search = function(nums, target) {
  9. let left = 0, right = nums.length - 1;
  10. // 使用左闭右闭区间
  11. while (left <= right) {
  12. let mid = left + Math.floor((right - left)/2);
  13. if (nums[mid] > target) {
  14. right = mid - 1; // 去左面闭区间寻找
  15. } else if (nums[mid] < target) {
  16. left = mid + 1; // 去右面闭区间寻找
  17. } else {
  18. return mid;
  19. }
  20. }
  21. return -1;
  22. };
  23. // (版本二)左闭右开区间
  24. /**
  25. * @param {number[]} nums
  26. * @param {number} target
  27. * @return {number}
  28. */
  29. var search = function(nums, target) {
  30. let left = 0, right = nums.length;
  31. // 使用左闭右开区间 [left, right)
  32. while (left < right) {
  33. let mid = left + Math.floor((right - left)/2);
  34. if (nums[mid] > target) {
  35. right = mid; // 去左区间寻找
  36. } else if (nums[mid] < target) {
  37. left = mid + 1; // 去右区间寻找
  38. } else {
  39. return mid;
  40. }
  41. }
  42. return -1;
  43. };

练习

704. 二分查找

image.png

  1. var search = function(nums, target) {
  2. let left = 0, right = nums.length - 1;
  3. // 使用左闭右闭区间
  4. while (left <= right) {
  5. let mid = left + Math.floor((right - left)/2);
  6. if (nums[mid] > target) {
  7. right = mid - 1; // 去左面闭区间寻找
  8. } else if (nums[mid] < target) {
  9. left = mid + 1; // 去右面闭区间寻找
  10. } else {
  11. return mid;
  12. }
  13. }
  14. return -1;
  15. };

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

image.png
两个二分法 分别找左边界和右边界

  1. var searchRange = function(nums, target) {
  2. var left = leftBound(nums,target);
  3. var right = rightBound(nums,target);
  4. return [left,right]
  5. };
  6. //[...1,3,3,3,3,5,6..]
  7. // mid
  8. //查找左端点
  9. function leftBound(nums,target){
  10. var left=0;
  11. var right=nums.length-1;
  12. while(left <= right){
  13. var mid= Math.floor((right+left)/2);
  14. if(nums[mid] == target) {
  15. if(mid == 0 || nums[mid-1]<target){
  16. return mid //该位置是左端点
  17. }
  18. right = mid-1
  19. }else if(nums[mid]<target){
  20. left = mid+1;
  21. }else if(nums[mid]>target){
  22. right = mid-1;
  23. }
  24. }
  25. return -1;
  26. }
  27. //[...1,3,3,3,3,5,6..]
  28. // mid
  29. //查找右端点
  30. function rightBound(nums,target){
  31. var left=0;
  32. var right=nums.length-1;
  33. while(left <= right){
  34. var mid = Math.floor((right+left)/2);
  35. if(nums[mid] ==target) {
  36. if(mid == nums.length-1 || nums[mid+1]>target){
  37. return mid //该位置是右端点
  38. }
  39. left = mid+1
  40. }else if(nums[mid]<target){
  41. left = mid+1;
  42. }else if(nums[mid]>target){
  43. right = mid-1;
  44. }
  45. }
  46. return -1;
  47. }

35. 搜索插入位置

image.png

var searchInsert = function(nums, target) {

    var left =0;
    var right = nums.length-1;
    var index = -1;
    //index是最终元素的下标,如果没有找到就是元素的插入位置
    while(left <= right){
        var mid =left +  Math.floor((right-left)/2)
        if(nums[mid]==target){
             index = mid
        } else if (nums[mid]>target){
            if(mid ==0 || nums[mid-1]<target){
                index = mid
            }
            right = mid-1; 
        }else if(target > nums[mid]){
            if(mid == nums.length-1 || target<nums[mid+1]){
                index = mid+1
            }
            left = mid+1
        }       
    }   
     return index;  
};

4. 寻找两个正序数组的中位数

image.png
给定两个大小为 m 和 n 的有序数组 nums1 和 nums2。
请你找出这两个有序数组的中位数,并且要求算法的时间复杂度为 O(log(m + n))。

你可以假设 nums1 和 nums2 不会同时为空。
https://www.bilibili.com/video/av55640101?from=search&seid=16181943450989372605
示例 1:
nums1 = [1, 3]
nums2 = [2]
则中位数是 2.0

示例 2:
nums1 = [1, 2]
nums2 = [3, 4]

则中位数是 (2 + 3)/2 = 2.5

分析:
image.png

image.png

image.png
image.png
思路:
时间复杂度提示使用二分法,合并数组中找到合适分界点,是中位数。
合并数组过程中,蓝色区域始终小于黄色区域,需要满足L1<=R2,L2<=R1
从较短数组开始二分

有序数组中位数
function getMidian(num){
var len = num.length
return (num[Math.floor((len-1)/2)]+num[Math.floor(len/2)]) /2
}

/**
 * @param {number[]} nums1
 * @param {number[]} nums2
 * @return {number}
 */
var findMedianSortedArrays = function(nums1, nums2) {
    //从较短数组开始遍历
    if(nums1.length > nums2.length) [nums1,nums2]=[nums2,nums1]

    var len1 = nums1.length;
    var len2 = nums2.length;

    //如果数组1为空 直接返回数组2的中位数
    if(len1 === 0){
        return (nums2[Math.floor((len2-1)/2)]+ nums2[Math.floor(len2/2)])/2
    }

    var len = len1+len2;
    var start1 = 0
    var end1 = len1; //?
    var cut1,cut2; //数组num1 num2分割线左边元素个数

    while(start1<=end1){
        cut1 = Math.floor((start1+end1)/2);
        //len+1  最后个数为奇数的时候,返回为左侧的最大值
        cut2 = Math.floor((len+1)/2)-cut1;  

        var L1 = cut1 === 0?-Infinity:nums1[cut1-1];
        var L2 = cut2 === 0?-Infinity:nums2[cut2-1];
        var R1 = cut1 === len1?Infinity:nums1[cut1];
        var R2 = cut2 === len2?Infinity:nums2[cut2];

        if(L1 > R2){
            end1 = cut1-1 
        } else if (L2 > R1){
            start1 = cut1+1   
        } else {
            if(len%2 === 0){
                return (Math.max(L1,L2) + Math.min(R1,R2))/2
            } else {
                return Math.max(L1,L2)
            }
        }
    }
    return -1 
};