996. Number of Squareful Arrays

问题:

给定一组数,将其排列

使得相邻两个数的和,正好是一个可被平方的数。

求所有的排列可能个数。

Example 1:
Input: [1,17,8]
Output: 2
Explanation: 
[1,8,17] and [17,8,1] are the valid permutations.

Example 2:
Input: [2,2,2]
Output: 1

Note:
1 <= A.length <= 12
0 <= A[i] <= 1e9

  

解法:Backtracking(回溯算法)

  • 状态:到目前为止,排列好的数列。(余下几个数left,当前选择的数x)
  • 选择:以当前选择的数 为标准,下一个能与他之和满足条件,成为平方数的,所有可能数。
    • ⚠️  注意:若数列中存在重复的数字,那么当前为止该数字只能选择一次,作为一个排列。
  • 递归退出条件:
    • left==0,所有数用完,找到一个满足条件的解,res++,return
    • 尝试完所有可能,未找到,return

 

对于本问题:

  • 求排列:避免重复元素->使用set:count对不同元素,进行计数。
    • 每次递归,用掉一个数,count[x]--
    • 递归结束,恢复count[x]++

 

  • 构造每个元素,下一个可选的所有数:使用map:opt:
    • key=当前元素x,value={ 可选元素1,可选元素2...... } y
    • 这些可选元素满足:sqrt(x+y)^2 = x+y

 

♻️  💗  技巧:递归函数 debug方法:printf

  • 定义:
    • 缩紧记录变量 int countI
    • printIndent(int n)函数,打印缩紧
  • 打印位置:
    • 递归入口:printIndent(n++) -> 打印参数 + "\n"
    • 递归出口:printIndent(n--) -> 打印返回值 return res + "\n"
      • ⚠️  注意:这里,是在每一个return之前都打印

INPUT:

[1,17,8]

OUTPUT:

2

打印效果:STDOUT:

x:8
 x:1
  return:0
 x:17
  return:0
 return:0
x:17
 x:8
  x:1
   return 1 (res add)
  return:1
 return:1
x:1
 x:8
  x:17
   return 2 (res add)
  return:2
 return:2

  

 

 

代码参考:

 1 class Solution {
 2 public:
 3     // ** DEBUG method of Recursion
 4    // int countI=0;
 5    // void printIndent(int n) {
 6    //     for(int i=0;i<n;i++)
 7    //         printf(" ");
 8    // }
 9     void dfs(int& res, 
10              unordered_map<int, unordered_set<int>>& opt, unordered_map<int, int>& count, 
11              int left, int x) {
12     //    printIndent(countI++);
13     //    printf("x:%d\n", x);
14         if(left==0) {
15             res++;
16       //      printIndent(countI--);
17       //      printf("return %d (res add)\n",res);
18             return;
19         }
20         count[x]--;
21         for(int op:opt[x]) {
22             if(count[op]>0) {
23                 dfs(res, opt, count, left-1, op);
24             }
25         }
26         count[x]++;
27         //printIndent(countI--);
28         //printf("return:%d\n", res);
29         return;
30     }
31     int numSquarefulPerms(vector<int>& A) {
32         int res=0;
33         unordered_map<int, unordered_set<int>>opt;
34         unordered_map<int, int>count;
35         
36         for(int& a:A){
37             count[a]++;
38         }
39         //create opt list
40         for(auto &a:count) {
41             for(auto &b:count) {
42                 int x = a.first, y = b.first;
43                 int s = sqrt(x+y);
44                 if(s*s==x+y) {
45                     opt[x].insert(y);
46                 }
47             }
48         }
49         for(auto &a:count) {
50             dfs(res, opt, count, A.size()-1, a.first);
51         }
52         
53         return res;
54     }
55 };

 

posted @ 2021-01-29 16:28  habibah_chang  阅读(66)  评论(0编辑  收藏  举报