共计 2212 个字符,预计需要花费 6 分钟才能阅读完成。
问题背景与数学原理分析
初看这个问题可能会觉得矛盾:一个数被 3 整除,余数应该是 0、1 或 2,怎么可能余 5?这其实涉及到模运算的数学定义。在数学中,a ≡ b mod m表示 a 和 b 在除以 m 时有相同的余数,但余数并不限于 0 到 m - 1 的范围。例如,11 ≡ 5 mod 3是正确的,因为 11 除以 3 商 3 余 2,5 除以 3 商 1 余 2,两者余数相同。

因此,我们需要找的是满足 x ≡ 5 mod 3 且1 ≤ x ≤ 100的整数 x。通过模运算性质可以转化为x = 3k + 5(k 为整数),然后寻找 x 在 1 到 100 之间的解。
常见错误解法示例
很多开发者第一反应可能会写出这样的代码:
def wrong_solution():
return [x for x in range(1, 101) if x % 3 == 5] # 永远返回空列表
function wrongSolution() {return Array.from({length: 100}, (_, i) => i + 1).filter(x => x % 3 === 5);
}
这种写法的问题在于 % 运算符在大多数编程语言中返回的是最小非负余数(0 到 m -1),所以 x % 3 的结果永远不会等于 5。
正确的编程实现
Python 版本
def find_numbers():
"""
找出 1 -100 范围内满足 x ≡ 5 mod 3 的所有整数
等价于解方程 x = 3k + 5,其中 x 在 [1,100] 范围内
"""
result = []
k = -2 # 从 k =- 2 开始,使得 3k+5= -1,下一个 k =- 1 时 x =2
while True:
x = 3 * k + 5
if x > 100:
break
if x >= 1:
result.append(x)
k += 1
return result
# 单元测试
def test_find_numbers():
expected = [2, 5, 8, 11, 14, 17, 20, 23, 26, 29, 32, 35, 38, 41, 44, 47, 50, 53, 56, 59, 62, 65, 68, 71, 74, 77, 80, 83, 86, 89, 92, 95, 98]
assert find_numbers() == expected
print("测试通过!")
test_find_numbers()
JavaScript 版本
function findNumbers() {
/**
* 找出 1 -100 范围内满足 x ≡ 5 mod 3 的所有整数
* 等价于解方程 x = 3k + 5,其中 x 在 [1,100] 范围内
*/
const result = [];
let k = -2; // 从 k =- 2 开始
while (true) {
const x = 3 * k + 5;
if (x > 100) break;
if (x >= 1) result.push(x);
k++;
}
return result;
}
// 单元测试
function testFindNumbers() {const expected = [2, 5, 8, 11, 14, 17, 20, 23, 26, 29, 32, 35, 38, 41, 44, 47, 50, 53, 56, 59, 62, 65, 68, 71, 74, 77, 80, 83, 86, 89, 92, 95, 98];
const actual = findNumbers();
console.assert(JSON.stringify(actual) === JSON.stringify(expected),
` 测试失败!预期:${expected},实际:${actual}`);
console.log("测试通过!");
}
testFindNumbers();
性能优化建议
- 数学优化:可以直接计算 k 的取值范围,避免循环。最小 k 满足 3k+5≥1 ⇒ k≥-4/3 ⇒ k≥-1;最大 k 满足 3k+5≤100 ⇒ k≤95/3 ⇒ k≤31。所以 k 从 - 1 到 31。
def optimized_find_numbers():
return [3*k +5 for k in range(-1, 32) if 1 <= 3*k +5 <= 100]
- 更通用的函数:
def find_mod_numbers(mod, remainder, start, end):
"""通用解法:找出 [start,end] 范围内满足 x ≡ remainder mod mod 的所有整数"""
# 找到第一个 k 使得 mod*k + remainder >= start
first_k = (start - remainder + mod - 1) // mod # 向上取整的技巧
last_k = (end - remainder) // mod # 向下取整
return [mod*k + remainder for k in range(first_k, last_k +1)]
实际应用场景讨论
- 日历计算:比如计算某个月的所有星期五,可以看作是 ” 日期 ≡ 5 mod 7″ 的问题
- 循环队列:确定队列中特定位置的元素
- 密码学:某些加密算法涉及模运算的特殊余数
变体问题思考
如果题目改为余数是负数呢?例如找 1 -100 范围内 x ≡ -1 mod 3 的数。根据模运算定义,这等价于 x ≡ 2 mod 3,所以解法类似。
def find_negative_remainder():
# x ≡ -1 mod 3 等价于 x ≡ 2 mod 3
return [x for x in range(1, 101) if x % 3 == 2]
数学思维拓展
这种模运算的思维方式可以应用于:
- 哈希函数设计:如何均匀分布键值
- 随机数生成:线性同余生成器的原理
- 算法竞赛问题:如找出满足特定模条件的子序列
通过这个问题,我们学习到:
- 编程语言中的
%运算符与数学模运算的差异 - 如何将数学概念准确转化为代码
- 边界条件的处理方法
- 编写通用函数的重要性
希望这个例子能帮助你在遇到类似问题时,从数学本质出发,找到更优雅的解决方案。
正文完
发表至: 未分类
近一天内
