Problem#  An array is squareful  if the sum of every pair of adjacent elements is a
perfect square .
Given an integer array nums, return the number of permutations of nums
that aresquareful  .
Two permutations perm1 and perm2 are different if there is some index i
such that perm1[i] != perm2[i].
Examples#  Example 1#  1
 2
 3
 Input: nums =  [ 1 , 17 , 8 ] 
 Output: 2 
 Explanation: [ 1 , 8 , 17 ]  and [ 17 , 8 , 1 ]  are the valid permutations. 
 
Example 2#  1
 2
 Input: nums =  [ 2 , 2 , 2 ] 
 Output: 1 
 
Constraints#  1 <= nums.length <= 120 <= nums[i] <= 10^9Solution#  Method 1 – Backtracking with Pruning#  Intuition#  We need to count all unique permutations of the array where every adjacent pair sums to a perfect square. Since the array can have duplicates, we must avoid counting duplicate permutations. We use backtracking to generate all valid permutations, skipping duplicates and pruning paths early if the current pair does not sum to a perfect square.
Approach#  Sort the array to handle duplicates easily. Use a backtracking function that tries to build the permutation step by step:Keep a used array to track which elements are already in the current permutation. For each unused element, if it is the same as the previous and the previous was not used, skip it (to avoid duplicates). If the current element can be appended (either it’s the first, or the sum with the previous is a perfect square), proceed. If the permutation is complete, increment the answer.  Use a helper function to check if a number is a perfect square. Return the total count. Code#  
Cpp
 
Go
 
Java
 
Kotlin
 
Python
 
Rust
 
Typescript 
 1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 #include  <vector> 
 #include  <algorithm> 
 #include  <cmath> 
 using  namespace  std;
class  Solution  {
public : 
    int  numSquarefulPerms(vector< int >&  nums) {
         sort(nums.begin(), nums.end());
         int  n =  nums.size(), ans =  0 ;
         vector< bool >  used(n, false);
         function< void (vector< int >& , int )>  dfs =  [& ](vector< int >&  path, int  depth) {
             if  (depth ==  n) { ++ ans; return ; }
             for  (int  i =  0 ; i <  n; ++ i) {
                 if  (used[i] ||  (i >  0  &&  nums[i] ==  nums[i- 1 ] &&  ! used[i- 1 ])) continue ;
                 if  (depth ==  0  ||  isSquare(path.back() +  nums[i])) {
                     used[i] =  true;
                     path.push_back(nums[i]);
                     dfs(path, depth+ 1 );
                     path.pop_back();
                     used[i] =  false;
                 }
             }
         };
         auto  isSquare =  [](int  x) {
             int  r =  sqrt(x);
             return  r* r ==  x;
         };
         vector< int >  path;
         dfs(path, 0 );
         return  ans;
     }
 }; 
 1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 import  (
    "sort" 
     "math" 
 )
 func  numSquarefulPerms (nums  []int ) int  {
    sort .Ints (nums )
     n , ans  :=  len(nums ), 0 
     used  :=  make([]bool , n )
     var  isSquare  = func (x  int ) bool  {
         r  :=  int(math .Sqrt (float64(x )))
         return  r * r  ==  x 
     }
     var  dfs  func (path  []int , depth  int )
     dfs  = func (path  []int , depth  int ) {
         if  depth  ==  n  {
             ans ++ 
             return 
         }
         for  i  :=  0 ; i  < n ; i ++  {
             if  used [i ] ||  (i  > 0  &&  nums [i ] ==  nums [i - 1 ] &&  !used [i - 1 ]) {
                 continue 
             }
             if  depth  ==  0  ||  isSquare (path [len(path )- 1 ]+ nums [i ]) {
                 used [i ] = true 
                 dfs (append(path , nums [i ]), depth + 1 )
                 used [i ] = false 
             }
         }
     }
     dfs ([]int {}, 0 )
     return  ans 
 } 
 1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 import  java.util.*;
