歌曲时长配对问题
问题描述
小F有一个由歌曲组成的列表,每首歌的持续时间用数组 time 表示,其中第 i 首歌的时长为 time[i] 秒。她想知道列表中有多少对歌曲的总持续时间能够被 10 整除。具体来说,我们希望找到所有满足 i < j 且 (time[i] + time[j]) % 10 == 0 的配对。
输入输出
-
输入:
time:一个整数数组,表示每首歌的持续时间。
-
输出:
- 一个整数,表示满足条件的配对数量。
测试样例
-
样例1:
- 输入:
time = [3, 2, 15, 1, 4] - 输出:
0 - 解释:没有满足条件的配对。
- 输入:
-
样例2:
- 输入:
time = [10, 20, 30] - 输出:
3 - 解释:所有配对都满足条件,分别是
(10, 20)、(10, 30)、(20, 30)。
- 输入:
-
样例3:
- 输入:
time = [7, 3, 5, 5, 10] - 输出:
2 - 解释:满足条件的配对是
(3, 7)和(5, 5)。
- 输入:
思路解析
1. 暴力解法
最直接的方法是使用两层循环,遍历所有可能的配对 (i, j),检查是否满足 (time[i] + time[j]) % 10 == 0。这种方法的时间复杂度为 O(n^2),在数组较大时效率较低。
package main
import "fmt"
func solution(time []int) int {
count:=0
for i:=0;i<len(time)-1;i++{
for j:=i+1;j<len(time);j++{
if (time[i]+time[j])%10==0{
count++
}
}
}
return count // Placeholder return
}
func main() {
fmt.Println(solution([]int{3, 2, 15, 1, 4}) == 0)
fmt.Println(solution([]int{10, 20, 30}) == 3)
fmt.Println(solution([]int{7, 3, 5, 5, 10}) == 2)
}
2. 优化解法
我们可以通过使用哈希表来优化这个过程。具体步骤如下:
- 创建一个哈希表
countMap,记录每个歌曲时长对10取余后的结果出现的次数。 - 遍历数组
time,对于每个歌曲时长t,计算t % 10,并在哈希表中查找与之配对的数量。 - 更新哈希表,记录当前歌曲时长对
10取余后的结果。
代码实现
package main
import "fmt"
func solution(time []int) int {
count := 0
countMap := make(map[int]int)
for _, t := range time {
remainder := t % 10
complement := (10 - remainder) % 10
if val, ok := countMap[complement]; ok {
count += val
}
countMap[remainder]++
}
return count
}
func main() {
fmt.Println(solution([]int{3, 2, 15, 1, 4}) == 0)
fmt.Println(solution([]int{10, 20, 30}) == 3)
fmt.Println(solution([]int{7, 3, 5, 5, 10}) == 2)
}
代码解析
-
初始化:
count:用于记录满足条件的配对数量。countMap:哈希表,记录每个歌曲时长对10取余后的结果出现的次数。
-
遍历数组:
- 使用
for _, t := range time遍历数组time。 - 计算当前歌曲时长
t对10取余后的结果remainder。 - 计算与之配对的余数
complement,即(10 - remainder) % 10。
- 使用
-
查找配对:
- 在哈希表
countMap中查找complement出现的次数,并将其加到count中。
- 在哈希表
-
更新哈希表:
- 将当前歌曲时长对
10取余后的结果remainder的计数加1。
- 将当前歌曲时长对
-
返回结果:
- 返回
count,表示满足条件的配对数量。
- 返回
总结
通过使用哈希表,我们可以将时间复杂度优化到 O(n),从而高效地计算出满足条件的配对数量。这种方法在处理大规模数据时也能保持较高的效率。
蛇形填充n阶方阵
问题描述
小U面临一个有趣的任务:在一个 n × n 的方阵中填入 1 到 n × n 这些数字,并要求按照蛇形顺序从右上角开始,沿着方阵的边界顺时针进行填充。蛇形填充的特殊排列方式使得每一层数字呈现出波浪形的排列方式。
输入输出
-
输入:
n:方阵的维度。
-
输出:
- 一个二维整数数组,表示填充后的方阵。
测试样例
-
样例1:
- 输入:
n = 4 - 输出:
[[10, 11, 12, 1], [9, 16, 13, 2], [8, 15, 14, 3], [7, 6, 5, 4]]
- 输入:
-
样例2:
- 输入:
n = 5 - 输出:
[[13, 14, 15, 16, 1], [12, 23, 24, 17, 2], [11, 22, 25, 18, 3], [10, 21, 20, 19, 4], [9, 8, 7, 6, 5]]
- 输入:
-
样例3:
- 输入:
n = 3 - 输出:
[[7, 8, 1], [6, 9, 2], [5, 4, 3]]
- 输入:
思路解析
1. 初始化方阵
首先,我们需要初始化一个 n × n 的二维数组,用于存储填充后的结果。
2. 定义方向
我们需要定义四个方向:右、下、左、上。每个方向对应一个二维向量,表示移动的方向。
3. 填充数字
从右上角开始,按照顺时针方向填充数字。每次填充一个数字后,检查下一个位置是否越界或已经填充过。如果越界或已经填充过,则改变方向。
4. 改变方向
当遇到边界或已经填充过的位置时,改变方向。方向的顺序是:右 -> 下 -> 左 -> 上,循环往复。
代码实现
package main
import (
"fmt"
"reflect"
)
func solution(n int) [][]int {
res := make([][]int, n)
for i := range res {
res[i] = make([]int, n)
}
// 定义四个方向:右、下、左、上
directions := [][]int{{0, 1}, {1, 0}, {0, -1}, {-1, 0}}
dir := 1 // 初始方向为下
x, y := 0, n-1 // 初始位置为右上角
for i := 1; i <= n*n; i++ {
res[x][y] = i
nextX, nextY := x + directions[dir][0], y + directions[dir][1]
// 检查下一个位置是否越界或已经填充过
if nextY == n || nextX < 0 || nextX == n || nextY < 0 || res[nextX][nextY] != 0 {
dir = (dir + 1) % 4 // 改变方向
nextX, nextY = x + directions[dir][0], y + directions[dir][1]
}
x, y = nextX, nextY
}
return res
}
func main() {
fmt.Println(reflect.DeepEqual(solution(4), [][]int{{10, 11, 12, 1}, {9, 16, 13, 2}, {8, 15, 14, 3}, {7, 6, 5, 4}}))
fmt.Println(reflect.DeepEqual(solution(5), [][]int{{13, 14, 15, 16, 1}, {12, 23, 24, 17, 2}, {11, 22, 25, 18, 3}, {10, 21, 20, 19, 4}, {9, 8, 7, 6, 5}}))
fmt.Println(reflect.DeepEqual(solution(3), [][]int{{7, 8, 1}, {6, 9, 2}, {5, 4, 3}}))
}
代码解析
-
初始化方阵:
- 使用
make([][]int, n)初始化一个n × n的二维数组res。 - 使用
for i := range res遍历每一行,并使用make([]int, n)初始化每一行的切片。
- 使用
-
定义方向:
- 使用
directions数组定义四个方向:右、下、左、上。 - 初始方向为下,使用
dir := 1表示。
- 使用
-
填充数字:
- 从右上角开始,使用
x, y := 0, n-1表示初始位置。 - 使用
for i := 1; i <= n*n; i++循环填充数字。 - 每次填充一个数字后,计算下一个位置
nextX, nextY。
- 从右上角开始,使用
-
检查下一个位置:
- 检查下一个位置是否越界或已经填充过。
- 如果越界或已经填充过,则改变方向
dir = (dir + 1) % 4。 - 重新计算下一个位置
nextX, nextY。
-
更新位置:
- 更新当前位置
x, y为下一个位置nextX, nextY。
- 更新当前位置
-
返回结果:
- 返回填充后的二维数组
res。
- 返回填充后的二维数组
总结
通过上述方法,我们可以高效地实现蛇形填充,并保持格式的整齐性。该方法的时间复杂度为 O(n^2),其中 n 是方阵的维度。这种方法在处理大规模数据时也能保持较高的效率。