【路飞】69. x 的平方根 、35. 搜索插入位置、1. 两数之和、34. 在排序数组中查找元素的第一个和最后一个位置

132 阅读2分钟

69. x 的平方根

给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target  的那 两个 整数,并返回它们的数组下标。

你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。

你可以按任意顺序返回答案。

示例 1:

输入: x = 4
输出: 2

示例 2:

输入: x = 8
输出: 2
解释: 8 的算术平方根是 2.82842..., 由于返回类型是整数,小数部分将被舍去。

解题思路:这题的解题思路是固定循环一百遍,因为二分算法每次都是将范围减少一半,所以一百遍会使head和tail足够接近,代码如下:

var mySqrt = function(x) {
    //边界条件处理,小于1就返回0
    if(x < 1) return 0;
    //二分其实位置head和末尾位置tail
    let head = 0,tail = x,m;
    //使查找的范围大于当前查找的值
    tail += 1;
    for(let i = 0; i < 100; i ++){
        //每次范围缩小一半,使head和tail接近
        m = (head + tail) / 2.0;
        if(m * m <= x) head = m;
        else tail = m;
    }
    return parseInt(head);
};

35. 搜索插入位置

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

请必须使用时间复杂度为 O(log n) 的算法。

示例 1:

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

示例 2:

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

示例 3:

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

解题思路:这题的要求是找到大于等于目标值的第一个参数,就是类似于0000011111模型找到第一个1,小于目标值的都是0 大于等于目标值的都是1,二分算法代码如下:

var searchInsert = function(nums, target) {
    let head = 0,tail = nums.length - 1,m;
    //最后三个数使用for循环更好,因为边界条件不好判断
    while(tail - head > 3){
        //计算中间值
        m = (head + tail) >> 1;
        //数组范围缩小一半.当中间值小于目标值说明目标值在后部分,当中间值大于目标值,说明在前半分
        if(nums[m] < target) head = m - 1;
        else tail = m;
    }
    for(let i = head; i <= tail; i ++){
        //从前往后对比,当大于等于目标值的时候,你就是目标值的位置
        if(nums[i] >= target) return i;
    }
    //至此说明没有找到目标值,所以目标值是最后一个
    return nums.length;
};

1. 两数之和

给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target  的那 两个 整数,并返回它们的数组下标。

你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。

你可以按任意顺序返回答案。

示例 1:

输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。

示例 2:

输入: nums = [3,2,4], target = 6
输出: [1,2]

示例 3:

输入: nums = [3,3], target = 6
输出: [0,1]

解题思路:这题的解题思路就是重组数组,然后从小到大排序,然后开始遍历重组的数组,在剩下的数字里找到目标值减当前值,找到的话就返回两个索引,代码如下:

var twoSum = function(nums, target) {
    //重组数组
    let data = [];
    for(let i = 0; i < nums.length; i ++){
        data.push({idx:i,val:nums[i]})
    }
    //从小到大排序
    data.sort((a,b) => {
        return a.val - b.val;
    })
    //开始遍历数组查找符合的数组
    for(let i = 0; i < data.length; i ++){
        // 查找剩下的数组里是否存在target - data[i].val
        let j =  two_sun(i + 1,data,target - data[i].val);
        //j == -1 说明不存在,进行下一轮比较
        if(j == -1) continue;
        至此说明找到对应值
        //return [data[i].idx,j]
    }
    return;
};

let two_sun = function(idx,data,target){
    let henad = idx, tail = data.length - 1,m;
    while(tail - henad > 3){
        m = (henad + tail) >> 1;
        if(data[m].val >= target) tail = m;
        else henad = m + 1;
    }
    for(let i = henad; i <= tail; i ++){
        //因为要返回的是索引,所以这里返回的是索引
        if(data[i].val == target) return data[i].idx; 
    }
    return -1;
}

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

给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。

如果数组中不存在目标值 target,返回 [-1, -1]。

示例 1:

输入: nums = [5,7,7,8,8,10], target = 8
输出: [3,4]

示例 2:

输入: nums = [5,7,7,8,8,10], target = 6
输出: [-1,-1]

示例 3:

输入: nums = [], target = 0
输出: [-1,-1]

解题思路:这题的解题思路也是模型00001111,其实位置值就是第一个1的位置,结尾位置就是目标值加一的1的位置,然后判断结尾的前一位是否等于目标值,如果是就是结尾位置,如果不是就是-1,代码如下:

var searchRange = function(nums, target) {
    //边界处理
    if(nums.length < 1 || (nums.length == 1 && nums[0] != target)) return [-1,-1];
    if(nums.length == 1) return [i,0]
    //查起始位置
    let i = search_range(0,nums,target);
    //判断第一个1是不是等于目标值,如果不是就说明不存在
    if(nums[i] != target ) return [-1,-1];
    let j = search_range(i,nums,target + 1);
    return [i,j - 1]
};
//以下是二分算法代码
let search_range = function(idx,data,target){
    let head = idx,tail = data.length,m;
    while(tail - head > 3){
        m = (head + tail) >> 1;
        if(data[m] < target) head = m + 1;
        else tail = m;
    }
    for(let i = head; i <= tail; i ++){
        if(data[i] >= target) return i;
    }
    return data.length;
}