算法练习(1)—— 简单递归/回溯
前言
算法课的一环。题目一般都是从leetcode里拿,希望自己在学习中能有所提升吧,也希望自己能坚持下去。
习题
这次的例题是在 Backtracking
栏目里找的第一题。
标题为 526. Beautiful Arrangement
懒得点链接的同学就直接看我下面的搬运吧~
Description
Suppose you have N integers from 1 to N. We define a beautiful arrangement as an array that is constructed by these N numbers successfully if one of the following is true for the ith position (1 <= i <= N) in this array:
- The number at the ith position is divisible by i.
- i is divisible by the number at the ith position.
Now given N, how many beautiful arrangements can you construct?
Note
N is a positive integer and will not exceed 15.
Example
Input: 2
Output: 2
Explanation:The first beautiful arrangement is [1, 2]:
Number at the 1st position (i=1) is 1, and 1 is divisible by i (i=1).
Number at the 2nd position (i=2) is 2, and 2 is divisible by i (i=2).
The second beautiful arrangement is [2, 1]:
Number at the 1st position (i=1) is 2, and 2 is divisible by i (i=1).
Number at the 2nd position (i=2) is 1, and i (i=2) is divisible by 1.
思路与代码
1.首先理解一下题意,大概就是每个数放在对应的第i位,要么它能整除i,要么i能整除它。
2.题目给了个N=2的样例,不太具有代表性,因此我列一个N=4的solution:
[1,2,3,4] [1,4,3,2]
[2,1,3,4] [2,4,3,1]
[3,2,1,4] [3,4,1,2]
[4,1,3,2] [4,2,3,1]
3.列出来之后,我的最直接的想法就是枚举法。题目要求 N <= 15
,如果用纯粹的枚举,最多需要 15!
步。所以在枚举的过程中需要剪枝,就是列出之前先判断是否符合 两个要求之一 。这样其实可以省去特别多的次数。
4.实际写出来的代码如下:
#include <set>
class Solution {
public:
int countArrangement(int N) {
int count = 0;
std::set<int> restNum;
for (int i = 1; i <= N; i++)
restNum.insert(i);
recurse(1, restNum, count, N);
return count;
}
/**
** @param 当前递归所在的数组下标 i
** @param 当前递归所剩余的未使用的数字 restNum
** @param beautiful arrangement的个数,按引用传递
** @param 最大数字 N
*/
void recurse(int i, set<int> restNum, int& count, int N) {
// 递归结束条件
if (i == N) {
int target = *restNum.begin();
if (target % i == 0 || i % target == 0)
count++;
else
return;
}
if (i < N) {
std::set<int>::iterator it = restNum.begin();
// 对于满足条件的数字进行枚举,依次放入
for (; it != restNum.end(); it++) {
int target = *it;
if (target % i == 0 || i % target == 0) {
std::set<int> recurseSet(restNum);
recurseSet.erase(target);
recurse(i + 1, recurseSet, count, N);
}
}
}
}
};
5.以上代码已通过。一开始用的vector,写到一半觉得删除元素不方便,改成了set,果然顺手许多~我觉得应该有更好的做法,有大神的话希望分享一下