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=1,letters[1]='f'>'a' → right=0;
  • 第二次循环:mid=0,letters[0]='c'>'a' → right=-1;
  • 循环结束,返回 letters[0]='c'(正确)。

用例 2:target 等于中间字符

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

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

五、总结

  1. 二分查找的核心是精准匹配题目要求的判断条件,本题需严格区分「>=target」和「>target」,否则会导致结果错误;
  2. 解题时要充分利用题目给出的特性(如本题「非递减排列」),去掉冗余逻辑(如去重),提升效率;
  3. 边界条件是二分查找的高频坑点,提前预处理边界场景(如 target 大于所有字符),能有效避免数组越界。
相关推荐
机器人零零壹30 分钟前
技术白皮书:iRobotCAM如何解决机器人激光切割应用中的核心难点,从CAD离线编程到双目视觉定位与轨迹自适应提升复杂空间曲线切割的精度、效率与柔性化水平
人工智能·算法
ZhengEnCi3 小时前
大模型的分类到底怎么分:从基础模型到推理模型、从通用到专用的完整图谱
算法
取名真是4 小时前
Python 算法知识点从基础到进阶
开发语言·python·算法
罗西的思考4 小时前
【轻量化复刻大模型 / KIMI K3】KDA 模块交互式演示
人工智能·算法·机器学习
nm_zfyjt6 小时前
信息流广告投放优化实践:线索成本评估模型与转化链路重构(家装建材案例)
算法·重构·内蒙古朋友圈广告服务商·内蒙古朋友圈获客
w_zero_one8 小时前
算法--构造
java·数据结构·算法
其实防守也摸鱼8 小时前
信创安全竞赛知识总结与题库
大数据·网络·人工智能·算法·安全·php
小超人诞生日记9 小时前
C++ 智能指针的使用及其原理详解
c++·算法
AiNightVision13 小时前
无人机夜视模块如何选择?——从参数指标到系统集成的完整选型指南
人工智能·算法·计算机视觉·车载系统·无人机·视频·智能硬件