996. Number of Squareful Arrays

Task text is translated from Russian for the selected interface language. Code is left unchanged.

Complexity: hard

array является квадратным, если сумма каждой пары соседних elementов является совершенным квадратом. Если задан integer array nums, return количество перестановок nums, которые являются квадратными. Две перестановки perm1 и perm2 различны, если существует некоторый индекс i такой, что perm1[i] != perm2[i].

Example:

Input: nums = [1,17,8]

Output: 2

C# solution

matched/original
public class Solution {
    public int NumSquarefulPerms(int[] nums) {
        Array.Sort(nums);
        var used = new bool[nums.Length];
        var result = new HashSet<string>();
        var path = new List<int>();
        Backtrack(nums, used, path, result);
        return result.Count;
    }
    
    private void Backtrack(int[] nums, bool[] used, List<int> path, HashSet<string> result) {
        if (path.Count == nums.Length) {
            if (IsSquareful(path)) {
                result.Add(string.Join(",", path));
            }
            return;
        }
        
        for (int i = 0; i < nums.Length; i++) {
            if (used[i] || (i > 0 && nums[i] == nums[i - 1] && !used[i - 1])) continue;
            path.Add(nums[i]);
            used[i] = true;
            Backtrack(nums, used, path, result);
            path.RemoveAt(path.Count - 1);
            used[i] = false;
        }
    }
    
    private bool IsSquareful(List<int> perm) {
        for (int i = 0; i < perm.Count - 1; i++) {
            int sum = perm[i] + perm[i + 1];
            int root = (int)Math.Sqrt(sum);
            if (root * root != sum) return false;
        }
        return true;
    }
}

C++ solution

auto-draft, review before submit
#include <bits/stdc++.h>
using namespace std;

// Auto-generated C++ draft from the C# solution. Review containers, LINQ and helper types before submit.
class Solution {
public:
    public int NumSquarefulPerms(vector<int>& nums) {
        sort(nums.begin(), nums.end());
        var used = new bool[nums.size()];
        var result = new HashSet<string>();
        var path = new List<int>();
        Backtrack(nums, used, path, result);
        return result.size();
    }
    
    private void Backtrack(vector<int>& nums, bool[] used, List<int> path, HashSet<string> result) {
        if (path.size() == nums.size()) {
            if (IsSquareful(path)) {
                result.push_back(string.Join(",", path));
            }
            return;
        }
        
        for (int i = 0; i < nums.size(); i++) {
            if (used[i] || (i > 0 && nums[i] == nums[i - 1] && !used[i - 1])) continue;
            path.push_back(nums[i]);
            used[i] = true;
            Backtrack(nums, used, path, result);
            path.RemoveAt(path.size() - 1);
            used[i] = false;
        }
    }
    
    private bool IsSquareful(List<int> perm) {
        for (int i = 0; i < perm.size() - 1; i++) {
            int sum = perm[i] + perm[i + 1];
            int root = (int)Math.Sqrt(sum);
            if (root * root != sum) return false;
        }
        return true;
    }
}

Java solution

auto-draft, review before submit
import java.util.*;
import java.math.*;

// Auto-generated Java draft from the C# solution. Review API differences before LeetCode submit.
public class Solution {
    public int NumSquarefulPerms(int[] nums) {
        Arrays.sort(nums);
        var used = new boolean[nums.length];
        var result = new HashSet<String>();
        var path = new List<int>();
        Backtrack(nums, used, path, result);
        return result.size();
    }
    
    private void Backtrack(int[] nums, boolean[] used, List<int> path, HashSet<String> result) {
        if (path.size() == nums.length) {
            if (IsSquareful(path)) {
                result.add(String.Join(",", path));
            }
            return;
        }
        
        for (int i = 0; i < nums.length; i++) {
            if (used[i] || (i > 0 && nums[i] == nums[i - 1] && !used[i - 1])) continue;
            path.add(nums[i]);
            used[i] = true;
            Backtrack(nums, used, path, result);
            path.RemoveAt(path.size() - 1);
            used[i] = false;
        }
    }
    
