歌曲时长配对问题&蛇形填充n阶方阵| 豆包MarsCode AI刷题

43 阅读6分钟

歌曲时长配对问题

问题描述

小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. 优化解法

我们可以通过使用哈希表来优化这个过程。具体步骤如下:

  1. 创建一个哈希表 countMap,记录每个歌曲时长对 10 取余后的结果出现的次数。
  2. 遍历数组 time,对于每个歌曲时长 t,计算 t % 10,并在哈希表中查找与之配对的数量。
  3. 更新哈希表,记录当前歌曲时长对 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)
}

代码解析

  1. 初始化

    • count:用于记录满足条件的配对数量。
    • countMap:哈希表,记录每个歌曲时长对 10 取余后的结果出现的次数。
  2. 遍历数组

    • 使用 for _, t := range time 遍历数组 time
    • 计算当前歌曲时长 t 对 10 取余后的结果 remainder
    • 计算与之配对的余数 complement,即 (10 - remainder) % 10
  3. 查找配对

    • 在哈希表 countMap 中查找 complement 出现的次数,并将其加到 count 中。
  4. 更新哈希表

    • 将当前歌曲时长对 10 取余后的结果 remainder 的计数加1。
  5. 返回结果

    • 返回 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}}))
}

代码解析

  1. 初始化方阵

    • 使用 make([][]int, n) 初始化一个 n × n 的二维数组 res
    • 使用 for i := range res 遍历每一行,并使用 make([]int, n) 初始化每一行的切片。
  2. 定义方向

    • 使用 directions 数组定义四个方向:右、下、左、上。
    • 初始方向为下,使用 dir := 1 表示。
  3. 填充数字

    • 从右上角开始,使用 x, y := 0, n-1 表示初始位置。
    • 使用 for i := 1; i <= n*n; i++ 循环填充数字。
    • 每次填充一个数字后,计算下一个位置 nextX, nextY
  4. 检查下一个位置

    • 检查下一个位置是否越界或已经填充过。
    • 如果越界或已经填充过,则改变方向 dir = (dir + 1) % 4
    • 重新计算下一个位置 nextX, nextY
  5. 更新位置

    • 更新当前位置 x, y 为下一个位置 nextX, nextY
  6. 返回结果

    • 返回填充后的二维数组 res

总结

通过上述方法,我们可以高效地实现蛇形填充,并保持格式的整齐性。该方法的时间复杂度为 O(n^2),其中 n 是方阵的维度。这种方法在处理大规模数据时也能保持较高的效率。