持续创作,加速成长!这是我参与「掘金日新计划 · 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 <= 104letters[i]是一个小写字母letters按非递减顺序排序letters最少包含两个不同的字母target是一个小写字母
解题思路一:(ASCII码比较)
这道题可以采用二分查找来实现
我们可以通过转成ASCII码,用ASCII码进行比较
target所处的位置可以分两种情况来看:
- target在字符列表内
- target在左边界上,用二分查找进行查询
- target在右边界上,返回字符列表的第一个元素
- target左右边界内,用二分查找进行查询
- 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];
}
}
提交结果
时间复杂度:O(log n)
空间复杂度:O(1)
解题思路二:(字符比较)
这道题其实也可以使用字符列表和target进行比较,也是用二分查找所实现
具体思路:取中间值mid
mid > target,mid 可能就是我们要找的那个最小值,也可能不是,所以需要保留,即right = midmid <= target,中间值小于目标字母时,左指针移动到中间值的后一位,即left = mid + 1- 循环结束后还要进行检查寻找到的元素是否比目标字母大,如果不满足,则取数组首位元素
代码:(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];
}
}
}
提交结果
时间复杂度:O(log n)
空间复杂度:O(1)
总结
这两种思路用的都是二分查找,字符比较比转ASCII码再进行比较的内存消耗要小一些,两种都可以提交成功,喜欢哪种就可以用哪种