526优美的排列

题目:假设有从 1 到 N 的 N 个整数,如果从这 N 个数字中成功构造出一个数组,使得数组的第 i 位 (1 <= i <= N) 满足如下两个条件中的一个,我们就称这个数组为一个优美的排列。条件:a>第 i 位的数字能被 i 整除  b>i 能被第 i 位上的数字整除现在给定一个整数 N,请问可以构造多少个优美的排列?
来源:https://leetcode-cn.com/problems/beautiful-arrangement/

法一:自己的代码   回溯法  时间上击败百分之60

思路:遍历回溯,先取一个数字放在第一位上看是否满足如果满足,回溯遍历剩下的,否则结束

class Solution:
    def countArrangement(self, N: int) -> int:
        results = [0]
        # 逆序遍历更省时间
        nums = [N-i for i in range(N)]
        print(nums)
        def backtrack(a=[], nums=nums, index=0):
            if len(a) == N:
                results[0] = results[0] + 1
                return
            index += 1
            for i,j in enumerate(nums):
                # 剪枝条件,如果不满足,直接进入下一个循环
                if (j % index == 0) | ( index % j == 0):
                    b = nums.copy()
                    del b[i]
                    backtrack(a+[j],nums=b,index=index)
                else:
                    continue
        backtrack()
        return results[0]

if __name__ == '__main__':
    duixiang = Solution()
    a = duixiang.countArrangement(15)
    print(a)
View Code

改进后的思路:由于满足每个index的数不用,如给的是8,则第三位只能是1 3 6这个三个数,其它的数不需要遍历,每个位置遍历的数都是满足这个位置的和已经用过的差集,提交后超时

class Solution:
    def countArrangement(self, N: int) -> int:
        results = [0]
        nums = [N-i for i in range(N)]
        # nums = [i+1 for i in range(N)]
        print(nums)
        # 求数n的所有因子,但不包括n,因为下面的index_multiple中已经包括了
        def find_factor(n):
            res = []
            if n == 1:
                return set([1])
            for i in range(1,n):
                if n % i == 0:
                    res.append(i)
            return set(res)
        # 求index到N之间,所有index的倍数
        def index_multiple(index,N):
            p = 1
            res = []
            while p * index <= N:
                res.append(p*index)
                p += 1
            return set(res)
        # 回溯函数
        def backtrack(a=[], nums=nums, index=0):
            # 这里可以看做是可变对象的妙用,如果变量为整型的话,则函数调用结束会变为调用前的值
            if len(a) == N:
                results[0] = results[0] + 1
                return
            index += 1
            # num中存放的是第index位可以放的数字,每次只遍历在该位可以放的数字,注意要去掉已经使用过的数字a
            # 这里如果不加括号的话会先计算 差集 - 后计算并集 |  因为 - 的优先级高
            # 对nums的限定就是剪枝条件
            nums = list((index_multiple( index, N) | find_factor(index)) - set(a))
            # 排序后再逆序也超时
            # nums.sort()
            # nums.reverse()
            for i,j in enumerate(nums):
                backtrack(a+[j],index=index)
        backtrack()
        return results[0]

if __name__ == '__main__':
    duixiang = Solution()
    a = duixiang.countArrangement(15)
    print(a)
View Code

可考虑的改进,对index排序,先填充质数,再合数,再填2,最后填1,或许会更快

 

posted on 2019-12-01 14:20  吃我一枪  阅读(188)  评论(0编辑  收藏  举报

导航