每日一题:寻找比目标字母大的最小值

84 阅读1分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第5天,点击查看活动详情

力扣题目链接

题目要求

给你一个排序后的字符列表 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 是一个小写字母

解题思路一:(ASCII码比较)

这道题可以采用二分查找来实现

我们可以通过转成ASCII码,用ASCII码进行比较

target所处的位置可以分两种情况来看:

  1. target在字符列表内
    • target在左边界上,用二分查找进行查询
    • target在右边界上,返回字符列表的第一个元素
    • target左右边界内,用二分查找进行查询
  2. target在字符列表外
    • target在字符列表左侧,返回字符列表的第一个元素
    • target在字符列表右侧,返回字符列表的第一个元素

代码(JAVA实现)

class Solution {
    public char nextGreatestLetter(char[] letters, char target) {
        int left = 0;
        int right = letters.length-1;
        // 这里的l,r,t是将字符转化为整数,也就是字符的ASCII码,用ASCII码进行比较
        int l = letters[left];
        int r = letters[right];
        int t = target;

        //用来判断target是否在字符列表外,只要有一个条件满足,直接返回字符列表的第一个元素即可
        if (t < l || t > r || t == r) {
            return letters[0];
        }

        while (left < right) {
            int mid = left + (right - left)/2;
            int m = letters[mid];
            if (m > t) {
                right = mid;
            }else if(m <= t) {
                left = mid + 1;
            }
        }
        return letters[left];
    }
}

提交结果

image.png

时间复杂度:O(log n)

空间复杂度:O(1)

解题思路二:(字符比较)

这道题其实也可以使用字符列表和target进行比较,也是用二分查找所实现

具体思路:取中间值mid

  1. mid > targetmid 可能就是我们要找的那个最小值,也可能不是,所以需要保留,即right = mid
  2. mid <= target,中间值小于目标字母时,左指针移动到中间值的后一位,即 left = mid + 1
  3. 循环结束后还要进行检查寻找到的元素是否比目标字母大,如果不满足,则取数组首位元素

代码:(JAVA实现)

class Solution {
    public char nextGreatestLetter(char[] letters, char target) {
        int n = letters.length;
        int l = 0;
        int r = n-1;
        while (l < r){
            int mid = l + (r - l)/2;
            if (letters[mid] > target) {
                r = mid;
            }else {
                l = mid + 1;
            }
        }
        if (letters[r] > target) {
            return letters[r];
        }else {
            return letters[0];
        }
    }
}

提交结果

image.png

时间复杂度:O(log n)

空间复杂度:O(1)

总结

这两种思路用的都是二分查找字符比较转ASCII码再进行比较内存消耗要小一些,两种都可以提交成功,喜欢哪种就可以用哪种