2741. Special Permutations

题目 #

You are given a 0-indexed integer array nums containing n distinct positive integers. A permutation of nums is called special if:

  • For all indexes 0 <= i < n - 1, either nums[i] % nums[i+1] == 0 or nums[i+1] % nums[i] == 0.

Return the total number of special permutations. As the answer could be large, return it modulo $10^9 + 7$.

Example 1:

Input: nums = [2,3,6]
Output: 2
Explanation: [3,6,2] and [2,6,3] are the two special permutations of nums.

Example 2:

Input: nums = [1,4,3]
Output: 2
Explanation: [3,1,4] and [4,1,3] are the two special permutations of nums.

Constraints:

  • 2 <= nums.length <= 14
  • $1 <= nums[i] <= 10^9$

思路1 dp递推 #

分析 #

  • 一位一位数放,将某个数是否出现过记录在二进制数中
  • 记录上一位出现的数字,枚举下一位可以出现什么数字,记录的是第i位是x的某个状态的数量

代码 #

 1func specialPerm1(nums []int) int {
 2	var mod int = 1e9 + 7
 3	n := len(nums)
 4	// 第一维是上一位是什么数字,第二维是状态(保存什么数字出现过的二进制),value为数量
 5	stMap := map[int]map[uint16]int{}
 6	for i, v := range nums {
 7		stMap[v] = map[uint16]int{
 8			1 << i: 1,
 9		}
10	}
11	for i := 1; i < n; i++ {
12		tmp := stMap
13		stMap = make(map[int]map[uint16]int)
14		// 遍历map,找state中没出现过的数字,看能否填到此位,能填就加上数量
15		for l, vMap := range tmp {
16			// 遍历所有的状态,然后遍历所有的nums,没出现过且可以放就放进去
17			for j, v := range nums {
18				for st, c := range vMap {
19					// 出现过或不能放到下一位就跳过
20					if st&(1<<j) > 0 || (v%l != 0 && l%v != 0) {
21						continue
22					}
23					if stMap[v] == nil {
24						stMap[v] = make(map[uint16]int)
25					}
26					st |= (1 << j)
27					stMap[v][st] = (stMap[v][st] + c) % mod
28				}
29			}
30		}
31	}
32	res := 0
33	for _, c := range stMap {
34		for _, c1 := range c {
35			res = (res + c1) % mod
36		}
37	}
38	return res
39}

思路2 优化时间复杂度 #

分析 #

  • 在上一步的基础上,发现每次要遍历所有的数,如果提前把某个数下一个数能选啥给找出来可以遍历少一点

代码 #

 1func specialPerm(nums []int) int {
 2	var mod int = 1e9 + 7
 3	// 先找出谁能和谁做邻居
 4	// key为数字值,v为index
 5	pMap := map[int][]int{}
 6	n := len(nums)
 7	for i, v := range nums {
 8		for j := i + 1; j < n; j++ {
 9			v1 := nums[j]
10			if v%v1 == 0 || v1%v == 0 {
11				pMap[v] = append(pMap[v], j)
12				pMap[v1] = append(pMap[v1], i)
13			}
14		}
15	}
16	stMap := map[int]map[uint16]int{}
17	for i, v := range nums {
18		stMap[v] = map[uint16]int{
19			1 << i: 1,
20		}
21	}
22	for range nums[:n-1] {
23		tmp := stMap
24		stMap = make(map[int]map[uint16]int)
25		// 遍历map,找state中没出现过的数字,看能否填到此位,能填就加上数量
26		for k, v := range tmp {
27			for _, v1 := range pMap[k] {
28				for st, c := range v {
29					if st&(1<<v1) > 0 {
30						continue
31					}
32					st |= 1 << v1
33					if stMap[nums[v1]] == nil {
34						stMap[nums[v1]] = make(map[uint16]int)
35					}
36					stMap[nums[v1]][st] = (stMap[nums[v1]][st] + c) % mod
37				}
38			}
39		}
40	}
41	res := 0
42	for _, c := range stMap {
43		for _, c1 := range c {
44			res = (res + c1) % mod
45		}
46	}
47	return res
48}