在排序数组中查找数字(Python and C++解法)
题目:
统计一个数字在排序数组中出现的次数。
示例 1:
输入: nums = [5,7,7,8,8,10], target = 8
输出: 2
示例 2:
输入: nums = [5,7,7,8,8,10], target = 6
输出: 0
限制:
0 <= 数组长度 <= 50000
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/zai-pai-xu-shu-zu-zhong-cha-zhao-shu-zi-lcof
思路:
对于排序数组,自然需要想到使用二分查找法,找到目标数字后向两边遍历,找到第一个和最后一个目标数字,但是如果数组中都是目标数字的话,那么遍历就是O(n)的时间复杂度,这种方法和直接从头遍历一样。
因此,可以考虑对于找第一个目标数字和找最后一个目标数字都使用二分查找法,那么时间复杂度为2*O(log n),但是需要使用变形的二分查找法,且该算法的实现需要注意细节。
为了练习递归思想,解法使用递归而非循环实现。
Python解法:
1 class Solution: 2 def search(self, nums: List[int], target: int) -> int: 3 def getFirstTarget(nums, target, left, right): # 找第一个目标数字 4 if left > right: # 递归终止条件 5 return -1 # 不能返回0,因为当数组的唯一元素就是目标元素,函数返回下标0 6 midIndex = left + ((right - left) >> 1) 7 midData = nums[midIndex] 8 if midData < target: 9 left = midIndex + 1 10 elif midData > target: 11 right = midIndex - 1 12 else: # 如果不判断midIndex-1>0,就需要midIndex == 0放在or左边 13 if midIndex == 0 or nums[midIndex-1] != target: 14 return midIndex 15 else: 16 right = midIndex - 1 17 return getFirstTarget(nums, target, left, right) 18 def getLastTarget(nums, target, left, right): 19 if left > right: 20 return -1 21 midIndex = left + ((right - left) >> 1) 22 midData = nums[midIndex] 23 if midData < target: 24 left = midIndex + 1 25 elif midData > target: 26 right = midIndex - 1 27 else: 28 if midIndex == len(nums)-1 or nums[midIndex+1] != target: # 如果不判断midIndex+1<len(nums)-1,就需要midIndex == len(nums)-1放在or左边 29 return midIndex 30 else: 31 left = midIndex + 1 32 return getLastTarget(nums, target, left, right) 33 34 count = 0 35 if len(nums) > 0: 36 firstIndex = getFirstTarget(nums, target, 0, len(nums)-1) 37 lastIndex = getLastTarget(nums, target, 0, len(nums)-1) 38 if firstIndex > -1 and lastIndex > -1: 39 count = lastIndex - firstIndex + 1 40 return count
C++解法:
class Solution { public: int search(vector<int>& nums, int target) { int count = 0; if(nums.size() > 0) { int leftIndex = getFirstTarget(nums, target, 0, nums.size()-1); int rightIndex = getLastTarget(nums, target, 0, nums.size()-1); if(leftIndex > -1 && rightIndex > -1) count = rightIndex - leftIndex + 1; } return count; } int getFirstTarget(vector<int>& theNums, int theTarget, int left, int right) { if(left > right) // 递归终止条件 return -1; int midIndex = (left + ((right - left) >> 1)); int mindData = theNums[midIndex]; if (mindData > theTarget) right = midIndex - 1; else if(mindData < theTarget) left = midIndex + 1; else { if(midIndex == 0 || theNums[midIndex-1] != theTarget) return midIndex; else right = midIndex - 1; } return getFirstTarget(theNums, theTarget, left, right); } int getLastTarget(vector<int>& theNums, int theTarget, int left, int right) { if(left > right) // 递归终止条件 return -1; int midIndex = (left + ((right - left) >> 1)); int mindData = theNums[midIndex]; if (mindData > theTarget) right = midIndex - 1; else if(mindData < theTarget) left = midIndex + 1; else { if(midIndex == theNums.size()-1 || theNums[midIndex+1] != theTarget) return midIndex; else left = midIndex + 1; } return getLastTarget(theNums, theTarget, left, right); } };