LeetCode题目记录

92 阅读4分钟

二分查找

[744. 寻找比目标字母大的最小字母](简单)

题目描述:

给你一个排序后字符列表 letters ,列表中只包含小写英文字母。另给出一个目标字母 target,请你寻找在这一有序列表里比目标字母最小字母

在比较时,字母是依序循环出现的。举个例子:

  • 如果目标字母 target = 'z' 并且字符列表为 letters = ['a', 'b'],则答案返回 'a'

注: 若字符列表中没有比目标字母大的,则返回列表中第一个字母

  示例 1:

输入: letters = ["c", "f", "j"],target = "a"
输出: "c"

示例 2:

输入: letters = ["c","f","j"], target = "c"
输出: "f"

示例 3:

输入: letters = ["c","f","j"], target = "d"
输出: "f"

提示:

  • 2 <= letters.length <= 104
  • letters[i]是一个小写字母
  • letters 按非递减顺序排序
  • letters 最少包含两个不同的字母
  • target 是一个小写字母

解题方法

方法一:按顺序查找

已知给定的数组是按照递增的顺序排序,因此可以通过遍历列表,从左往右开始查找第一个比目标字母大的字母,即为比目标字母大的最小字母

var nextGreatestLetter = function (letters, target) {
    const length = letters.length;
    //先将列表的第一个字母赋给result
    let result = letters[0];
    for (let i = 0; i < length; i++) {
        //当某一个列表字母大于目标字母,将该字母赋给result
        if (letters[i] > target) {
            result = letters[i];
            break;
        }
    }
    //返回结果
    return result;
};

方法二:二分查找

因为列表是有序的,适合使用二分法来进行查找

  • 首先比较目标字母和列表的最后一个字母,如果目标字母大于或等于列表的最后一个字母,则列表中就不存在比目标字母大的字母,此时返回列表的第一个字母;反之,列表中一定存在比目标字母大的字母;

  • 进行二分查找,初始时,二分查找的范围是整个列表的长度-1,接着取列表的中间值与目标字母进行比较,如果中间字母大于目标字母,则从左侧继续查找,反之从右侧继续查找

var nextGreatestLetter = function (letters, target) {
    const length = letters.length;
    //第一步判断目标字母与列表的最后一个字母
    if (target >= letters[length - 1]) {
        return letters[0];
    }
    //定义二分查找的开始和结尾
    let low = 0, high = length - 1;
    while (low < high) {
        //定义中间下标值
        const mid = Math.floor((high - low) / 2) + low;
        //中间字母大于目标字母,将中间下标当做结尾,从左侧接着查找
        if (letters[mid] > target) {
            high = mid;
        //反之,将中间下标+1当做开始,从右侧接着查找
        } else {
            low = mid + 1;
        }
    }
    //返回结果
    return letters[low];
};

704. 二分查找(简单)

题目描述:

给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target  ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。 示例 1:

输入: nums = [-1,0,3,5,9,12], target = 9
输出: 4
解释: 9 出现在 nums 中并且下标为 4

示例 2:

输入: nums = [-1,0,3,5,9,12], target = 2
输出: -1
解释: 2 不存在 nums 中因此返回 -1

提示:

  1. 你可以假设 nums 中的所有元素是不重复的。
  2. n 将在 [1, 10000]之间。
  3. nums 的每个元素都将在 [-9999, 9999]之间。

解题方法

使用二分法进行查找,开始时查找的范围是整个数组,然后每次查找都取中间位置的值与目标值进行比较,如果中间值大于目标值说明目标值在左侧区域,接着取左侧的中间值继续与目标值比较,直到开始位置小于等于结束位置时停止查找

在升序数组 nums 中寻找目标值target,对于特定下标 i,比较 nums[i]target 的大小:

  • 如果 nums[i]=target,则下标 i 即为要寻找的下标;

  • 如果 nums[i]>target,则 target 只可能在下标 i 的左侧;

  • 如果 nums[i]<target,则 target 只可能在下标 i 的右侧。

var search = function(nums, target) {
    const length = nums.length
    //声明左边开始位置和右侧结束位置
    let left = 0 ,right= length-1
    while(left<=right){
         //取两者的中间值
         const mid = Math.floor((right - left) / 2) + left;
         //如果中间值等于目标值,返回该值下标
         if(nums[mid]==target) {
             return mid
          //如果中间值大于目标值,则缩小范围即中间值的左侧范围
         }else if (nums[mid]>target){
             right=mid-1
          //如果中间值小于目标值,则缩小范围即中间值的右侧范围
         }else{
             left=mid+1
         } 
    } 
    //循环完依旧没有,则返回-1
    return -1
};

