[leetcode 3347][Go][答案二分]万能的二分法

[leetcode 3347][Go][答案二分]万能的二分法
inkOrCloud力扣随机五道题三道都是二分
题目链接
leetcode 3347 执行操作后元素的最高频率 II ## 解题思路
超时方案:暴力枚举+二分查找
枚举所有可能的n,再通过二分查找n的数量、n-k至n+k的范围,结合操作上限得出,在3346
执行操作后元素的最高频率 I中能通过,但在此题中能超时
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45func findLeftIndex(nums []int, n int) int {
var l, r = 0, len(nums) - 1
if nums[0] >= n {
return -1
}
for l < r {
m := (l + r + 1) / 2
if nums[m] >= n {
r = m - 1
} else {
l = m
}
}
return l
}
func findRightIndex(nums []int, n int) int {
var l, r = 0, len(nums) - 1
if nums[len(nums)-1] <= n {
return len(nums)
}
for l < r {
m := (l + r) / 2
if nums[m] <= n {
l = m + 1
} else {
r = m
}
}
return r
}
func maxFrequency(nums []int, k int, numOperations int) int {
sort.Ints(nums)
var ret = 0
var maxN = nums[len(arr)-1]
var minN = nums[0]
for n := minN; n <= maxN; n++ {
a := findRightIndex(arr, n) - findLeftIndex(arr, n) - 1
b := findRightIndex(arr, min(maxN, n+k)) - findLeftIndex(arr, max(0, n-k)) - 1
c := a + min(b-a, numOperations)
ret = max(ret, c)
}
return ret
}
答案二分
这里分出一个子问题,考虑两种情况,一是n为nums数组上的值,那么当前频率就是min([n-k,n-1]+[n+1,n+k], numOperations)+[n,n] ([a,b]代表数组上数值范围从a到b的数量),二是n为nums数组上某些元素之间的值但不等于数组上的任何元素,那么此时频率就是min([n-k, n+k], numOperations)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43//寻找第一个小于n的值的下标
func findLeftIndex(nums []int, n int) int {
if nums[0] >= n {
return -1
}
return sort.Search(len(nums), func(i int) bool {
return nums[i] >= n
}) - 1
}
//寻找第一个大于n的值的下标
func findRightIndex(nums []int, n int) int {
if nums[len(nums)-1] <= n {
return len(nums)
}
return sort.Search(len(nums), func(i int) bool {
return nums[i] > n
})
}
func sub2(nums []int, k int, length int) bool {
for i := 0; i+length <= len(nums); i++ {
end := i + length - 1
//只要确定左右边界差值小于等于2k就能确定中间的值一定能通过加[-k,k]得到n
if nums[end]-nums[i] <= 2*k {
return true
}
}
return false
}
func sub1(nums []int, k int, op int) int {
var ret = 0
//这里主要需要计算[n,n]的长度所以需要二分查找
for _, n := range nums {
r1 := findRightIndex(nums, n)
l1 := findLeftIndex(nums, n)
r2 := findRightIndex(nums, n+k)
l2 := findLeftIndex(nums, n-k)
ret = max(ret, (r1-l1-1)+min((r2-l2-1)-(r1-l1-1), op))
}
return ret
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16func maxFrequency(nums []int, k int, numOperations int) int {
sort.Ints(nums)
var r1 = sub1(nums, k, numOperations)
//查找无法满足sub2的最小length减去1即为答案
var r2 = sort.Search(numOperations+2, func(i int) bool {
//因为[0,r1]在sub1中已经确定所以直接返回false
if i <= r1 {
return false
}
if i > numOperations {
return true
}
return !sub2(nums, k, i)
}) - 1
return max(r1, r2)
}

![[leetcode 3321][Go][有序集合]计算子数组的 x-sum II](https://s3.inkorcloud.top/image/2025/11/c9f55b2ecb04d16a57547b9f4de294ef.png)
![[leetcode 2589][Go][贪心]完成所有任务的最少时间](https://s3.inkorcloud.top/image/2025/11/b966fd1a91aa1ea098b86e6d778523c2.png)
![[leetcode 3234][Go]统计1显著的字符串的数量](https://s3.inkorcloud.top/image/2025/11/a72a47911de291f51cbb5902e4811c1f.png)
![[leetcode 1611][Go][位运算][记忆化搜索]使整数变为 0 的最少操作次数](https://s3.inkorcloud.top/image/2025/11/9715b5f3d8a7574ded3648767538558e.png)
![[leetcode 2528][Go][二分答案][差分数组][前缀和]最大化城市的最小电量](https://s3.inkorcloud.top/image/2025/11/fa0013722d9361b4383839722394dcf2.png)