leetcode-932.漂亮数组
分治法(递归实现)
题目详情
对于某些固定的 N
,如果数组 A
是整数 1, 2, ..., N
组成的排列,使得:
对于每个 i < j
,都不存在 k
满足i < k < j
使得 A[k] * 2 = A[i] + A[j]
。
那么数组 A
是漂亮数组。
给定 N
,返回任意漂亮数组 A
(保证存在一个)。
示例1:
输入:4
输出:[2,1,4,3]
示例2:
输入:5
输出:[3,1,2,5,4]
思路:
以5为例画出分治法的"分治图":
我的代码:
/* 结论:
* <1> A 是漂亮数组,则 a * A + b 也是漂亮数组
* <2> A 为奇数漂亮数组,B 为偶数漂亮数组,A + B 为漂亮数组
* <3>数组两两配对,左数组 * 2 - 1 一定是奇数组,右数组 * 2 一定为偶数组,合并一定为漂亮数组
* 假设 [1] 是最小漂亮数组,按照上面规律递推得到的一定是漂亮数组。
* |1|1|1|1|1|1|1|1|
* |1 2|1 2|1 2|1 2|
* |1 3 2 4|1 3 2 4|
* |1 5 3 7 2 6 4 8|
*/
class Solution
{
public:
vector<int> beautifulArray(int n)
{
//递归出口
if (n == 1) return {1};
//递归实现奇数偶数的映射
int odd = (n + 1) / 2, even = n / 2;
vector<int> left = beautifulArray(odd);
vector<int> right = beautifulArray(even);
vector<int> res; //res存储每层"治"后的结果(奇在前偶在后)
//治理的方法取决于是left还是right
//left是奇数映射,right是偶数映射 所以反射需要做相对应的处理
for (auto &c : left) res.push_back(2 * c - 1);
for (auto &c : right) res.push_back(2 * c);
return res;
}
};
通过图中可以看出:我们分治的过程有很多重复的处理,比如上面例子图中第二层和第三层都有对2的分治,这里我们可以利用hash进行减少重复加速处理:
class Solution
{
public:
unordered_map<int, vector<int>> mp;
vector<int> beautifulArray(int n)
{
if (n == 1) return {1};
if (mp.count(n)) return mp[n]; //如果已经处理过n的情况直接利用即可
int odd = (n + 1) / 2, even = n / 2;
vector<int> left = beautifulArray(odd);
vector<int> right = beautifulArray(even);
vector<int> res;
for (auto &c : left) res.push_back(2 * c - 1);
for (auto &c : right) res.push_back(2 * c);
mp[n] = res;
return res;
}
};
涉及知识点:
1.分治法
顾名思义,分治问题由“分”(divide)和“治”(conquer)两部分组成,通过把原问题分为子问题,再将子问题进行处理合并,从而实现对原问题的求解。例如归并排序就是典型的分治问题,其中“分”即为把大数组平均分成两个小数组,通过递归实现,最终我们会得到多个长度为 1 的子数组;“治”即为把已经排好序的两个小数组合成为一个排好序的大数组,从长度为 1 的子数组开始,最终合成一个大数组。