374. 猜数字大小(简单)

题目描述:

猜数字游戏的规则如下:

  • 每轮游戏,我都会从 1 到 n 随机选择一个数字。 请你猜选出的是哪个数字。

  • 如果你猜错了,我会告诉你,你猜测的数字比我选出的数字是大了还是小了。 你可以通过调用一个预先定义好的接口 int guess(int num) 来获取猜测结果,返回值一共有 3 种可能的情况(-11 或 0):

  • -1:我选出的数字比你猜的数字小 pick < num

  • 1:我选出的数字比你猜的数字大 pick > num

  • 0:我选出的数字和你猜的数字一样。恭喜!你猜对了!pick == num 返回我选出的数字。

示例 1:

输入:n = 10, pick = 6
输出:6

示例 2:

输入:n = 1, pick = 1
输出:1

示例 3:

输入:n = 2, pick = 1
输出:1

示例 4:

输入:n = 2, pick = 2
输出:2

提示:

  • 1 <= n <= 231 - 1
  • 1 <= pick <= n

解题方法:

开始位置为1,结束位置为n,查找的前提条件是开始位置小于结束位置;将两者的中间值进行判断,当返回的值<=0时,说明目标值在中间值的左侧部分,反之目标值在右侧,直到最后开始位置与结束位置相同时,说明已找到该值,此时退出循环

var guessNumber = function(n) {
    //定义开始位置和结束位置
    let left = 1,right=n;
    while(left<right){
        //取两者中间值
        const mid = Math.floor((right - left)/2 + left)
        //判断中间值所返回的值,如果<=0,则说明值在左侧区域
        if(guess(mid)<=0){
            right=mid
        //反之在右侧区域
        }else{
            left=mid+1
        }   
    }
    //当开始位置与结束位置相同时,区间只有一个值即为答案,退出循环
    return left
};

852. 山脉数组的峰顶索引

题目描述

符合下列属性的数组 arr 称为 山脉数组 : arr.length >= 3 存在 i (0 < i < arr.length - 1) 使得: arr[0] < arr[1] < ... arr[i-1] < arr[i] arr[i] > arr[i+1] > ... > arr[arr.length - 1] 给你由整数组成的山脉数组 arr ,返回任何满足 arr[0] < arr[1] < ... arr[i - 1] < arr[i] > arr[i + 1] > ... > arr[arr.length - 1] 的下标 i 。

示例 1:

输入:arr = [0,1,0]
输出:1

示例 2:

输入:arr = [0,2,1,0]
输出:1

示例 3:

输入:arr = [0,10,5,2]
输出:1

示例 4:

输入:arr = [3,4,5,1]
输出:2

示例 5:

输入:arr = [24,69,100,99,79,78,67,36,26,19]
输出:2

提示:

  • 3 <= arr.length <= 104
  • 0 <= arr[i] <= 106
  • 题目数据保证 arr 是一个山脉数组

解题方法

从题目描述中可以得知,山脉数组是中间值为最大,两边逐渐减小的数组,因此取得中间值来与其左右值进行比较

  • 中间值大于左侧值并且大于右侧值,则返回该中间值的下标

  • 中间值大于左侧且小于右侧,则结果值在右侧

  • 中间值大于右侧且小于左侧,则结果值在左侧

var peakIndexInMountainArray = function (arr) {
    const length = arr.length;
    let left = 0,
        right = length - 1;
    while (left < right) {
        const mid = Math.floor((right - left) / 2 + left);
        if (arr[mid] > arr[mid - 1] && arr[mid] > arr[mid + 1]) {
            return mid;
        } else if (arr[mid] > arr[mid - 1] && arr[mid] < arr[mid + 1]) {
            left = mid;
        } else {
            right = mid + 1;
        }
    }
    return left;
};

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

提示:

  • 1 <= nums.length <= 104
  • -104 <= nums[i] <= 104
  • nums 为 无重复元素 的 升序 排列数组
  • -104 <= target <= 104

解题方法

  • 特殊情况:判断目标值是否大于数组最后一个值,true则返回数组长度

  • 开始范围为[left,right],当中间值小于目标值时,结果值在右侧,此时范围为[mid+1,right],反之范围为[left,mid]

var searchInsert = function (nums, target) {
    const length = nums.length;
    let low = 0,
        high = length - 1;
    if (target > nums[high]) {
        return length;
    }
    while (low < high) {
        const mid = Math.floor((high - low) / 2 + low);
        if (nums[mid] < target) {
            low = mid + 1;
        } else {
            high = mid;
        }
        // return mid
    }
    return low;
};