- 正方形数组的数目
给定一个非负整数数组 A,如果该数组每对相邻元素之和是一个完全平方数,则称这一数组为正方形数组。
返回 A 的正方形排列的数目。两个排列 A1 和 A2 不同的充要条件是存在某个索引 i,使得 A1[i] != A2[i]。
示例 1:
输入:[1,17,8]
输出:2
解释:
[1,8,17] 和 [17,8,1] 都是有效的排列。
示例 2:
输入:[2,2,2]
输出:1
提示:
1 <= A.length <= 12
0 <= A[i] <= 1e9
题解
很有趣的题目,首先双重循环,判断哪些数字可以和其他数字挨着,那么全部遍历后,根据连接关系便得到了一个图。接下来就是DFS暴力搜索这个图,使得从某个点开始不断搜索下去,不重复的可以遍历完所有节点。
如果去除重复的排列结果呢?非常有趣:比如从节点1开始,可以到达节点3和节点5,然后发现节点3和节点5的nums都是一样的,那么节点3和节点5的后面的连接关系肯定一样,那么DFS时只需要深度遍历节点3或者节点5即可。于是扼杀了重复的情况。
AC代码
class Solution {
public:
vector<int>to[15];
bool vis[15];
int ans;
void dfs(int dp,int u,vector<int>& nums)
{
if(dp>=nums.size())//说明完整遍历了整个图
{
ans++;
return;
}
map<int,bool>cis;
cis.clear();
for(int i=0;i<to[u].size();i++)
{
int v = to[u][i];
if(vis[v])continue;
if(cis.find(nums[v])==cis.end())//去重复的排列结果
{
cis[nums[v]] = true;
vis[v] = true;
dfs(dp+1,v,nums);
vis[v] = false;
}
}
}
int numSquarefulPerms(vector<int>& nums)
{
for(int i=0;i<nums.size();i++)
{
for(int j=i+1;j<nums.size();j++)
{
int base = nums[i] + nums[j];
int t = sqrt(base);
if(t*t==base)
{
to[i].push_back(j);
to[j].push_back(i);
}
}
}
memset(vis,0,sizeof(vis));
map<int,bool>cis;
ans = 0;
for(int i=0;i<nums.size();i++)
{
if(cis.find(nums[i])==cis.end())
{
cis[nums[i]] = true;
vis[i] = true;
dfs(1,i,nums);
vis[i] = false;
}
}
return ans;
}
};