異なる数のコレクションを指定すると、可能なすべての順列を返します。
たとえば、[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)
再帰的なソリューションの時間の複雑さを理解できません。
誰もが両方の複雑さを説明できますか?
再帰的解法は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
_です。この関係を説明する スターリングの近似 と呼ばれるかなり良い関係があります。
これはoutput(これは大きな問題です)の問題であり、ルーチンの実装ではありません。 n
個の異なるアイテムの場合、答えとして返される_n!
_順列があり、少なくともO(n!)
の複雑さがあります。
_ O(n!) = O(n^(1/2+n)/exp(n)) = O(sqrt(n) * (n/e)^n)
_
any定数c
のO(n!) > O(n^c)
が簡単にわかるので、実装自体が別のO(n^3)
を追加します
_ O(n!) + O(n^3) = O(n!)
_