具体地,我们定义函数 backtrack}(\textit{index}, n),表示尝试向位置 index 放入数。其中 n 表示排列的长度。在当前函数中,我们首先找到一个符合条件的未被使用过的数,然后递归地执行 backtrack}(\textit{index}+1, n),当该函数执行完毕,回溯到当前层,我们再尝试下一个符合条件的未被使用过的数即可。
回溯过程中,我们可以用 vis 数组标记哪些数被使用过,每次我们选中一个数 x,我们就将 vis}[x] 标记为 true,回溯完成后,我们再将其置为 false。
特别地,为了优化回溯效率,我们可以预处理每个位置的符合条件的数有哪些,用二维数组 match 保存。当我们尝试向位置 index 放入数时,我们只需要遍历 match}[\textit{index}] 即可。
var countArrangement = function(n) { const vis = newArray(n + 1).fill(0); const match = newArray(n + 1).fill(0); let num = 0; for (let i = 0; i <= n; i++) { match[i] = []; } for (let i = 1; i <= n; i++) { for (let j = 1; j <= n; j++) { if (i % j === 0 || j % i === 0) { match[i].push(j); } } }
constbacktrack = (index, n) => { if (index === n + 1) { num++; return; } for (const x of match[index]) { if (!vis[x]) { vis[x] = true; backtrack(index + 1, n); vis[x] = false; } } } backtrack(1, n); return num; };
classSolution: defcountArrangement(self, n: int) -> int: match = defaultdict(list) for i inrange(1, n + 1): for j inrange(1, n + 1): if i % j == 0or j % i == 0: match[i].append(j) num = 0 vis = set()
defbacktrack(index: int) -> None: if index == n + 1: nonlocal num num += 1 return for x inmatch[index]: if x notin vis: vis.add(x) backtrack(index + 1) vis.discard(x) backtrack(1) return num
int **match; int *matchColSize; int *vis; int num;
voidbacktrack(int index, int n) { if (index == n + 1) { num++; return; } for (int i = 0; i < matchColSize[index]; i++) { int x = match[index][i]; if (!vis[x]) { vis[x] = true; backtrack(index + 1, n); vis[x] = false; } } }
intcountArrangement(int n) { vis = malloc(sizeof(int) * (n + 1)); match = malloc(sizeof(int *) * (n + 1)); matchColSize = malloc(sizeof(int) * (n + 1)); memset(matchColSize, 0, sizeof(int) * (n + 1)); memset(vis, 0, sizeof(int) * (n + 1)); num = 0; for (int i = 1; i <= n; i++) { match[i] = malloc(sizeof(int) * (n)); for (int j = 1; j <= n; j++) { if (i % j == 0 || j % i == 0) { match[i][matchColSize[i]++] = j; } } } backtrack(1, n); return num; }
publicclassSolution { publicintCountArrangement(int n) { int[] f = newint[1 << n]; f[0] = 1; for (int mask = 1; mask < (1 << n); mask++) { int num = BitCount(mask); for (int i = 0; i < n; i++) { if ((mask & (1 << i)) != 0 && ((num % (i + 1)) == 0 || (i + 1) % num == 0)) { f[mask] += f[mask ^ (1 << i)]; } } } return f[(1 << n) - 1]; }
privatestaticintBitCount(int i) { i = i - ((i >> 1) & 0x55555555); i = (i & 0x33333333) + ((i >> 2) & 0x33333333); i = (i + (i >> 4)) & 0x0f0f0f0f; i = i + (i >> 8); i = i + (i >> 16); return i & 0x3f; } }
[sol2-JavaScript]
1 2 3 4 5 6 7 8 9 10 11 12 13
var countArrangement = function(n) { const f = newArray(1 << n).fill(0); f[0] = 1; for (let mask = 1; mask < (1 << n); mask++) { const num = mask.toString(2).split('0').join('').length for (let i = 0; i < n; i++) { if ((mask & (1 << i)) !== 0 && ((num % (i + 1)) === 0 || (i + 1) % num === 0)) { f[mask] += f[mask ^ (1 << i)]; } } } return f[(1 << n) - 1]; };
[sol2-Python3]
1 2 3 4 5 6 7 8 9 10 11
classSolution: defcountArrangement(self, n: int) -> int: f = [0] * (1 << n) f[0] = 1 for mask inrange(1, 1 << n): num = bin(mask).count("1") for i inrange(n): if mask & (1 << i) and (num % (i + 1) == 0or (i + 1) % num == 0): f[mask] += f[mask ^ (1 << i)] return f[(1 << n) - 1]
[sol2-C]
1 2 3 4 5 6 7 8 9 10 11 12 13 14
intcountArrangement(int n) { int f[1 << n]; memset(f, 0, sizeof(f)); f[0] = 1; for (int mask = 1; mask < (1 << n); mask++) { int num = __builtin_popcount(mask); for (int i = 0; i < n; i++) { if (mask & (1 << i) && (num % (i + 1) == 0 || (i + 1) % num == 0)) { f[mask] += f[mask ^ (1 << i)]; } } } return f[(1 << n) - 1]; }
[sol2-Golang]
1 2 3 4 5 6 7 8 9 10 11 12 13
funccountArrangement(n int)int { f := make([]int, 1<<n) f[0] = 1 for mask := 1; mask < 1<<n; mask++ { num := bits.OnesCount(uint(mask)) for i := 0; i < n; i++ { if mask>>i&1 > 0 && (num%(i+1) == 0 || (i+1)%num == 0) { f[mask] += f[mask^1<<i] } } } return f[1<<n-1] }