连续数字差绝对值为K的问题 | 豆包MarsCode AI刷题

150 阅读3分钟

连续数字差绝对值为K的问题

在生成特定规则数字的问题中,我们需要灵活构造满足约束条件的结果集合。本题要求生成所有长度为 n 的非负整数,且每两个连续数字的差的绝对值必须为 k。这一问题不仅考验对数字序列的理解,还要求我们能够通过递归或回溯方法逐步构造合规的数字组合。同时,为了保证结果的正确性和输出顺序,需要在构造过程中进行剪枝优化,合理选择下一步操作,从而高效地找到所有满足条件的整数组合。

一、问题描述

小R正在研究一些数字生成的有趣性质。他需要找出所有长度为 n 且满足其每两个连续位上的数字之间的差的绝对值为 k 的非负整数。注意,除了数字 0 本身之外,答案中的每个数字都不能有前导零(例如,01 是无效的,但 0 是有效的)。最后,请从小到大返回所有符合条件的整数。

二、解题思路

这道题需要逐位生成符合条件的数字,因此可以采用递归或回溯的方式解决:

  1. 递归生成数字

    • 从数字 1 到 9 开始(因为不能有前导零),逐位构造长度为 n 的数字。
    • 对于每个数字,根据其最后一位,尝试添加符合条件的下一位(当前数字的最后一位加 k 或减 k)。
  2. 剪枝优化

    • 在构造过程中,若当前位加或减 k 后的值超出合法范围(如小于 0 或大于 9),直接跳过该分支。
    • 当数字长度达到 n 时,将其加入结果集合。
  3. 特殊情况处理

    • 当 n=1 时,可以直接返回所有数字(0 到 9)。
    • 当 k=0 时,每个数字的所有位必须相同,如 111 或 777。

三、解题步骤

  • 初始化结果集合:准备一个结果列表,用于存储所有符合条件的数字。

  • 递归构造数字

    • 从 1 到 9 依次开始,调用递归函数进行数字构造;
    • 在递归函数中,根据当前数字的最后一位计算可能的下一位,判断其合法性后继续递归。
  • 特殊情况处理

    • 如果 n=1,需要额外将数字 0 加入结果。
  • 输出结果:返回结果集合,按从小到大的顺序排列.

四、代码实现

以下是基于Go语言的代码实现:

// findNumbers 找到所有满足条件的整数
func findNumbers(n, k int) []int {
	var results []int

	// 从 1 到 9 开始构造数字
	for i := 1; i <= 9; i++ {
		buildNumbers(i, n-1, k, &results)
	}

	// 如果 n == 1,则需要包含 0
	if n == 1 {
		results = append(results, 0)
	}

	// 从小到大返回结果
	sort.Ints(results)
	return results
}

// buildNumbers 递归构造符合条件的数字
func buildNumbers(current, remaining, k int, results *[]int) {
	if remaining == 0 {
		*results = append(*results, current)
		return
	}

	lastDigit := current % 10

	// 尝试加 k 和减 k 的情况
	for _, diff := range []int{k, -k} {
		nextDigit := lastDigit + diff
		if nextDigit >= 0 && nextDigit <= 9 { // 确保合法性
			buildNumbers(current*10+nextDigit, remaining-1, k, results)
		}
	}
}

五、复杂度分析

  • 时间复杂度

    • 对于每个起始数字(1 到 9),递归生成一棵深度为 n 的树;
    • 每次递归有两个分支(加 k 和减 k),总调用次数约为 O(9*2^(n-1))。
    • 因此,总时间复杂度为 O(9*2^(n−1))。
  • 空间复杂度

    • 递归调用栈的深度为 n,因此空间复杂度为 O(n)。

六、总结

本题是一个经典的递归与回溯问题,通过逐步构造满足条件的数字,确保每一步的合法性,并在长度达到 n 时将结果加入集合。

  • 关键点:利用递归函数逐位生成数字,同时通过条件判断对非法分支进行剪枝优化。
  • 特殊情况:如 k=0 或 n=1 时的特殊处理。