python算法5.3——LeetCode_996_NumberOfSquarefulArrays

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)

猜你喜欢

转载自blog.csdn.net/nominior/article/details/89786980
996
5.3
今日推荐