Question:
Given an array A
of non-negative integers, the array is squareful if for every pair of adjacent elements, their sum is a perfect square.
Return the number of permutations of A that are squareful. Two permutations A1
and A2
differ if and only if there is some index i
such that A1[i] != A2[i]
.
正方形数组的数目
给定一个非负整数数组 A
,如果该数组每对相邻元素之和是一个完全平方数,则称这一数组为正方形数组。
返回 A 的正方形排列的数目。两个排列 A1
和 A2
不同的充要条件是存在某个索引 i
,使得 A1[i] != A2[i]。
示例 1:
输入:[1,17,8] 输出:2 解释: [1,8,17] 和 [17,8,1] 都是有效的排列。
示例 2:
输入:[2,2,2] 输出:1
分析:开始有两种思路:
1.遍历得到列表各种排列方式,并判断。不太可行,必定超时
2.找出列表中的完全平方数组合,对组合进行排列,涉及到重复值的问题,最终未实现。
评论中有大佬提到回溯法,查了一下发现自己之前学过相关的内容,竟然没有想到。
回溯法,基本可以理解为深度优先遍历+剪枝,是对树遍历的优化。在对树进行深度优先遍历时,当遇到非解、非最优解时,不再深入遍历,放弃这一枝。
应用到本题:从列表中不断选择元素进行排序,每次选择元素相当于树的深度增加;当选择的元素与前一元素不构成完全平方数时,放弃后续选择,选择元素不加入已排序元素,从剩余未选择的元素中选择下一元素,这一操作相当于剪枝。
class Solution:
def numSquarefulPerms(self, A) -> int:
results = []
result = []
self.bt(A,result,results)
self.Judge2(results)
print(results)
return len(results)
def bt(self,a,res,ress):
for i in a[::-1]:
# print(a,i,res)
if len(res) == 0:
b = a.copy()
re = res.copy()
re.append(i)
b.remove(i)
self.bt(b,re,ress)
elif self.Judge(res[-1]+i):
b = a.copy()
re = res.copy()
re.append(i)
b.remove(i)
self.bt(b, re, ress)
if len(a) == 0:
ress.append(res)
def Judge(self,num):
num = math.sqrt(num)
return num == int(num)
def Judge2(self,l):
for i in range(len(l)):
for j in range(i+1,len(l))[::-1]:
if str(l[i]) == str(l[j]):
l.pop(j)
问题:虽然做了剪枝优化,但对重复的元素的排序,只在结果中进行了排除,重复运算量很大,超时,示例:[2,2,2,2,2,2,2,2,2,2]
根据评论中PayneMiller大佬的代码,进行优化:在选择元素进行排序之前,先对元素进行排序,保证相同元素相邻;在选择排序时,如果有重复元素,只对最后一个元素进行选择(如果选择前面元素排序,当这一枝遍历完毕,进行下一枝遍历时,仍会产生相同枝,只对最后元素选择可避免重复枝出现)
import math
class Solution:
def numSquarefulPerms(self, A) -> int:
results = []
result = []
A.sort()
self.bt(A,result,results)
# self.Judge2(results)
print(results)
return len(results)
def bt(self,a,res,ress):
for i in range(len(a))[::-1]:
# print(a,i,res)
if i!= 0 and a[i] == a[i - 1]:
continue
if len(res) == 0 or self.Judge(res[-1]+a[i]):
b = a.copy()
re = res.copy()
re.append(a[i])
b.pop(i)
self.bt(b,re,ress)
if len(a) == 0:
ress.append(res)
def Judge(self,num):
num = math.sqrt(num)
return num == int(num)
附上评论里PayneMiller大佬源码:
class Solution:
def numSquarefulPerms(self, A) -> int:
res = []
A.sort()
self.helper(A, [], res)
return len(res)
def helper(self, nums, curr, res):
if not nums:
res.append(curr)
return
for i in range(len(nums)):
if i > 0 and nums[i] == nums[i - 1]:
continue
if len(curr) == 0 or math.sqrt(curr[-1] + nums[i]) % 1 == 0:
self.helper(nums[:i] + nums[i + 1:], curr + [nums[i]], res)