昨天一朋友和我推荐了CCF考试
二话不说就报名了
不过报名费是真的有些心痛
但这个学期就是抱着一种心态
看到什么比赛就像参加
大学时期没怎么想
现在就想把之前落下的给补上
81-搜索旋转排序数组 II
假设按照升序排序的数组在预先未知的某个点上进行了旋转。
( 例如,数组 [0,0,1,2,2,5,6]
可能变为 [2,5,6,0,0,1,2]
)。
编写一个函数来判断给定的目标值是否存在于数组中。若存在返回 true
,否则返回 false
。
示例 1:
,5,6,0,0,1,2]
示例 2:
,5,6,0,0,1,2]
进阶:
- 这是 搜索旋转排序数组 的延伸题目,本题中的 nums 可能包含重复元素。
- 这会影响到程序的时间复杂度吗?会有怎样的影响,为什么?
思路:
本题有两种方法,第一种属于作弊法,第二种就是很常规的二分法了。
方法一:
直接使用直接使用if target in nums即可迅速得出答案。但是没有什么营养价值
代码如下:
class Solution(object):
# 此种解法属于作弊方法,直接使用if target in nums
def search(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: bool
"""
return True if target in nums else False
if __name__ == "__main__":
nums = [2, 5, 6, 0, 0, 1, 2]
target = 0
is_contain = Solution().search(nums, target)
print(is_contain)
不过执行效率也是不高,只有10%左右。
方法二:
该方法是基于常规的二分法来实现的,我们知道凡是碰到这种数组或矩阵里找某值的题目,大部分是采用二分法的,因为其效率快,本题亦是如此。不过本题有两个陷阱,一是给定列表是两段分别单调有序的数组合并起来的,这就会产生多种分类情况。因为我们知道使用二分法的先决条件就是:给定序列单调有序,在此题中就相当于是中间有一部分断层了。二是给定列表中可能存在重复值,如何去重也是一个需要考虑的问题。问题主要是这两个,至于怎么解决,我们一个一个来。
先说第二个问题吧,这个解决起来比较简单。
如下图所示:
此时第二个问题就解决了,再来说说第一个问题。说个题外话哈,其实你会发现本题就是个分类讨论的题目,只要把各种情况给考虑到了,答案自然就出来了。现在的关键就是如何确定分类的条件,大的方向还是将nums[mid]与nums[start],nums[end]作比较,但每个大比较里面还有各种小情况,具体见下图所示:
代码如下:
class Solution(object):
def search(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: bool
"""
# 分别定义nums数组的首尾指针
start = 0
end = len(nums)-1
while start <= end:
mid = (start+end)//2
if nums[mid] == target:
return True
# 此时start到end之间表示的元素刚好为单增序列
if nums[mid] == nums[start]:
start += 1
elif nums[mid] == nums[end]:
end -= 1
elif nums[mid] > nums[start]:
if nums[start] <= target < nums[mid]:
end = mid - 1
else:
start = mid + 1
elif nums[mid] < nums[end]:
if nums[end] >= target > nums[mid]:
start = mid + 1
else:
end = mid - 1
return False
if __name__ == "__main__":
nums = [5, 1, 3]
target = 3
is_contain = Solution().search(nums, target)
print(is_contain)
执行效率和方法一差不多,在10%左右。如果各位读者有更好的方法还请多多分享!!!