一連の数値のすべての部分集合を見つけるための以下のコードの複雑さは何ですか?再帰的および末尾再帰的コードの実行時および領域の複雑さ
public List<List<Integer>> subsets(int[] nums) {
List<List<Integer>> subsets = new ArrayList<>();
subsets.add(new ArrayList<Integer>());
return find(subsets, nums, 0);
}
private List<List<Integer>> find(List<List<Integer>> subsets, int[] nums, int index) {
if (index == nums.length) {
return subsets;
}
List<List<Integer>> newSubsets = new ArrayList<>();
for (List<Integer> subset: subsets) {
List<Integer> newSubset = new ArrayList<>();
newSubset.addAll(subset);
newSubset.add(nums[index]);
newSubsets.add(newSubset);
}
subsets.addAll(newSubsets);
return find(subsets, nums, index + 1);
}
ことがあるサブセットの数だと、あなたが返されるリストにそれぞれ1を追加する必要がありますように、O(2^nums.length)
ですか?また、以下のバージョンが漸近的にまだO(2^set.size())
であると考えているのですが、一般的な再帰によって寄与する空間の複雑さはO(set.size())
ですが、上記のテール再帰的コードではO(1)
ですか?
public static ArrayList<ArrayList<Integer>> getSubsets(ArrayList<Integer> set) {
ArrayList<ArrayList<Integer>> subsets = new ArrayList<>();
getSubsets(set, subsets, 0);
return subsets;
}
private static void getSubsets(ArrayList<Integer> set, ArrayList<ArrayList<Integer>> subsets, int index) {
if (index == set.size()) {
subsets.add(new ArrayList<Integer>());
return;
}
getSubsets(set, subsets, index + 1);
int item = set.get(index);
ArrayList<ArrayList<Integer>> moreSubsets = new ArrayList<>();
for (ArrayList<Integer> subset: subsets) {
ArrayList<Integer> newSubset = new ArrayList<>();
newSubset.addAll(subset);
newSubset.add(item);
moreSubsets.add(newSubset);
}
subsets.addAll(moreSubsets);
}
Javaは末尾呼び出しの削除を行いません。 – user2357112
...しかし、あなたは反復を反復に変換することから唯一のステップです。それは少し速く実行されますが、メソッド呼び出しの不足であまりにも多くのメモリを節約しません。 2回の反復の後、サブセットはスタックフレームよりもはるかに多くのメモリを割り当てます。 – Selindek