持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第3天,点击查看活动详情
一、题目
给你一个排序后的字符列表 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"
作者:力扣 (LeetCode) 链接:leetcode.cn/leetbook/re… 来源:力扣(LeetCode) 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
二、思路
暴力解法
- 由题意可知,给到一个list,判断target在list中比target大的最小字母
- 字符可以直接判断,例如 a < b => true
- 简单的做法就是直接一个for循环,循环出的每个参数,与target判断,如果当前i 大于target,那么就返回这个值
- 同时要注意到比较时字母是循环的,例如题目举的例子,
- 因此如果没有返回值,则返回list的第一个值
- 代码上的优化问题,这里有一个next()函数
- 两个参数一个是可迭代对象,一个是默认兑现,如果迭代对象没有返回值的时候,返回默认值
二分思路
- 首先,定义左右区间, left 等于0 ,right等于 len - 1,中间值是mid = left + ((right - left)//2)
- 循环条件是left 小于 right
- 先寻找区间,是在左区间还是在右区间
- 如果 letters[mid] > target 那么说明值存在left 到mid之间
- 那么就重新定义右区间,right = mid
- 如果 letters[mid] > target 为 False,那么说明左区间的值小了,要缩小区间, left = mid + 1
- 当 left 小于right 不成立的时候, letters[left]就是最接近的值
- 同时要考虑一个问题,就是如果如题目上举的例子的情况,那么就要再判断一下,
- 判断如果target 大于等于 letters[right], 返回 letters[0]
二分查找
三、代码
暴力解法
class Solution:
def nextGreatestLetter(self, letters: List[str], target: str) -> str:
""""
暴力解法
由题意可知,给到一个list,判断target在list中比target大的最小字母
字符可以直接判断,例如 a < b => true
简单的做法就是直接一个for循环,循环出的每个参数,与target判断,如果当前i 大于target,那么就返回这个值
同时要注意到比较时字母是循环的,例如题目举的例子,
因此如果没有返回值,则返回list的第一个值
代码上的优化问题,这里有一个next()函数
两个参数一个是可迭代对象,一个是默认兑现,如果迭代对象没有返回值的时候,返回默认值
"""
// 常规写法
for i in letters:
if i > target:
return i
return letters[0]
// 优化后的写法
return next((i for i in letters if i > target), letters[0])
二分解法
class Solution:
def nextGreatestLetter(self, letters: List[str], target: str) -> str:
""""
首先,定义左右区间, left 等于0 ,right等于 len - 1,中间值是mid = left + ((right - left)//2)
循环条件是left 小于 right
先寻找区间,是在左区间还是在右区间
如果 letters[mid] > target 那么说明值存在left 到mid之间
那么就重新定义右区间,right = mid
如果 letters[mid] > target 为 False,那么说明左区间的值小了,要缩小区间, left = mid + 1
当 left 小于right 不成立的时候, letters[left]就是最接近的值
同时要考虑一个问题,就是如果如题目上举的例子的情况,那么就要再判断一下,
判断如果target 大于等于 letters[right], 返回 letters[0]
"""
left = 0
right = len(letters) - 1
if target >= letters[right]:
return letters[0]
while left < right:
mid = left + ((right-left)//2)
if letters[mid] > target:
right = mid
else:
left = mid + 1
return letters[left]
四、测试结果
暴力解法
二分查找
五、番外-bisect使用
在二分查找中常用bisect库
文档地址:docs.python.org/3.10/librar…
bisect
bisect.bisect(列表, 元素): 返回元素在列表中顺序插入的位子,如果list中已存在元素,则返回在该元素的最后一个位置之后
import bisect
list1, num1 = [1,3,5,7,9], 2
// 例子1
int1 = bisect.bisect(list1,num1)
print(int1, type(int1), list1)
// 例子2
list2, num2= [1,2,3,5,7,9], 2
int2 = bisect.bisect_right(list2, num2)
print(int2, type(int2), list2)
对比两张图可看到结果
bisect_left
bisect.bisect_left(列表, 元素): 返回元素在列表中顺序插入的位子,如果list中已存在元素,则返回在该元素的第一个位置
// 例子1
list1, num1 = [1,3,5,7,9], 2
int1 = bisect.bisect_left(list1,num1)
print(int1, type(int1), list1)
// 例子2
list2, num2= [1,2,3,5,7,9], 2
int2 = bisect.bisect_left(list2, num2)
print(int2, type(int2), list2)
看到下标,能看出,插入的位置的区别
bisect_right
bisect_right(列表, 元素): 返回元素在列表中顺序插入的位子,如果list中已存在元素,则返回在该元素的最后一个位置之后
// 例子1
list1, num1 = [1, 3, 5, 7, 9], 2
int1 = bisect.bisect_right(list1, num1)
print(int1, type(int1), list1)
// 例子2
list2, num2 = [1, 2, 3, 5, 7, 9], 2
int2 = bisect.bisect_right(list2, num2)
print(int2, type(int2), list2)
依然是对比他们的下标位置
insort
bisect.insort(列表, 元素): 无返回值,在列表中插入元素
第二张图,告诉了当前是没有返回值的,第三张图说明了插入的位置
insort_left
bisect.insort_left(列表, 元素): 无返回值,在列表中插入元素
// 例子1
list1, num1 = [1, 3, 5, 7, 9], 2
int1 = bisect.insort_left(list1, num1)
print(int1, list1)
// 例子2
list2, num2 = [1, 2, 3, 5, 7, 9], 2
int2 = bisect.insort_left(list2, num2)
print(int2, list2)
insort_right
bisect.insort_right(列表, 元素): 无返回值,在列表中插入元素
总结
返回元素要插入位置中:
- bisect与bisect_right返回的位置相同,如果存在元素中,返回的是该元素的最后一个位置之后
- bisect_left 返回的位置,如果存在元素,返回的是该元素的第一个位置
- insort_left与insort_right:插入的位置,left在前,right在后
- insort_right与insort的插入方式相同
二分查找优化
- 两种情况的判断,
- 第一种是target在list中,那么就通bisect_right找到要插入的位置,然后在通过返回的这个下标,拿到相邻的最新小字母
- 第二种是target不再list中,那么就直接的返回letters[0]
left, right = 0, len(letters) - 1
print(letters[-1])
if target < letters[-1]:
print(letters[bisect.bisect_right(letters, target)])
return letters[bisect.bisect_right(letters, target)]
else:
print(letters[0])
return letters[0]
优化的写法
return letters[bisect.bisect_right(letters, target)] if target < letters[-1] else letters[0]