Offer 驾到,掘友接招!我正在参与2022春招系列活动-刷题打卡任务活动详情
一、题目描述
给定一个数组,求其有多少排列,满足任意两个相邻元素之和是一个完全平方数。
数据范围
n <= 12
二、思路分析
由于数据很小,我们第一时间想到了暴搜,再加上一点点剪枝。
剪枝方式:如果当前相邻的两个元素之和不满足是一个完全平方数,则不继续做了。
去重:判断两个排列不同是它们要有一个不同的元素,题目中的数有可能是重复的,故我们需要去重。其实很快,统计一下相同的数字出现了几次,把最后的结果除一下重复出现的排列即可。
但是有一个小bug,如果重复出现的数字很多,剪枝就会失效。但是这种情况很少,只有当出现所有数字都相同时才会达到这个超时的极限,所以我们特判一下就好了。
三、AC代码
class Solution {
public:
int pd[20];
int a[20];
int n,count;
map<int,int> mp;
map<int,int>::iterator iter;
int jiecheng(int x) {
int ans=1;
while (x) {
ans*=x;
x--;
}
return ans;
}
bool js(long long x, long long y) {
if ((int)sqrt(x+y)*sqrt(x+y) == x + y) {
return true;
}
return false;
}
void dfs(int t, vector<int>& nums){
if (t == n) {
count++;
} else {
for (int i=0; i<n; i++) {
if (pd[i]==0 && (t==0 || js(a[t-1], nums[i]))) {
a[t] = nums[i];
pd[i]=1;
dfs(t+1,nums);
pd[i]=0;
}
}
}
return;
}
int numSquarefulPerms(vector<int>& nums) {
n = nums.size();
for (int i=0; i<n; i++) mp[nums[i]]++;
if (mp.begin()->second == n) {
if (js(nums[0],nums[0])) return 1;
else return 0;
}
dfs(0,nums);
for (iter = mp.begin(); iter!=mp.end(); iter++) {
count /= jiecheng(iter->second);
}
return count;
}
};
四、总结
一开始没有仔细考虑清楚边界的特殊情况,做题心思得再缜密些。