leetcode刷题记录-744. 寻找比目标字母大的最小字母

538 阅读2分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第2天,点击查看活动详情

前言

今天的题目为简单,现在在碰到在有序列表中查找某个值的时候,就应该想一下二分查找能否实现,因为相比于简单的循环遍历,二分查找能更加的节省时间复杂度

每日一题

今天的题目是 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 是一个小写字母

题解

暴力解法

题目很简单,需要返回一个数组里面比目标字母大的第一个字母,那就去遍历目标数组,一碰到比目标字符大的就返回,要注意的是题目会出现目标字符比数组都大的这种情况,这种时候会返回数组的第一项,所以我们可以用一个数来保存下第一项,如果目标字符大于全部数组元素的话,就把第一项返回出去。

/**
 * @param {character[]} letters
 * @param {character} target
 * @return {character}
 */
var nextGreatestLetter = function (letters, target) {
  const n = letters.length;
  let res = letters[0];
  for (let i = 0; i < n; i++) {
    if (letters[i] > target) {
      res = letters[i];
      return res;
    }
  }
  return res;
};

image.png

二分查找优化

看到题目提供的数组是有序的,就可以联想到二分查找来对时间复杂度进行优化,二分查找不同于循环遍历,能节省很多的遍历时间,主要是通过每次取到数组的中间项,通过中间项和目标数组的大小来判断我们要的那个数是在中间项的左边还是右边,以此一直循环直到找到为止,比起循环遍历的 O(n) 时间复杂度,二分查找能够将时间复杂度优化到 O(logn)。

image.png

  1. 首先我们需要定义好左边界和右边界,然后取两个边界的中间作为中间值

  2. 如果 target 大于 中间值,说明 我们要的数在中间值到右边界这一段当中,就把左边界更新为中间值

  3. 一直这样子重复,知道成功找到我们需要的目标数为止。

/**
 * @param {character[]} letters
 * @param {character} target
 * @return {character}
 */
var nextGreatestLetter = function(letters, target) {
    const n = letters.length;
    if (target >= letters[n - 1]) {
        return letters[0];
    }
    let low = 0, high = n - 1;
    while (low < high) {
        const mid = Math.floor((high - low) / 2) + low;
        if (letters[mid] > target) {
            high = mid;
        } else {
            low = mid + 1;
        }
    }
    return letters[low];
};

image.png