1. 将数字变成 0 的操作次数
这道题其实是道送分题,我一开始以为有什么坑,就先跳过了,最后才回来做,然后就按照题目的题意写就可以了:
[[email protected]]# cat Q1.go
func numberOfSteps(num int) (rst int) {
for num != 0 {
if num&1 == 0 {
num >>= 1
} else {
num -= 1
}
rst++
}
return rst
}
2. 大小为 K 且平均值大于等于阈值的子数组数目
这道题我想应该是考察的滑动窗口的思想,也就是保持 K 个元素的窗口,然后不断得往后移动,对于每个新的窗口,只需要做: sum = sum - old + new
即可,所以整个下来也没有啥问题,需要注意的就是题目是 ≥ threshold,我这里载了一次:
[[email protected]]# cat Q2.go
func numOfSubarrays(arr []int, k int, threshold int) int {
var (
i, sum, count int
length = len(arr)
)
for i = 0; i < k; i++ {
sum += arr[i]
}
for {
if threshold*k <= sum {
count++
}
if i >= length {
break
}
sum = sum - arr[i-k] + arr[i]
i++
}
return count
}
3. 时钟指针的夹角
这道题目看上去是个数学题,但其实我觉得倒有点像是考验细心的题目,一个难点就在于定位时针的位置,因为时针的位置还和分针有关,所以这里我的解决方式就是分别求出时针和分针相对于 12:00 的角度,然后再一减就是他们之间的夹角了。其中
- 分针的角度:minute * 6 ,因为一圈是 60 秒,总共 360 度,所以一分钟是 6 度。
- 时针的角度:hour 30 + (minute/ 60 ) 30,因为时针还会根据分钟走上一小段,这一小段就等于 ( minute / 60) * 30
所以最终的结果就是:时针的角度 - 分针的角度,再换算成 180 以内即可:
[[email protected]]# cat Q3.go
func angleClock(hour int, minutes int) float64 {
var (
locaH, locaM, diff float64
)
locaM = float64(6 * minutes)
locaH = float64(30*hour%360) + float64(minutes)*30.0/60.0
diff = max(locaH, locaM) - min(locaH, locaM)
if diff > 180.0 {
diff = 360 - diff
}
return diff
}
4. 跳跃游戏 IV
这道题我一看以为是 DP,但是推不出来表达式,然后一想应该是个 BFS,然后写了一版正向 BFS(从 0 开始,找 N-1),OOM 了,看了一下数据,全是同一个数字,一共有 50002 个 7,好奇怪。于是就换种思路,写了一版反向 BFS(从 N-1 开始,找 0),然后就过了,没看出来复杂度有多大区别。
这里有个优化的点就是,对相同值的索引要做个反向索引,这样可以保证 BFS 不会 Timeout:
[[email protected]]# cat Q4.go
import "container/list"
func minJumps(arr []int) int {
var (
length = len(arr)
// steps[i]: 从 i 到 end 的最小步数
steps = make([]int, length)
// 反向索引
valIdx = map[int][]int{}
i int
// 剪枝
visitedMap = map[int]bool{}
)
if length == 0 || length == 1 {
return 0
}
visitedMap[0] = true
visitedMap[-1] = true
visitedMap[length] = true
valIdx[arr[0]] = append(valIdx[arr[0]], i)
for i = 0; i < length; i++ {
steps[i] = -1
valIdx[arr[i]] = append(valIdx[arr[i]], i)
}
var q = list.New()
steps[length-1] = 0
q.PushBack(length - 1)
for q.Len() > 0 {
i = q.Remove(q.Front()).(int)
if i-1 >= 0 && steps[i-1] == -1 {
if i-1 == 0 {
return steps[i] + 1
}
q.PushBack(i - 1)
steps[i-1] = steps[i] + 1
}
if i+1 < length && steps[i+1] == -1 {
q.PushBack(i + 1)
steps[i+1] = steps[i] + 1
}
for _, idx := range valIdx[arr[i]] {
if idx == 0 {
return steps[i] + 1
}
if steps[idx] == -1 {
q.PushBack(idx)
steps[idx] = steps[i] + 1
}
}
}
return steps[0]
}
5. 小结
感觉双周赛的题目比较简单,玩家也稍微快一些,1小时加 5 分钟刷完的情况下,也只能到 100 多名。