leetcode------996. 正方形数组的数目,map【1】

本文介绍了一种高效求解正方形数组排列数量的算法。通过将数组元素分类并使用深度优先搜索(DFS)策略,避免了重复计算,大幅提高了算法效率。文章详细解析了算法实现过程,包括元素分类、状态转移矩阵构建及DFS遍历等关键步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 https://leetcode-cn.com/problems/number-of-squareful-arrays/

给定一个非负整数数组 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

下面的这个是非常高效的dfs,是将A中元素先归类(相同元素放在一个篮子里),然后从不同篮子里面取,遇到有很多相同元素的情况,简直牛! 击败了100%代码

class Solution {
    public:
        int n=13;
        map<int,int> mp;
        int dp[13][13];
        int res=0;
        int numSquarefulPerms(vector<int>& A) {
            n=A.size();
            for(int i=0; i<n; i++)
            {
                if(mp.count(A[i])==0)
                    mp[A[i]]=1;
                else
                    mp[A[i]]++;
            }
            map<int,int>::iterator it1,it2;
            for(it1=mp.begin(); it1!=mp.end(); it1++)
            {
                for(it2=it1; it2!=mp.end(); it2++)
                    if(isSquare(it1->first+it2->first))
                    {
                        int k1=distance(mp.begin(),it1);
                        int k2=distance(mp.begin(),it2);
                        //cout<<k1<<" "<<k2<<endl;
                        dp[k1][k2]=1;
                        dp[k2][k1]=1;

                    }

            }
            for(it1=mp.begin(); it1!=mp.end(); it1++)
            {
                mp[it1->first]--;
                dfs(distance(mp.begin(),it1),1);
                mp[it1->first]++;
            }
            return res;
        }
        bool isSquare(int t)
        {
            int s=sqrt(t);
            return s*s==t;
        }
        void dfs(int a,int il)
        {
            if(il==n)
            {
                res++;
                return;
            }
            map<int,int>::iterator it1,it2;
            for(it1=mp.begin(); it1!=mp.end(); it1++)
            {
                int k=distance(mp.begin(),it1);
                if(dp[a][k]&&mp[it1->first]>0)
                {
                    mp[it1->first]--;
                    dfs(k,il+1);
                    mp[it1->first]++;
                }
            }
        }
};

下面是常规代码,对于具有相同元素,超时了

class Solution {
    public:
        int n=13;
        vector< vector<int> > vv;

        bool  vist[13];

        int dp[13][13];
        int res[13];

        int numSquarefulPerms(vector<int>& A) {

            n=A.size();
            for(int i=0; i<n; i++)
            {
                for(int j=0; j<=i; j++)
                    if(isSquare(A[i]+A[j]))
                    {
                        dp[j][i]=1;
                        dp[i][j]=1;
                    } 
            }
            for(int i=0; i<n; i++)
            {
                memset(vist,0,sizeof(vist));
                vist[i]=true;
                res[0]=A[i];
                dfs(1,A);
                vist[i]=false;
            }
            
            return vv.size();
        }
        
        bool isSquare(int t)
        {
            int s=sqrt(t);
            return s*s==t;
        }
        
        void dfs(int il,vector<int>& A)
        {
            
            if(il==n)
            {
                for(int i=0; i<vv.size(); i++)
                {
                    int j;
                    for(j=0; j<n; j++)
                    {
                        if(vv[i][j]==res[j]) continue;
                        else break    ;
                    }
                    if(j==n) return;
                }
                vector<int> r;
                for(int i=0; i<n; i++) r.push_back(res[i]);
                vv.push_back(r);
                return;
            }
            for(int i=0; i<n; i++)
            {
                if(vist[i]==false&&dp[il][i])
                {
                    vist[i]=true;
                    res[il]=A[i];
                    dfs(il+1,A);
                    vist[i]=false;
                }
            }
        }
};

其实关键是常规算法需要排除重复的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值