996. 正方形数组的数目
给定一个非负整数数组
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
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/number-of-squareful-arrays
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
做题结果
成功,还学会了一种有重复元素计算种类的方式 总数/(a!*b!*....*c!),此处a,b,c指代各种数字的个数
方法1:状态压缩
1. 定义每次最后一个选取的位置+已选位置 dp[n][1<<n]
2. 选1个必然可以,dp[i][1<<i]=1
3. 对于某个状态,假设它最后一个选取的x,那在这个基础上可继续选取尚未选取且可与它相连的元素 y,从而扩展1位
4. 最终结果为所有位数最后一位选取的和 sum(dp[i][(1<<n)-1])
5. 由于含有重复元素,结果需要除以所有重复元素阶乘的积
class Solution {
public int numSquarefulPerms(int[] nums) {
Map<Integer,Set<Integer>> graph = new HashMap<>();
int n = nums.length;
for(int i = 0; i < n; i++){
for(int j = 0; j < n; j++){
if(i==j) continue;
if(isConnect(nums[i],nums[j])) graph.computeIfAbsent(i,o->new HashSet<>()).add(j);
}
}
long[][] dp = new long[n][1<<n];//最后一个加入的是谁
for(int i = 0; i < n; i++){
dp[i][1<<i]=1;
}
for(int i = 1; i < (1<<n); i++){
//枚举最后加入的两个元素
for(int j = 0; j < n; j++){
if((i&(1<<j))>0) {
for(Integer k:graph.getorDefault(j,new HashSet<>())){
if((i&(1<<k))==0){
dp[k][i|(1<<k)]+=dp[j][i];
}
}
}
}
}
//去掉重复
Map<Integer,Integer> times = new HashMap<>();
for(int v:nums){
times.put(v,times.getorDefault(v,0)+1);
}
long ans = 0;
for(int i = 0; i < n; i++){
ans += dp[i][(1<<n)-1];
}
for(Integer v:times.values()){
ans = ans/mul(v);
}
return (int) ans;
}
private int mul(int v){
return v==0?1:v*mul(v-1);
}
private boolean isConnect(int a, int b){
int sum = a+b;
int sqrt = (int) Math.sqrt(sum);
return sqrt*sqrt==sum;
}
}
方法2:回溯
上面算组合数什么的很麻烦,那有没有不用算组合数的方式呢?也有
1. 通过数字构建图,而非索引,然后堆数字分类计数
2. 枚举第一个元素,然后DFS逐步枚举后续元素,如果能枚举到最后一个,则增加1种
3. 注意数目为0的元素不能再枚举
4. 需要恢复现场,比如 123,先枚举1,1消耗一个,计算完数目后,需要恢复一个以满足,2开头的消耗
class Solution {
public int numSquarefulPerms(int[] nums) {
Map<Integer,Set<Integer>> graph = new HashMap<>();
Map<Integer,Integer> times = new HashMap<>();
for(int num:nums){
times.put(num,times.getorDefault(num,0)+1);
}
for(int num1:nums){
for(int num2:nums){
if(isConnect(num1,num2)) graph.computeIfAbsent(num1,o->new HashSet<>()).add(num2);
}
}
int ans = 0;
for(int key:graph.keySet()){
times.put(key,times.get(key)-1);
ans += dfs(graph,times,nums.length-1,key);
times.put(key,times.get(key)+1);
}
return ans;
}
private int dfs(Map<Integer,Set<Integer>> graph,Map<Integer,Integer> times,int last,int id){
if(last == 0) return 1;
int ans = 0;
for(Integer item:graph.get(id)){
if(times.get(item)==0) continue;
times.put(item,times.get(item)-1);
ans += dfs(graph,times,last-1,item);
times.put(item,times.get(item)+1);
}
return ans;
}
private boolean isConnect(int a, int b){
int sum = a+b;
int sqrt = (int) Math.sqrt(sum);
return sqrt*sqrt==sum;
}
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。