题目:
给你一个按 非递减顺序 排列的数组 nums ,返回正整数数目和负整数数目中的最大值。
- 换句话讲,如果
nums中正整数的数目是pos,而负整数的数目是neg,返回pos和neg二者中的最大值。
注意: 0 既不是正整数也不是负整数。
算法:
方法一:二分查找
时间复杂度O(2logn)
func maximumCount(nums []int) int {
posCount, negCount := 0, 0
// 找到第一个大于等于0的位置index
neg := findNegtive(nums)
pos := findPostive(nums)
if 0 <= neg && neg < len(nums) {
negCount = neg + 1
}
if 0 <= pos && pos < len(nums) {
posCount = len(nums) - pos
}
return max(posCount, negCount)
}
func max(a, b int) int {
if a > b {
return a
}
return b
}
// 找到最大的负数index
func findNegtive(nums []int) int {
left, right := 0, len(nums) - 1
for left <= right {
mid := (left + right) / 2
if nums[mid] < 0 {
left = mid + 1
} else {
right = mid - 1
}
}
return right
}
// 找到最小的正数index
func findPostive(nums []int) int {
left, right := 0, len(nums) - 1
for left <= right {
mid := (left + right) / 2
if nums[mid] <= 0 {
left = mid + 1
} else {
right = mid - 1
}
}
return left
}
关于二分多说几句:
1.为什么循环条件是left <= right
考虑nums中只有一个元素,此时left == right,nums[left],nums[right]是正数,负数都有可能,需要和0进行比较,判断left,和right哪个移动。并且每次循环只比较了mid,left + 1 == right时,left,right可能还没有和0比较过。
2.是nums[mid] <= 0 {left = mid + 1 }还是nums[mid] < 0 left = mid + 1, 看你把需不需要0,把0当成正数还是负数处理,为了找最小的正数,把0当成负数处理,就是nums[mid] <= 0 {left = mid + 1 }
3.返回left,还是right
left == right == mid时,可能nums[left]是正数负数都有可能,但肯定是在边界除了。
以findPostive为例,(-无穷,left - 1) <= 0, mid(left,right),0 < (right + 1,+无穷)
如果mid <= 0 则变成了(-无穷,left - 1) <= 0, mid(right),0 < (right + 1(left),+无穷),此时left是最小正数。
如果0 < mid,则变成了(-无穷,left - 1(right)) <= 0, mid(left),0 < (right + 1,+无穷),此时left是最小正数。
方法二:遍历
害,这种朴素方法居然都没有想到了,时间复杂度也就O(n),nums长度也就2000而已。
func maximumCount(nums []int) int {
posCount, negCount := 0, 0
// 找到第一个大于等于0的位置index
for i := range nums {
if nums[i] > 0 {
posCount ++
} else if nums[i] < 0 {
negCount ++
}
}
return max(posCount, negCount)
}
func max(a, b int) int {
if a > b {
return a
}
return b
}