
该函数接收一个数字列表,返回一个新列表的列表:对原列表每个索引 i,生成一个新列表,其中仅第 i 个元素被替换为除它自身外所有其他元素的乘积,其余位置保持不变。
这是一个经典的“除自身以外数组的乘积”问题的变体——但不是返回单个结果数组,而是返回全部 n 种置换结果组成的二维列表(即每行对应一种“只改一个位置”的情形)。
✅ 正确思路解析
原提问者代码的主要错误在于:
- results = arr 是浅拷贝(实际是同一对象引用),导致每次修改 results[i] 都污染了原始数组和后续迭代;
- 使用 np.prod(arr) / arr[i] 在整数场景下易引发浮点误差或除零异常;
- 未构造独立的新列表,也未收集所有结果到返回值中。
下面提供 纯 Python(无 NumPy)、健壮、高效且可读性强 的实现:
def multi_list(arr):
"""
输入: 数字列表 arr(支持 int/float,假设非空且不含零更安全)
输出: 列表的列表 —— 对每个索引 i,返回一个新列表,
其中 arr[i] 被替换为其余所有元素的乘积,其余元素不变。
"""
if not arr:
return []
n = len(arr)
# 预计算总乘积(注意:若含0需特殊处理,见下方说明)
total_product = 1
for x in arr:
total_product *= x
result = []
for i in range(n):
# 构造新列表:深拷贝原列表(避免引用问题)
new_row = arr.copy()
# 替换第 i 个位置为“其余元素乘积”
# 即 total_product // arr[i](整除)或 total_product / arr[i](浮点)
# ⚠️ 若 arr[i] == 0,total_product 必为 0,此时其余元素乘积需单独计算
if arr[i] == 0:
# 手动计算除第 i 个外所有元素的乘积
prod_others = 1
for j, x in enumerate(arr):
if j != i:
prod_others *= x
new_row[i] = prod_others
else:
new_row[i] = total_product // arr[i] if isinstance(arr[i], int) and total_product % arr[i] == 0 else total_product / arr[i]
result.append(new_row)
return result? 使用示例
arr = [69, 78, 62, 73, 23]
output = multi_list(arr)
for i, row in enumerate(output):
print(f"第{i}行: {row}")输出(与预期一致):
立即学习“Python免费学习笔记(深入)”;
第0行: [8119644, 78, 62, 73, 23] 第1行: [69, 7182762, 62, 73, 23] 第2行: [69, 78, 9036378, 73, 23] 第3行: [69, 78, 62, 7674732, 23] 第4行: [69, 78, 62, 73, 24358932]
⚠️ 注意事项与优化建议
- 零值处理:若输入含 0,则总乘积为 0,直接 total_product / arr[i] 会得到 0/0 错误或不正确结果。上述实现已内置安全分支,对 arr[i] == 0 单独计算其余元素乘积。
- 大数溢出:Python 整数自动支持高精度,无需担心溢出,但极端大数据可能影响性能。
- 时间复杂度:O(n²),因每个 arr[i]==0 分支需 O(n) 计算;若确保输入无零,可优化至 O(n) 预处理 + O(n) 构建(如左右乘积数组法),但本题需返回完整二维结果,O(n²) 已是最优输出复杂度。
- 避免副作用:始终使用 arr.copy() 创建新列表,绝不复用原列表引用。
✅ 总结
该函数本质是生成“单点扰动矩阵”:每一行代表将原向量在某一位替换为其补集乘积的结果。掌握深拷贝、边界条件(尤其是零)、以及明确区分“修改副本”与“复用原对象”,是写出正确逻辑的关键。无需依赖 NumPy,纯 Python 即可清晰、可靠地实现。










