【LeetCode 996】Offer 驾到,掘友接招!我正在参与2022春招系列活动-刷题打卡任务

238 阅读1分钟

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;
    }
};

四、总结

一开始没有仔细考虑清楚边界的特殊情况,做题心思得再缜密些。