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:

  1. The number at the ith position is divisible by i.
  2. i is divisible by the number at the ith position.

Now given N, how many beautiful arrangements can you construct?

Example 1:

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.

Note:

  1. N is a positive integer and will not exceed 15.

这道题给了我们1到N,总共N个正数,然后定义了一种优美排列方式,对于该排列中的所有数,如果数字可以整除下标,或者下标可以整除数字,那么我们就是优美排列,让我们求出所有优美排列的个数。那么对于求种类个数,或者是求所有情况,这种问题通常要用递归来做,递归简直是暴力的不能再暴力的方法了。而递归方法等难点在于写递归函数,如何确定终止条件,还有for循环中变量的起始位置如何确定。那么这里我们需要一个visited数组来记录数字是否已经访问过,因为优美排列中不能有重复数字。我们用变量pos来标记已经生成的数字的个数,如果大于N了,说明已经找到了一组排列,结果res自增1。在for循环中,i应该从1开始,因为我们遍历1到N中的所有数字,如果该数字未被使用过,且满足和坐标之间的整除关系,那么我们标记该数字已被访问过,再调用下一个位置的递归函数,之后不要忘记了恢复初始状态,参见代码如下:

解法一:

class Solution {
public:
int countArrangement(int N) {
int res = ;
vector<int> visited(N + , );
helper(N, visited, , res);
return res;
}
void helper(int N, vector<int>& visited, int pos, int& res) {
if (pos > N) {
++res;
return;
}
for (int i = ; i <= N; ++i) {
if (visited[i] == && (i % pos == || pos % i == )) {
visited[i] = ;
helper(N, visited, pos + , res);
visited[i] = ;
}
}
}
};

上面的解法在N=4时产生的优美序列如下:

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

通过看上面的分析,是不是觉得这道题的本质其实是求全排列,然后在所有全排列中筛选出符合题意的排列。那么求全排列的另一种经典解法就是交换数组中任意两个数字的位置,来形成新的排列,参见代码如下:

解法二:

class Solution {
public:
int countArrangement(int N) {
vector<int> nums(N);
for (int i = ; i < N; ++i) nums[i] = i + ;
return helper(N, nums);
}
int helper(int n, vector<int>& nums) {
if (n <= ) return ;
int res = ;
for (int i = ; i < n; ++i) {
if (n % nums[i] == || nums[i] % n == ) {
swap(nums[i], nums[n - ]);
res += helper(n - , nums);
swap(nums[i], nums[n - ]);
}
}
return res;
}
};

上面的解法在N=4时产生的优美序列如下:

2 4 3 1
4 2 3 1
3 4 1 2
4 1 3 2
1 4 3 2
3 2 1 4
2 1 3 4
1 2 3 4

参考资料:

https://discuss.leetcode.com/topic/79916/java-solution-backtracking

https://discuss.leetcode.com/topic/79921/my-c-elegant-solution-with-back-tracking

LeetCode All in One 题目讲解汇总(持续更新中...)

[LeetCode] Beautiful Arrangement 优美排列的更多相关文章

  1. [LeetCode] Beautiful Arrangement II 优美排列之二

    Given two integers n and k, you need to construct a list which contains n different positive integer ...

  2. LeetCode Beautiful Arrangement II

    原题链接在这里:https://leetcode.com/problems/beautiful-arrangement-ii/description/ 题目: Given two integers n ...

  3. LeetCode Beautiful Arrangement

    原题链接在这里:https://leetcode.com/problems/beautiful-arrangement/description/ 题目: Suppose you have N inte ...

  4. [Swift]LeetCode526. 优美的排列 | Beautiful Arrangement

    Suppose you have N integers from 1 to N. We define a beautiful arrangement as an array that is const ...

  5. 【LeetCode】526. Beautiful Arrangement 解题报告(Python & C++)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 日期 题目地址:https://leetcode.c ...

  6. LC 667. Beautiful Arrangement II

    Given two integers n and k, you need to construct a list which contains n different positive integer ...

  7. 526. Beautiful Arrangement

    Suppose you have N integers from 1 to N. We define a beautiful arrangement as an array that is const ...

  8. LeetCode:下一个排列【31】

    LeetCode:下一个排列[31] 题目描述 实现获取下一个排列的函数,算法需要将给定数字序列重新排列成字典序中下一个更大的排列. 如果不存在下一个更大的排列,则将数字重新排列成最小的排列(即升序排 ...

  9. LeetCode:字符串的排列【567】

    LeetCode:字符串的排列[567] 题目描述 给定两个字符串 s1 和 s2,写一个函数来判断 s2 是否包含 s1 的排列. 换句话说,第一个字符串的排列之一是第二个字符串的子串. 示例1: ...

随机推荐

  1. Java注解(2)-注解处理器(运行时|RetentionPolicy.RUNTIME)

    如果没有用来读取注解的工具,那注解将基本没有任何作用,它也不会比注释更有用.读取注解的工具叫作注解处理器.Java提供了两种方式来处理注解:第一种是利用运行时反射机制:另一种是使用Java提供的API ...

  2. 网络1711班 C语言第七次作业批改总结

    网络1711班 C语言第七次作业批改总结 1.本次作业评分细则 1.1 基本要求(1分) 按时交 - 有分 未交 - 0分 迟交一周以上 - 倒扣本次作业分数 抄袭 - 0分 泛泛而谈(最多七分) 1 ...

  3. 敏捷开发每日报告--day4

    1 团队介绍 团队组成: PM:齐爽爽(258) 小组成员:马帅(248),何健(267),蔡凯峰(285)  Git链接:https://github.com/WHUSE2017/C-team 2 ...

  4. Cocoapods最全完整使用教程

    什么是cocoapods cocoapods是库管理工具. cocoapods的用途 解决库之间的依赖关系.如前文所述: 一个开源的项目可能是另一个项目的基础, A依赖B, B依赖C和D, D又依赖E ...

  5. python的Flask 介绍

    Flask 介绍 知识点 微框架.WSGI.模板引擎概念 使用 Flask 做 web 应用 模板的使用 根据 URL 返回特定网页 实验步骤 1. 什么是 Flask? Flask 是一个 web ...

  6. Flask 页面缓存逻辑,jinja2 过滤器,测试器

    回调接入点-页面缓存逻辑 from flask import Flask,request,render_template from werkzeug.contrib.cache import Simp ...

  7. vue的简单tab

    <!DOCTYPE html><html lang="en"> <head> <meta charset="UTF-8" ...

  8. python全栈开发-Day13 内置函数

    一.内置函数 注意:内置函数id()可以返回一个对象的身份,返回值为整数. 这个整数通常对应与该对象在内存中的位置,但这与python的具体实现有关,不应该作为对身份的定义,即不够精准,最精准的还是以 ...

  9. v7000数据恢复_MDisk重建数据恢复方法(北亚数据恢复)

    很多工程师都有这样的疑问,MDisk重建后还能不能恢复数据呢?应该怎么做才能恢复数据呢?本文这里就以IBM V7000存储为例,详细讲解因为某个MDisk被重建导致的数据丢失的恢复方法.我们本案例中的 ...

  10. thinkphp框架调用类不存在的方法

    thinkphp框架调用类不存在的方法调用类不存在的方法,不会报错,但是也不会执行,这是根据tp框架里面的一个魔术方法,框架里面一共才十几个魔术方法