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