文章

腾讯音乐笔试 2023-04-13场

腾讯音乐笔试 2023-04-13场

只能说,难度倒排也算是一种潮流了?🤮

第一题

规定一个好数组

  • 数组中的元素只有0,1,2;
  • 数组中任意两个相邻的数字都不相同;
定义一个数组的权值是相邻两个数字的绝对值之和。例如数组1, 3, 2, 4, 1,则有权值为:$W =3-1+2-3+4-2+1-4=8$

那么,求所有长度为$n$的的好数组的权值之和,结果取$10^9+7$的模

  • $1 \le n \le 10^9$

思路

我们应用一下递推的思想,因为不难发现,数组$n_{k+1}$是由数组$n_k$发展而来的,那么我们枚举一下数组$n_k$的末尾,肯定只有三个数字,他们各自对$n_{k+1}$有什么贡献呢:

20230313-tme-1-example01

每个数字的贡献之和是$8$,又由于好数组的定义,任意相邻的数字不相同,则当数组$n_k$的末尾为$0$,那么给数组$n_{k+1}$的贡献就是2个:$01$和$02$,前$k-1$的数组切片是张得一样的。那么不难得出如下结论:

\[\begin{aligned} n_{k+1} &= 2 n_k + 8 \times 2^{k-1} \end{aligned}\]

其中为什么是$2^{k-1}$呢,我们发现,当$n_1$时,共计三种:{0, 1, 2},对于$n_2$的贡献分别是1次,则是$2^0$;到$n_2$时,共计六种:{01, 02, 10, 12, 20, 21},那么对于$n_3$的贡献分别是2次,则是$2^1$。

接下来就是通过这个递推公式往下推了:

\[\begin{aligned} n_{k+1} &= 2 n_k + 8 \times 2^{k-1} \\ &= 2(2n_{k-1}+8 \times 2^{k-2}) + 8 \times 2^{k-1} &= 4 n_k + 2 \times 8 \times 2^{k-1} \\ &= 4(2n_{k-2}+8 \times 2^{k-3}) + 2 \times 8 \times 2^{k-1} &= 8 n_{k-1} + 3 \times 8 \times 2^{k-1} \\ &= \cdots &= 2^{k-1}n_2+(k-1) \times 8 \times 2^{k-1} \\ &= 2^{k-1} \times 8 = (k-1) \times 2^{k+2} &= k \times 2^{k+2} \\ \end{aligned}\]

所以有:

\[n_k = (k-1) \times 2^{k+1}\]

是不是很简单?但是本题其实还没有完结,我们再回头看一下$n$的范围,好家伙,绝对超了int64,那乘法我们还不能直接用,得做个小操作——二分求$2^{k+1}$,同时取模:(2**s) % (1e9+7) == (2**(s/2))**2 * 2**(s%2)

至此,全体的坑才算全绕过了。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
func fun(n int) int {
	mod := int64(1e9 + 7)
	sum := int64(n-1) % mod
	k := int64(n + 1)
	var dfs func(i int64) int64
	dfs = func(i int64) int64 {
		if i == 0 {
			return 1
		}
		num := dfs(i / 2)
		num = (num * num) % mod
		if i%2 == 1 {
			num = (num * 2) % mod
		}
		return num
	}

	return int((sum * dfs(k)) % mod)
}

复杂度

  • 时间复杂度:$O(\log n)$
  • 空间复杂度:$O(\log n)$(递归栈)

第二题

给一棵二叉树,节点个数为$n$,节点上都有权值$w$,替换权值为:以该节点为根的子树的所有权值之积的末尾零的个数

思路

20230413-tme-2-example01

又是零,自然想到$2 \times 5$,那么我们只要递归+回溯统计2和5的个数就行了,简单的DFS,没什么难度。

代码

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
45
46
47
48
type TreeNode struct {
	Val   int
	Left  *TreeNode
	Right *TreeNode
}

func valueOfTree(root *TreeNode) *TreeNode {
	var dfs func(node *TreeNode) (int, int)
	dfs = func(node *TreeNode) (two int, five int) {
		if node == nil {
			return 0, 0
		}

		two, five = count(node.Val)
		t, f := dfs(node.Left)
		two += t
		five += f
		t, f = dfs(node.Right)
		two += t
		five += f
		if two > five {
			node.Val = five
		} else {
			node.Val = two
		}

		return two, five
	}

	dfs(root)

	return root
}

func count(num int) (two, five int) {
	if num == 0 {
		return 0, 0
	}
	for num%2 == 0 {
		num /= 2
		two++
	}
	for num%5 == 0 {
		num /= 5
		five++
	}
	return two, five
}

复杂度

  • 时间复杂度:$O(n \log w)$
  • 空间复杂度:$O(n)$

第三题

构建一个大小为$\frac{n \times (n+1)}{2}$的数组,其中有1个1,2个2,……,n个n,但是相邻数字不相同。求其中一个数组(任意一个返回)。

思路

以$n=6$为例:654321_65432_6543_654_65_6,还看不出来?看代码吧。

代码

1
2
3
4
5
6
7
8
9
10
11
func fun(n int) []int {
	idx := 0
	ans := make([]int, (n*(n+1))/2)
	for i := 1; i <= n; i++ {
		for j := n; j >= i; j-- {
			ans[idx] = j
			idx++
		}
	}
	return ans
}

复杂度

  • 时间复杂度:$O(n^2)$
  • 空间复杂度:$O(n)$
本文由作者按照 CC BY 4.0 进行授权