题目难度: 简单
今天继续更新程序员面试金典系列, 大家在公众号 算法精选 里回复 面试金典 就能看到该系列当前连载的所有文章了, 记得关注哦~
题目描述
稀疏数组搜索。有个排好序的字符串数组,其中散布着一些空字符串,编写一种方法,找出给定字符串的位置。
示例 1:
- 输入: words = ["at", "", "", "", "ball", "", "", "car", "", "","dad", "", ""], s = "ta"
- 输出:-1
- 说明: 不存在返回-1。
示例 2:
- 输入:words = ["at", "", "", "", "ball", "", "", "car", "", "","dad", "", ""], s = "ball"
- 输出:4
提示:
- words 的长度在[1, 1000000]之间
题目思考
- 如何利用数组有序这一条件?
解决方案
思路
- 解决有序数组搜索问题, 一个很自然的想法就是二分查找
- 但这个题目略有不同, 因为会存在一些空字符
- 如果区间中点字符不是空字符, 则可以根据它和 s 的大小关系, 决定向左还是向右查找, 这里和传统二分一样
- 那如果区间中点字符恰好是空字符, 该如何处理呢?
- 此时我们只能依次查找左右两个区间了, 左边如果找到目标字符就不再继续, 否则继续查找右边
- 这也限制了需要采用递归来实现二分, 递归二分需要注意递归出口, 即起点大于终点的情况, 此时肯定找不到, 返回-1
- 下面的代码就对应了上面的整个过程, 并且有详细的注释, 方便大家理解
复杂度
- 时间复杂度
O(N)
: 空字符不多的情况下时间复杂度接近传统二分, 即O(logN)
; 最差情况(所有字符串都是空)下, 需要遍历每个字符串一遍, 此时复杂度为O(N)
- 空间复杂度
O(logN)
: 递归栈的消耗
代码
class Solution:
def findString(self, words: List[str], s: str) -> int:
def find(b, e):
if b > e:
# 递归出口, 起点大于终点, 肯定找不到, 返回-1
return -1
m = (b + e) >> 1
if words[m] == "":
# 当前中点字符是空, 需要依次查找左右区间
l = find(b, m - 1)
# 左边找到后就直接返回, 不再继续查找右区间
return l if l != -1 else find(m + 1, e)
elif words[m] == s:
return m
elif words[m] < s:
return find(m + 1, e)
else:
return find(b, m - 1)
return find(0, len(words) - 1)
大家可以在下面这些地方找到我~😊
我的公众号: 算法精选, 欢迎大家扫码关注~😊