LeetCode 744. 寻找比目标字母大的最小字母 | 从低效到最优的二分解法优化

在算法刷题中,二分查找是高频考点,而「寻找比目标字母大的最小字母」这道题(LeetCode 744)是二分查找的经典应用场景。本文将从初版低效解法 入手,分析问题所在,逐步优化到最优解法,帮你理解二分查找的核心逻辑和题目特性的利用技巧。

一、题目描述

原题链接

LeetCode 744. Find Smallest Letter Greater Than Target(https://leetcode.cn/problems/find-smallest-letter-greater-than-target/

核心要求

给你一个字符数组 letters,该数组按非递减顺序 排列,以及一个字符 target。请你找出并返回 letters 中大于 target 的最小字符。如果不存在这样的字符,则返回 letters 的第一个字符。

示例

  • 示例 1:输入: letters = ["c","f","j"], target = "a",输出: "c"
  • 示例 2:输入: letters = ["c","f","j"], target = "c",输出: "f"
  • 示例 3:输入: letters = ["c","f","j"], target = "j",输出: "c"

优化解法:最优二分实现

1. 优化思路

  • 利用 letters 非递减的特性,去掉冗余去重,直接操作原数组,节省时间和空间;
  • 修正二分逻辑,精准瞄准「大于 target 的最小字符」;
  • 提前处理边界场景(target 大于所有字符),避免数组越界。
  1. 最优代码
java 复制代码
public char nextGreatestLetter(char[] letters, char target) {
    int left = 0;
    int right = letters.length - 1;
    
    // 提前处理边界:target大于/等于所有字符,直接返回第一个元素
    if (letters[right] <= target) {
        return letters[left];
    }
    
    // 二分查找:找大于target的最小字符
    while (left <= right) {
        // 防止left+right溢出,等价于(left+right)/2
        int mid = left + (right - left) / 2;
        if (letters[mid] > target) {
            // 当前元素大于target,尝试找更小的(左移右边界)
            right = mid - 1;
        } else {
            // 当前元素<=target,需要右移左边界,找更大的元素
            left = mid + 1;
        }
    }
    
    // 循环结束后,left指向第一个大于target的字符
    return letters[left];
}

核心逻辑解析

(1)边界预处理

if (letters[right] <= target) 直接判断「target 是否大于等于最后一个字符」,若是则返回第一个字符,避免后续二分越界。

(2)二分查找核心
  • letters[mid] > target:说明 mid 位置的字符是候选,但可能有更小的符合条件的字符,因此左移右边界(right = mid - 1);
  • letters[mid] <= target:说明 mid 位置的字符不符合要求,需要找更大的,因此右移左边界(left = mid + 1);
  • 循环结束时,left 必然指向「大于 target 的最小字符」(因为预处理已排除所有字符都 <=target 的情况)。
(3)时间 / 空间复杂度
  • 时间复杂度:O (logn)(纯二分查找,无额外遍历);
  • 空间复杂度:O (1)(仅用了几个变量,无额外数据结构)。

四、测试用例验证

用例 1:常规场景(target 小于所有字符)

输入:letters = ['c','f','j'], target = 'a'执行流程:

  • 边界判断:letters[2]='j' > 'a',进入二分;
  • 第一次循环:mid=1letters[1]='f'>'a'right=0
  • 第二次循环:mid=0letters[0]='c'>'a'right=-1
  • 循环结束,返回 letters[0]='c'(正确)。

用例 2:target 等于中间字符

输入:letters = ['c','f','j'], target = 'c'执行流程:

  • 边界判断:letters[2]='j' > 'c',进入二分;
  • 第一次循环:mid=1letters[1]='f'>'c'right=0
  • 第二次循环:mid=0letters[0]='c'<=cleft=1
  • 循环结束,返回 letters[1]='f'(正确)。

用例 3:边界场景(target 等于最后一个字符)

输入:letters = ['c','f','j'], target = 'j'执行流程:

  • 边界判断:letters[2]='j' <= 'j' → 直接返回 letters[0]='c'(正确)。

用例 4:含重复元素场景

输入:letters = ['c','c','f','j'], target = 'c'执行流程:

  • 边界判断:letters[3]='j' > 'c',进入二分;
  • 第一次循环:mid=1letters[1]='c'<=cleft=2
  • 第二次循环:mid=2letters[2]='f'>'c'right=1
  • 循环结束,返回 letters[2]='f'(正确)。

五、总结

  1. 二分查找的核心是精准匹配题目要求的判断条件,本题需严格区分「>=target」和「>target」,否则会导致结果错误;
  2. 解题时要充分利用题目给出的特性(如本题「非递减排列」),去掉冗余逻辑(如去重),提升效率;
  3. 边界条件是二分查找的高频坑点,提前预处理边界场景(如 target 大于所有字符),能有效避免数组越界。
相关推荐
灵感__idea1 天前
Hello 算法:众里寻她千“百度”
前端·javascript·算法
Wect2 天前
LeetCode 130. 被围绕的区域:两种解法详解(BFS/DFS)
前端·算法·typescript
NAGNIP2 天前
一文搞懂深度学习中的通用逼近定理!
人工智能·算法·面试
颜酱2 天前
单调栈:从模板到实战
javascript·后端·算法
CoovallyAIHub3 天前
仿生学突破:SILD模型如何让无人机在电力线迷宫中发现“隐形威胁”
深度学习·算法·计算机视觉
CoovallyAIHub3 天前
从春晚机器人到零样本革命:YOLO26-Pose姿态估计实战指南
深度学习·算法·计算机视觉
CoovallyAIHub3 天前
Le-DETR:省80%预训练数据,这个实时检测Transformer刷新SOTA|Georgia Tech & 北交大
深度学习·算法·计算机视觉
CoovallyAIHub3 天前
强化学习凭什么比监督学习更聪明?RL的“聪明”并非来自算法,而是因为它学会了“挑食”
深度学习·算法·计算机视觉
CoovallyAIHub3 天前
YOLO-IOD深度解析:打破实时增量目标检测的三重知识冲突
深度学习·算法·计算机视觉
NAGNIP3 天前
轻松搞懂全连接神经网络结构!
人工智能·算法·面试