web-dev-qa-db-ja.com

順列関数の時間の複雑さ

異なる数のコレクションを指定すると、可能なすべての順列を返します。

たとえば、[1,2,3]には次の順列があります。
[[1,2,3]、[1,3,2]、[2,1,3]、[2,3,1]、[3,1,2]、[3,2 、1]]

私の反復的な解決策は:

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

私の再帰的な解決策は:

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

私によると、私の反復解の時間の複雑さ(big-Oh)は次のとおりです:n * n(n + 1)/ 2〜O(n ^ 3)
再帰的なソリューションの時間の複雑さを理解できません。
誰もが両方の複雑さを説明できますか?

13
ojas

再帰的解法はO(n!)の方程式によって制御されるため、T(n) = n * T(n-1) + O(1)の複雑さがあります。

反復ソリューションには3つのネストされたループがあるため、O(n^3)の複雑さがあります。

ただし、反復ソリューションでは、_3_以外の数の正しい順列は生成されません。

_n = 3_の場合、n * (n - 1) * (n-2) = n!が表示されます。 LHSはO(n^3)(または_n=3_なのでO(n^n))で、RHSはO(n!)です。

リストのサイズの値が大きい場合、たとえばnの場合、nネストされたループがあり、有効な順列が提供されます。その場合の複雑さはO(n^n)であり、O(n!)よりもはるかに大きい、または_n! < n^n_です。この関係を説明する スターリングの近似 と呼ばれるかなり良い関係があります。

9
user1952500

これはoutput(これは大きな問題です)の問題であり、ルーチンの実装ではありません。 n個の異なるアイテムの場合、答えとして返される_n!_順列があり、少なくともO(n!)の複雑さがあります。

スターリングの近似の助けを借りて

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

any定数cO(n!) > O(n^c)が簡単にわかるので、実装自体が別のO(n^3)を追加します

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