力扣刷题记录04

题目分类 :二分查找
时间:2020-09-08

题目一 :数组交集

给定两个数组,编写一个函数来计算它们的交集。
示例 1:
输入:nums1 = [1,2,2,1], nums2 = [2,2]
输出:[2,2]
示例 2:
输入:nums1 = [4,9,5], nums2 = [9,4,9,8,4]
输出:[4,9]

思路
解法一 : 哈希表法

遍历第一个数组时利用哈希表记录所有数字的出现频率,遍历第二个数组时可以快速查询哪些元素在第一个数组中曾经出现,遍历完毕后即可得到两数组的交集。

代码

    let res = [];
    let map = {};
    for (let i = 0; i < nums1.length; i++) {
        if (map[nums1[i]] != undefined) {
            map[nums1[i]]++;
        } else {
            map[nums1[i]] = 1;
        }
    }

    for (let j = 0; j < nums2.length; j++) {
        if (map[nums2[j]] != undefined && map[nums2[j]] != 0) {
            res.push(nums2[j]);
            map[nums2[j]]--;
        }
    }

    return res

解法二 : 二分查找
使用sort函数将其中一个数组排序,再使用二分查找筛选出两数组交集。
代码

    nums2.sort((a, b) => a - b);
    let resArr = [];
    var searchNumber = function (target) {
        let left = 0;
        let right = nums2.length-1;
        if (nums2[left] == target) {
            nums2.splice(left, 1)
            return true;
        }
        if (nums2[right] == target) {
            nums2.splice(right, 1)
            return true;
        }
        while (left < right-1) {
            let mid = Math.floor((left + right) * 0.5);
            if (nums2[mid] == target) {
                nums2.splice(mid, 1);
                return true;
            }
            if (nums2[mid] < target) {
                left = mid;
            }
            if (nums2[mid] > target) {
                right = mid;
            } 
        }
        return false;
    }

    for (let i = 0; i < nums1.length; i++) {
        if (searchNumber(nums1[i])) {
            resArr.push(nums1[i])
        }
    }

    return resArr;

题目二 :X的平凡根

计算并返回 x 的平方根,其中 x 是非负整数。
由于返回类型是整数,结果只保留整数的部分,小数部分将被舍去。
示例 1:
输入: 4
输出: 2
示例 2:
输入: 8
输出: 2
说明: 8 的平方根是 2.82842…,
由于返回类型是整数,小数部分将被舍去。

思路
题目只要求返回整数部分,因此可在一个有序递增数组【1,2,3…x】中寻找一个数n,使得n的平方小于x,(n+1)的平方大于x,那么n即为x的平方根。在有序数组中查找数据,还是使用典型的二分查找方法。

代码

    let left = 0;
    let right = x;
    if (x == 0 || x == 1) return x;
    while (left < right - 1) {
        let mid = Math.floor((left + right) * 0.5)
        if (mid * mid == x) {
            return mid
        }
        if (mid * mid < x) {
            if ((mid + 1) * (mid + 1) > x) {
                return mid
            } else {
                left = mid;
            }
        }
        if (mid * mid > x) {
            if ((mid - 1) * (mid - 1) < x) {
                return (mid-1)
            }else{
                right = mid;
            }
        }
    }

题目三 :旋转数组中的最小数字

把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素。例如,数组 [3,4,5,1,2] 为 [1,2,3,4,5] 的一个旋转,该数组的最小值为1。
示例 1:
输入:[3,4,5,1,2]
输出:1
示例 2:
输入:[2,2,2,0,1]
输出:0

思路
题目的难点在于使用二分查找后,范围的选择和逼近方式的判断。主要的判断步骤写在代码的注释中,条理相对更清晰一些

代码

var minArray = function (numbers) {
    let left = 0;
    let right = numbers.length - 1;
    while (left < right - 1) {
        let mid = Math.floor((left + right) * 0.5);
        if (numbers[mid] > numbers[right]) { //当right指针的值小于mid指针指向的数值时,最小值在mid右侧,如数组[7,8,9,10,11,12,1,2,3],此时mid指向11,right指向3
            left = mid;
            continue;
        }
        if (numbers[mid] < numbers[right]) { //当right指针的值大于mid指针指向的数值时,最小值在mid左侧,如数组[10,6,7,8,9],此时mid指向7,right指向9
            right = mid
            continue;
        }
        if (numbers[mid] == numbers[right]) {
        //当mid指向的值和right指向的值相等时,最小值可能在左侧(如[11,5,6,7,7,7,7],此时mid和right均指向7)、右侧(如数组[7,7,7,7,5,6,7],此时,mid与right均指向7)或本身(如数组[7,7,7])
            right--;
            //取另一个right
            if (right == mid) {
   
                right = mid;
            }
        }
    }

    if (numbers[left] < numbers[right]){
        return numbers[left]
    }else{
        return numbers[right]
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值