递归全局变量问题:数组全排列结果异常及无全局变量实现方案
嗨,我来帮你拆解和解决这两个问题:
问题分析与解决方案
一、类变量ans输出异常的原因
你遇到的重复排列问题,核心有两个关键原因:
- 未复制
acc就添加到结果中:你在helper函数里直接把acc添加到self.ans,但acc是可变的列表对象,后续的acc.pop()操作会修改这个对象的内容。因为self.ans里存的是acc的引用而非独立副本,所以之前添加的结果会跟着acc的修改同步变化,最终出现重复的排列条目。 - 多余的
global ans声明:你的ans是类属性,用self.ans访问即可,global ans这行代码没有实际作用,反而容易造成混淆。
比如你输出里的[[1, 3, 2], [1, 3, 2]],就是因为第一次添加的[1,2,3]和第二次添加的[1,3,2]其实是同一个列表对象的引用,当acc被修改为[1,3,2]时,之前的条目也跟着变了。
修正后的类变量版本代码
只需要在添加到ans时,复制一份acc的副本(因为acc里是整数,浅拷贝acc.copy()就足够,不需要deepcopy):
from copy import deepcopy from typing import List class Solution: ans = [] def permute(self, nums: List[int]) -> List[List[int]]: if nums is None: return None # 重要:每次调用permute时清空ans,避免多次调用累积旧结果 self.ans.clear() self.helper(nums, []) return self.ans def helper(self, rem, acc): # 移除无用的global ans声明 rem_cpy = deepcopy(rem) if len(rem) == 0: # 添加acc的副本,而非引用 self.ans.append(acc.copy()) print(self.ans) return for i in range(len(rem_cpy)): acc.append(rem_cpy[i]) rem = rem_cpy[:i] + rem_cpy[i+1:] self.helper(rem, acc) acc.pop()
二、不使用全局/类变量的递归实现
要摆脱全局变量,我们可以让helper函数直接返回当前剩余元素能生成的所有排列,上层函数合并这些子结果即可。核心思路是:
- 当剩余元素为空时,返回只包含当前路径副本的列表;
- 遍历每个剩余元素,将其加入当前路径,递归处理剩余元素,把递归返回的所有排列合并到结果中,最后回溯弹出当前元素。
实现代码
from typing import List class Solution: def permute(self, nums: List[int]) -> List[List[int]]: if nums is None: return None return self.helper(nums, []) def helper(self, rem, acc): if not rem: # 返回包含当前路径副本的列表 return [acc.copy()] result = [] for i in range(len(rem)): acc.append(rem[i]) # 递归获取子排列,并合并到结果中 sub_perms = self.helper(rem[:i] + rem[i+1:], acc) result.extend(sub_perms) acc.pop() return result
更简洁的无回溯写法(无需pop)
这种写法每次递归都创建新的列表,完全避免了共享可变对象的问题,代码也更直观:
from typing import List class Solution: def permute(self, nums: List[int]) -> List[List[int]]: if not nums: return [[]] result = [] for i in range(len(nums)): # 固定当前元素,递归处理剩余元素的所有排列 for perm in self.permute(nums[:i] + nums[i+1:]): result.append([nums[i]] + perm) return result
这个版本里,每次递归都会生成新的排列列表,根本不需要全局变量或者类属性,逻辑也更清晰。
内容的提问来源于stack exchange,提问作者user6235442
相关产品推荐
相关产品推荐

