输入: nums = [5,7,7,8,8,10], target = 8
输出: 2
排序就是二分无疑。
用了两种方法,第一种相对较差,直接二分之后,找到遍历该target前后有多少个,然后再相加。这样比较一般,时间复杂度不只是二分的logn,而是n,因为最坏的情况还是要遍历一整个数组。
第二种方法是分别找到重复数字的最前面的数字的序号和最后面的数字的序号,再进行相减得到数目。二分的变体,依旧可以找到最前和最后的!
class Solution(object):
sign = False #全局变量,原因是下面可能分不清是没找到得
#到的0,还是找到的位置是0
def erfen(self, nums, target):
min = 0
max = len(nums) - 1
if nums[max] < target or nums[min] > target:
return False
while min <= max:
mid = (max + min) // 2
if nums[mid] > target:
max = mid - 1
if nums[mid] < target:
min = mid + 1
if nums[mid] == target:
Solution.sign = True
return mid
return False
def search(self, nums, target):
if not nums:
return 0
m = self.erfen(nums, target)
a = 0
if Solution.sign:
n = m
m -= 1
while nums[n] == target : # 这种往前和往后查找的办法可能遇到最坏的时间复杂度也是n,所以并不是好的办法,下面继续优化!!
n += 1
a += 1
if n == len(nums):
break
while m >= 0 and nums[m] == target :
m -= 1
a += 1
if m == -1:
break
return a
第二种:也可以把first和last函数合并成一个。
class Solution(object): # 改成两个,一个查找第一个出现的序号,一个查找最后一个出现的序号。
def search(self, nums, target):
# 二分的思想改进 # 记住不用递归,while在此不需要
if not nums:
return 0
self.sign_first = 0
self.sign_last = 0
def first(nums, max, min):
while min <= max:
mid = (max + min) // 2
if nums[mid] > target:
max = mid - 1
elif nums[mid] < target:
min = mid + 1
elif nums[mid] == target:
self.sign_first = 1
if mid == 0 or nums[mid - 1] != target:
return mid
else:
max = mid - 1
def last(nums, max, min):
while min <= max:
mid = (max + min) // 2 # 可以简化:fist保留
if nums[mid] > target:
max = mid - 1
elif nums[mid] <= target:
min = mid + 1
elif nums[mid] == target:
self.sign_last = 1
if mid == len(nums) - 1 or nums[mid + 1] != target:
return mid
else:
min = mid + 1
max = len(nums) - 1
min = 0
mid_first = first(nums, max, min)
mid_last = last(nums, max, min)
if not self.sign_first:
return 0
if mid_first == mid_last:
return 1
else:
return mid_last - mid_first + 1