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)
改进后的思路:由于满足每个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)
可考虑的改进,对index排序,先填充质数,再合数,再填2,最后填1,或许会更快