class  Solution  {
    public  int  numSquarefulPerms (int []  nums) {
         Arrays.sort (nums);
         int  n =  nums.length , ans[]  =  new  int [ 1] ;
         boolean []  used =  new  boolean [ n] ;
         backtrack(nums, new  ArrayList<> (), used, ans);
         return  ans[ 0] ;
     }
     void  backtrack (int []  nums, List< Integer>  path, boolean []  used, int []  ans) {
         if  (path.size () ==  nums.length ) { ans[ 0]++ ; return ; }
         for  (int  i =  0; i <  nums.length ; ++ i) {
             if  (used[ i]  ||  (i >  0 &&  nums[ i]  ==  nums[ i- 1]  &&  ! used[ i- 1] )) continue ;
             if  (path.isEmpty () ||  isSquare(path.get (path.size ()- 1) +  nums[ i] )) {
                 used[ i]  =  true ;
                 path.add (nums[ i] );
                 backtrack(nums, path, used, ans);
                 path.remove (path.size ()- 1);
                 used[ i]  =  false ;
             }
         }
     }
     boolean  isSquare (int  x) {
         int  r =  (int )Math.sqrt (x);
         return  r* r ==  x;
     }
 } 
 1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 class  Solution  {
    fun  numSquarefulPerms (nums: IntArray): Int {
         nums.sort()
         val  n = nums.size
         var  ans = 0 
         val  used = BooleanArray(n)
         fun  isSquare (x: Int) = kotlin.math.sqrt(x.toDouble()).toInt().let { it *it  ==  x }
         fun  dfs (path: MutableList<Int>, depth: Int) {
             if  (depth ==  n) { ans++ ; return  }
             for  (i in  0  until n) {
                 if  (used[i] ||  (i > 0  &&  nums[i] ==  nums[i-1 ] &&  !used[i-1 ])) continue 
                 if  (depth ==  0  ||  isSquare(path.last() + nums[i])) {
                     used[i] = true 
                     path.add(nums[i])
                     dfs(path, depth+1 )
                     path.removeAt(path.size-1 )
                     used[i] = false 
                 }
             }
         }
         dfs(mutableListOf(), 0 )
         return  ans
     }
 } 
 1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 class  Solution :
    def  numSquarefulPerms (self, nums: list[int]) ->  int:
         from  math import  isqrt
         nums. sort()
         n =  len(nums)
         used =  [False ]* n
         ans =  0 
         def  is_square (x):
             r =  isqrt(x)
             return  r* r ==  x
         def  dfs (path, depth):
             nonlocal  ans
             if  depth ==  n:
                 ans +=  1 
                 return 
             for  i in  range(n):
                 if  used[i] or  (i >  0  and  nums[i] ==  nums[i- 1 ] and  not  used[i- 1 ]):
                     continue 
                 if  depth ==  0  or  is_square(path[- 1 ] +  nums[i]):
                     used[i] =  True 
                     dfs(path +  [nums[i]], depth+ 1 )
                     used[i] =  False 
         dfs([], 0 )
         return  ans 
 1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 impl  Solution {
    pub  fn  num_squareful_perms (mut  nums: Vec< i32 > ) -> i32  {
         fn  is_square (x: i32 ) -> bool  {
             let  r =  (x as  f64 ).sqrt() as  i32 ;
             r* r ==  x
         }
         fn  dfs (nums: & Vec< i32 > , used: & mut  Vec< bool > , path: & mut  Vec< i32 > , ans: & mut  i32 ) {
             let  n =  nums.len();
             if  path.len() ==  n {
                 * ans +=  1 ;
                 return ;
             }
             for  i in  0 .. n {
                 if  used[i] ||  (i >  0  &&  nums[i] ==  nums[i- 1 ] &&  ! used[i- 1 ]) { continue ; }
                 if  path.is_empty() ||  is_square(path[path.len()- 1 ] +  nums[i]) {
                     used[i] =  true ;
                     path.push(nums[i]);
                     dfs(nums, used, path, ans);
                     path.pop();
                     used[i] =  false ;
                 }
             }
         }
         nums.sort();
         let  n =  nums.len();
         let  mut  used =  vec! [false ; n];
         let  mut  path =  vec! [];
         let  mut  ans =  0 ;
         dfs(& nums, & mut  used, & mut  path, & mut  ans);
         ans
     }
 } 
 1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 class  Solution  {
    numSquarefulPerms (nums : number []):  number  {
         nums .sort ((a ,b )=> a - b );
         const  n  =  nums .length ;
         let  ans  =  0 ;
         const  used  =  Array(n ).fill (false );
         function  isSquare (x : number ):  boolean  {
             const  r  =  Math.floor (Math.sqrt (x ));
             return  r * r  ===  x ;
         }
         function  dfs (path : number [], depth : number ) {
             if  (depth  ===  n ) { ans ++ ; return ; }
             for  (let  i  =  0 ; i  <  n ; ++ i ) {
                 if  (used [i ] ||  (i  >  0  &&  nums [i ] ===  nums [i - 1 ] &&  ! used [i - 1 ])) continue ;
                 if  (depth  ===  0  ||  isSquare (path [path .length - 1 ] +  nums [i ])) {
                     used [i ] =  true ;
                     dfs ([...path , nums [i ]], depth + 1 );
                     used [i ] =  false ;
                 }
             }
         }
         dfs ([], 0 );
         return  ans ;
     }
 } 
Complexity#  ⏰ Time complexity: O(n! * n), where n is the length of nums. We try all permutations, pruning invalid ones early. The actual number is less due to pruning and duplicate skipping. 🧺 Space complexity: O(n), for recursion stack and auxiliary arrays.