您的位置:首页 > 其它

算法练习(1)—— 简单递归/回溯

2017-09-09 01:59 369 查看

算法练习(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,果然顺手许多~我觉得应该有更好的做法,有大神的话希望分享一下
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  算法 递归 leetcode