Beautiful Arrangement 优美的排列

假设有从 1 到 N 的 个整数,如果从这 个数字中成功构造出一个数组,使得数组的第 i 位 (1 <= i <= N) 满足如下两个条件中的一个,我们就称这个数组为一个优美的排列。条件:

  1. 第 位的数字能被 整除
  2. i 能被第 i 位上的数字整除

现在给定一个整数 N,请问可以构造多少个优美的排列?

示例1:

输入: 2
输出: 2
解释: 

第 1 个优美的排列是 [1, 2]:
  第 1 个位置(i=1)上的数字是1,1能被 i(i=1)整除
  第 2 个位置(i=2)上的数字是2,2能被 i(i=2)整除

第 2 个优美的排列是 [2, 1]:
  第 1 个位置(i=1)上的数字是2,2能被 i(i=1)整除
  第 2 个位置(i=2)上的数字是1,i(i=2)能被 1 整除

说明:

  1. N 是一个正整数,并且不会超过15。

思路:这道题是用回溯法来做,如果我们采用暴力求解法的递归求出全排列,然后对求出的每一个全排列判断漫步满足条件,那么肯定会超时。所以这道题要采用剪枝的做法,如果当前选择的做法已经不满足条件,那么就不要继续了。

具体思路为假设我们有N个数1~N,那么对于第一个数有N种情况,第二个数有N-1种情况。。。以此类推,用一个记忆数组memo来判断是否访问过当前数组的下标,如果没有访问过并且当前下标和下标对应的值可以整除或被整除,那么继续选择下一个数字,否则当前数字重选,这样做可以大大减少搜索的次数。

核心代码如下:

	for (int i = 1; i <= N; i++) {
		if(!memo[i] && (pos%i==0 || i%pos==0)){
			memo[i] = 1;
			countArrangementCore(N, pos + 1, memo,res);
			memo[i] = 0;
		}
	}

对于每位(当前为第i位)数字都从1遍历到N,只是下一位(i+1位)数字是否选择由memo控制,那么我们的截止条件便是如果当前位置pos访问到了word的最后一位的下一位,那么把结果res++。

参考代码:

class Solution {
public:
void countArrangementCore(int N,int pos, vector<bool> &memo,int &res) {
	if (pos>N) {
		res++;
		return;
	}
	for (int i = 1; i <= N; i++) {
		if(!memo[i] && (pos%i==0 || i%pos==0)){
			memo[i] = 1;
			countArrangementCore(N, pos + 1, memo,res);
			memo[i] = 0;
		}
	}
}
int countArrangement(int N) {
	if (N <= 1) return 1;
	vector<bool> memo(N+1,0);
	int res = 0;
	countArrangementCore(N, 1,memo,res);
	return res;
}
};

猜你喜欢

转载自blog.csdn.net/qq_26410101/article/details/81568467