    private boolean IsSquareful(List<int> perm) {
        for (int i = 0; i < perm.size() - 1; i++) {
            int sum = perm[i] + perm[i + 1];
            int root = (int)Math.Sqrt(sum);
            if (root * root != sum) return false;
        }
        return true;
    }
}

JavaScript solution

matched/original
class Solution {
    numSquarefulPerms(nums) {
        nums.sort((a, b) => a - b);
        const used = new Array(nums.length).fill(false);
        const result = new Set();
        const path = [];
        this.backtrack(nums, used, path, result);
        return result.size;
    }
    
    backtrack(nums, used, path, result) {
        if (path.length === nums.length) {
            if (this.isSquareful(path)) {
                result.add(path.join(','));
            }
            return;
        }
        
        for (let i = 0; i < nums.length; i++) {
            if (used[i] || (i > 0 && nums[i] === nums[i - 1] && !used[i - 1])) continue;
            path.push(nums[i]);
            used[i] = true;
            this.backtrack(nums, used, path, result);
            path.pop();
            used[i] = false;
        }
    }
    
    isSquareful(perm) {
        for (let i = 0; i < perm.length - 1; i++) {
            const sum = perm[i] + perm[i + 1];
            const root = Math.sqrt(sum);
            if (root * root !== sum) return false;
        }
        return true;
    }
}

Python solution

matched/original
from itertools import permutations
import math

class Solution:
    def numSquarefulPerms(self, nums: List[int]) -> int:
        def isPerfectSquare(x):
            return int(math.isqrt(x)) ** 2 == x
        
        def isSquareful(perm):
            for i in range(len(perm) - 1):
                if not isPerfectSquare(perm[i] + perm[i + 1]):
                    return False
            return True
        
        perms = set(permutations(nums))
        count = sum(1 for perm in perms if isSquareful(perm))
        return count

Go solution

matched/original
import (
    "math"
    "sort"
)

func numSquarefulPerms(nums []int) int {
    sort.Ints(nums)
    used := make([]bool, len(nums))
    result := make(map[string]bool)
    path := []int{}
    backtrack(nums, used, path, result)
    return len(result)
}

func backtrack(nums []int, used []bool, path []int, result map[string]bool) {
    if len(path) == len(nums) {
        if isSquareful(path) {
            key := makeKey(path)
            result[key] = true
        }
        return
    }
    
    for i := 0; i < len(nums); i++ {
        if used[i] || (i > 0 && nums[i] == nums[i-1] && !used[i-1]) {
            continue
        }
        path = append(path, nums[i])
        used[i] = true
        backtrack(nums, used, path, result)
        path = path[:len(path)-1]
        used[i] = false
    }
}

func isSquareful(perm []int) bool {
    for i := 0; i < len(perm)-1; i++ {
        sum := perm[i] + perm[i+1]
        root := int(math.Sqrt(float64(sum)))
        if root*root != sum {
            return false
        }
    }
    return true
}

func makeKey(path []int) string {
    key := ""
    for _, num := range path {
        key += string(num) + ","
    }
    return key
}

Algorithm

1⃣Генерация перестановок:

Сгенерируйте все возможные перестановки arrayа nums.

Для каждой перестановки проверьте, является ли она квадратной.

2⃣Проверка квадратности:

Для каждой перестановки проверьте, является ли сумма каждой пары соседних elementов совершенным квадратом.

Для этого используйте функцию для проверки, является ли number совершенным квадратом.

3⃣Подсчет квадратных перестановок:

Подсчитайте количество перестановок, которые являются квадратными, и return это значение.

😎

Vacancies for this task

Active vacancies with overlapping task tags are shown.

All vacancies
There are no active vacancies yet.