Geração de Permutações Únicas com Números Repetidos em Go

Dado um array de números inteiors nums que pode conter elementos duplicados, retorne todas as permutações únicas possíveis em qualquer ordem.

Exemplo:
Entrada: nums = [1,1,2]
Saída: [[1,1,2], [1,2,1], [2,1,1]]

Análise do Algoritmo:
Para tratar duplicatas, o array deve ser ordenado primeiro para agrupar elementos iguais. Utiliza-se backtracking para explorar todas as permutações, e um mapa (ou slice) para rastrear índices usados, evitando repetições no mesmo nível da árvore de recursão. A condição de poda verifica se um elemento igual já foi considerado no mesmo nível, garantindo permutações únicas.

Implementação em Go (versão otiimzada):


func generateUniquePerms(nums []int) [][]int {
    var results [][]int
    var current []int
    length := len(nums)
    if length == 0 {
        return results
    }
    sort.Ints(nums) // Ordenação necessária para detecção de duplicatas
    used := make([]bool, length)
    var backtrack func(int)
    backtrack = func(idx int) {
        if idx == length {
            tmp := make([]int, length)
            copy(tmp, current)
            results = append(results, tmp)
            return
        }
        for i := 0; i < length; i++ {
            if i > 0 && nums[i] == nums[i-1] && !used[i-1] {
                continue // Poda: evita duplicatas no mesmo nível
            }
            if used[i] {
                continue // Elemento já utilizado no caminho atual
            }
            used[i] = true
            current = append(current, nums[i])
            backtrack(idx + 1)
            current = current[:len(current)-1]
            used[i] = false
        }
    }
    backtrack(0)
    return results
}

Implementação Alternativa com Função Separada:


func findUniquePermutations(nums []int) [][]int {
    var result [][]int
    var path []int
    used := make([]bool, len(nums))
    sort.Ints(nums)
    var dfs func()
    dfs = func() {
        if len(path) == len(nums) {
            tmp := make([]int, len(path))
            copy(tmp, path)
            result = append(result, tmp)
            return
        }
        for i := 0; i < len(nums); i++ {
            if i > 0 && nums[i] == nums[i-1] && !used[i-1] {
                continue // Pula elementos duplicados no mesmo nível
            }
            if used[i] {
                continue
            }
            used[i] = true
            path = append(path, nums[i])
            dfs()
            path = path[:len(path)-1]
            used[i] = false
        }
    }
    dfs()
    return result
}

Em ambas as implementações, a ordenação do array e o uso de um slice de booleanos used são cruciais para evitar permutações duplicadas. A poda com base em used[i-1] identifica se o elemento anterior foi desmarcado após backtracking, garantindo que apenas permutações únicas sejam geradas.

Tags: go permutações backtracking Algoritmos LeetCode

Publicado em 7-2 20:36