web-dev-qa-db-fra.com

Complexité temporelle de la fonction de permutation

Étant donné une collection de nombres distincts, renvoyez toutes les permutations possibles.

Par exemple, [1,2,3] ont les permutations suivantes:
[[1,2,3], [1,3,2], [2,1,3], [2,3,1], [3,1,2], [3,2 ,1] ]

Ma solution itérative est:

public List<List<Integer>> permute(int[] nums) {
        List<List<Integer>> result = new ArrayList<>();
        result.add(new ArrayList<>());
        for(int i=0;i<nums.length;i++)
        {
            List<List<Integer>> temp = new ArrayList<>();
            for(List<Integer> a: result)
            {
                for(int j=0; j<=a.size();j++)
                {
                    a.add(j,nums[i]);
                    List<Integer> current = new ArrayList<>(a);
                    temp.add(current);
                    a.remove(j);
                }
            }
            result = new ArrayList<>(temp);
        }
        return result;
    }

Ma solution récursive est:

public List<List<Integer>> permuteRec(int[] nums) {
        List<List<Integer>> result = new ArrayList<List<Integer>>();
        if (nums == null || nums.length == 0) {
            return result;
        }
        makePermutations(nums, result, 0);
        return result;
    }


void makePermutations(int[] nums, List<List<Integer>> result, int start) {
    if (start >= nums.length) {
        List<Integer> temp = convertArrayToList(nums);
        result.add(temp);
    }
    for (int i = start; i < nums.length; i++) {
        swap(nums, start, i);
        makePermutations(nums, result, start + 1);
        swap(nums, start, i);
    }
}

private ArrayList<Integer> convertArrayToList(int[] num) {
        ArrayList<Integer> item = new ArrayList<Integer>();
        for (int h = 0; h < num.length; h++) {
            item.add(num[h]);
        }
        return item;
    }

Selon moi, la complexité temporelle (big-Oh) de ma solution itérative est: n * n (n + 1)/2 ~ O (n ^ 3)
Je ne suis pas en mesure de comprendre la complexité temporelle de ma solution récursive.
Quelqu'un peut-il expliquer la complexité des deux?

13
ojas

La solution récursive a une complexité de O(n!) car elle est régie par l'équation: T(n) = n * T(n-1) + O(1).

La solution itérative a trois boucles imbriquées et a donc une complexité de O(n^3).

Cependant, la solution itérative ne produira pas de permutations correctes pour un nombre autre que 3.

Pour n = 3, Vous pouvez voir que n * (n - 1) * (n-2) = n!. Le LHS est O(n^3) (ou plutôt O(n^n) puisque n=3 Ici) et le RHS est O(n!).

Pour des valeurs plus grandes de la taille de la liste, disons n, vous pourriez avoir n boucles imbriquées et qui fourniront des permutations valides. La complexité dans ce cas sera O(n^n), et qui est beaucoup plus grande que O(n!), ou plutôt, n! < n^n. Il existe une relation plutôt agréable appelée approximation de Stirling qui explique cette relation.

9
user1952500

C'est la sortie (qui est énorme) qui compte dans ce problème, pas l'implémentation de la routine. Pour n éléments distincts, il y a n! Permutations à renvoyer comme réponse, et donc nous avons au moins O(n!) complexité.

Avec l'aide de approximation de Stirling

 O(n!) = O(n^(1/2+n)/exp(n)) = O(sqrt(n) * (n/e)^n)

nous pouvons facilement voir que O(n!) > O(n^c) pour toute constante c, c'est pourquoi peu importe si le l'implémentation elle-même ajoute un autre O(n^3) puisque

 O(n!) + O(n^3) = O(n!)
3
Dmitry Bychenko