Given an array A of non-negative integers, the array is squareful if for every pair of adjacent elements, their sum is a perfect square.
Return the number of permutations of A that are squareful. Two permutations A1 and A2 differ if and only if there is some index i such that A1[i] != A2[i].
Example 1:
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
Solved this with PHP.
- Go through the input and construct array ‘peers’
- peers holds an array of pointers pointing to all possible ‘partners’ in the input.
- For example,
[1 => [8=>ref(8)], 8 => [1=>ref(1), 17=>ref(17)], 17 => [8=>ref(8)]]
- Meanwhile, another array stat collect all numbers and its occurrence.
- Then peers is recursive. so it’s like a tree, with infinite depth.
- Starting from the root of peers, if found any number in ‘stat’, update (-1) stat, and move on to peers’ children
- if cannot find any match at some points, break;
- since stat is finite, the recursive func will run forever
- Calculate the sum.
Works well with even larger input length.
16ms runtime w/ 14.7M RAM
Class Solution { /** * @param Integer[] $ls * @return Integer */ function numSquarefulPerms($ls) { if(count($ls) <= 1){ return 0; } $peers = []; $stat = []; for($i = 0; $i < count($ls); $i++){ // Insert/Update stat if(!isset($stat[$ls[$i]])){ $stat[$ls[$i]] = 1; } else { $stat[$ls[$i]] ++; } for($j = $i + 1; $j < count($ls); $j++){ $value_i = $ls[$i]; $value_j = $ls[$j]; if(!isset($peers[$value_i])){ $peers[$value_i] = []; } if(!isset($peers[$value_j])){ $peers[$value_j] = []; } if($this -> isPerfectSquare($ls[$i] + $ls[$j])){ $peers[$value_i][$value_j] = &$peers[$value_j]; if($ls[$j] !== $ls[$i]){ $peers[$value_j][$value_i] = &$peers[$value_i]; } } } } // If any number has no partner foreach($peers as $p){ if($p === []){ return 0; } } return $this->traversal($stat, $peers, count($ls)); } // Check if number is perfect square w/ small optimization function isPerfectSquare($num){ $last_digit = $num % 10; if($last_digit == 2 || $last_digit == 3 || $last_digit == 7 || $last_digit == 8 ) return false; $sqrt = sqrt($num); return $sqrt == floor($sqrt); } function traversal($nums, &$tree, $max){ $count = 0; var_dump($nums); if(empty($nums)){ echo "Add\r\n"; return 1; } foreach($tree as $k => $v){ // Make a copy $nums_copy = $nums; if(isset($nums_copy[$k])){ // If exist decrease, if last remove if($nums[$k] > 1){ $nums_copy[$k] --; } else { unset($nums_copy[$k]); } // move on to children $count += $this -> traversal($nums_copy, $v, $max - 1); } } return $count; } }