Mendapatkan sekumpulan kekuatan di Jawa

86

Kekuatan dari {1, 2, 3}adalah:

{{}, {2}, {3}, {2, 3}, {1, 2}, {1, 3}, {1, 2, 3}, {1}}

Katakanlah saya punya Setdi Java:

Set<Integer> mySet = new HashSet<Integer>();
mySet.add(1);
mySet.add(2);
mySet.add(3);
Set<Set<Integer>> powerSet = getPowerset(mySet);

Bagaimana cara menulis fungsi getPowerset, dengan urutan kerumitan terbaik? (Saya pikir itu mungkin O (2 ^ n).)

Manuel Araoz
sumber
7
Misalkan Anda memiliki satu set konfigurasi - katakanlah "A", "B" dan "C" -, yang dapat digunakan untuk membuat parameter model, dan Anda ingin melihat subset mana yang memberikan hasil terbaik - misalnya hanya "A ". Solusi yang mungkin adalah menguji setiap anggota set kekuatan.
João Silva
7
Ini pertanyaan wawancara Google untuk pengembang perangkat lunak. Ini adalah masalah yang dibuat-buat untuk menguji ketangkasan pikiran Anda.
Eric Leschinski
Ini pertanyaan yang masuk akal. Misalnya untuk mengimplementasikan fungsi penilaian untuk cribbage, Anda harus menguji apakah ada elemen dari PowerSet yang berjumlah 15.
John Henckel

Jawaban:

101

Ya, O(2^n)memang, karena Anda perlu menghasilkan, yah, 2^nkemungkinan kombinasi. Berikut adalah implementasi yang berfungsi, menggunakan generik dan set:

public static <T> Set<Set<T>> powerSet(Set<T> originalSet) {
    Set<Set<T>> sets = new HashSet<Set<T>>();
    if (originalSet.isEmpty()) {
        sets.add(new HashSet<T>());
        return sets;
    }
    List<T> list = new ArrayList<T>(originalSet);
    T head = list.get(0);
    Set<T> rest = new HashSet<T>(list.subList(1, list.size())); 
    for (Set<T> set : powerSet(rest)) {
        Set<T> newSet = new HashSet<T>();
        newSet.add(head);
        newSet.addAll(set);
        sets.add(newSet);
        sets.add(set);
    }       
    return sets;
}  

Dan tes, berikan masukan contoh Anda:

 Set<Integer> mySet = new HashSet<Integer>();
 mySet.add(1);
 mySet.add(2);
 mySet.add(3);
 for (Set<Integer> s : SetUtils.powerSet(mySet)) {
     System.out.println(s);
 }
João Silva
sumber
1
Apakah lebih cepat menggunakan Iterator daripada menggunakan list? Misalnya: Setel <T> rest = new HashSet <T> (originalSet); Iterator <T> i = rest.iterator (); T kepala = i.next (); i. hapus (); ?
Dimath
1
@CosminVacaroiu ... apa lagi yang bisa dilakukannya?
pengguna253751
3
Apakah kamu yakin itu O(2^n)? Itu adalah jumlah set dalam set daya, tetapi setiap set harus dibuat dalam memori, yang membutuhkan waktu setidaknya sebanding dengan ukuran set. Menurut wolfram alpha, ada di O(n * 2^n): kueri wolfram alpha
fabian
1
Akankah ini berfungsi bahkan jika ukuran set berada di urutan 10 ^ 5?
bane19
1
@GauravShankar 2 ^ 100 = 2 ^ (10 ^ 2) sudah lebih besar dari 10 ^ 30. Anda tidak akan menyaksikan penghitungan selesai pada mesin turing mana pun yang akan Anda hitung.
Karl Richter
31

Sebenarnya, saya telah menulis kode yang melakukan apa yang Anda minta di O (1). Pertanyaannya adalah apa yang Anda rencanakan untuk dilakukan dengan Set berikutnya. Jika Anda hanya akan memanggilnya size(), itu adalah O (1), tetapi jika Anda akan mengulanginya, itu jelas O(2^n).

contains()akan menjadi O(n), dll.

Apakah Anda benar-benar membutuhkan ini?

EDIT:

Kode ini sekarang tersedia di Guava , diekspos melalui metode Sets.powerSet(set).

Kevin Bourrillion
sumber
Saya perlu mengulang setiap subset
Manuel Araoz
Tetapi apakah Anda perlu menyimpan setiap subset?
finnw
2
Metode ini sekarang ada di Guava: guava-libraries.googlecode.com/svn/trunk/javadoc/com/google/…
Kevin Bourrillion
Bagaimana jika saya hanya ingin pangkat dengan elemen k persis? Apakah kode Anda efisien untuk itu?
Eyal
Tautan baru (Jambu biji dipindahkan ke Github)
yiwei
12

Inilah solusi di mana saya menggunakan generator, keuntungannya adalah, seluruh rangkaian daya tidak pernah disimpan sekaligus ... Jadi Anda dapat mengulanginya satu per satu tanpa perlu disimpan di memori. Menurut saya ini adalah opsi yang lebih baik ... Perhatikan bahwa kompleksitasnya sama, O (2 ^ n), tetapi persyaratan memori berkurang (dengan asumsi pengumpul sampah berperilaku!;))

/**
 *
 */
package org.mechaevil.util.Algorithms;

import java.util.BitSet;
import java.util.Iterator;
import java.util.Set;
import java.util.TreeSet;

/**
 * @author st0le
 *
 */
public class PowerSet<E> implements Iterator<Set<E>>,Iterable<Set<E>>{
    private E[] arr = null;
    private BitSet bset = null;

    @SuppressWarnings("unchecked")
    public PowerSet(Set<E> set)
    {
        arr = (E[])set.toArray();
        bset = new BitSet(arr.length + 1);
    }

    @Override
    public boolean hasNext() {
        return !bset.get(arr.length);
    }

    @Override
    public Set<E> next() {
        Set<E> returnSet = new TreeSet<E>();
        for(int i = 0; i < arr.length; i++)
        {
            if(bset.get(i))
                returnSet.add(arr[i]);
        }
        //increment bset
        for(int i = 0; i < bset.size(); i++)
        {
            if(!bset.get(i))
            {
                bset.set(i);
                break;
            }else
                bset.clear(i);
        }

        return returnSet;
    }

    @Override
    public void remove() {
        throw new UnsupportedOperationException("Not Supported!");
    }

    @Override
    public Iterator<Set<E>> iterator() {
        return this;
    }

}

Untuk menyebutnya, gunakan pola ini:

        Set<Character> set = new TreeSet<Character> ();
        for(int i = 0; i < 5; i++)
            set.add((char) (i + 'A'));

        PowerSet<Character> pset = new PowerSet<Character>(set);
        for(Set<Character> s:pset)
        {
            System.out.println(s);
        }

Ini dari Perpustakaan Proyek Euler saya ... :)

st0le
sumber
Jambu biji bekerja seperti ini, tetapi dibatasi hingga 32 elemen. Itu tidak masuk akal karena 2 ** 32 mungkin terlalu banyak iterasi. Ia menggunakan lebih sedikit memori daripada milik Anda karena ia menghasilkan AbstractSet hanya saat diperlukan. Coba kode Anda dengan kode Guava di mana Anda hanya mencetak 1 dari 10.000 elemen, dan buat contoh besar. Saya bertaruh bahwa Jambu biji akan lebih cepat.
Eyal
@Eyal, saya yakin begitu, saya tidak pernah mengklaim sebaliknya. Saya menulis ini sendiri, ini tidak dimaksudkan untuk kode produksi. Itu adalah latihan dalam algoritma.
st0le
1
Catatan kecil: 'returnSet' Anda adalah TreeSet, yang mengharuskan item-itemnya sebanding. Mungkin bukan ini masalahnya. Pertimbangkan untuk menukarnya dengan HashSet atau LinkedHashSet
Joris Kinable
10

Jika n <63, yang merupakan asumsi yang masuk akal karena Anda akan kehabisan memori (kecuali menggunakan implementasi iterator) mencoba untuk membangun set daya, ini adalah cara yang lebih ringkas untuk melakukannya. Operasi biner jauh lebih cepat daripada Math.pow()dan array untuk topeng, tetapi entah bagaimana pengguna Java takut akan mereka ...

List<T> list = new ArrayList<T>(originalSet);
int n = list.size();

Set<Set<T>> powerSet = new HashSet<Set<T>>();

for( long i = 0; i < (1 << n); i++) {
    Set<T> element = new HashSet<T>();
    for( int j = 0; j < n; j++ )
        if( (i >> j) % 2 == 1 ) element.add(list.get(j));
    powerSet.add(element); 
}

return powerSet;
Andrew Mao
sumber
Kondisi terminasi dalam loop for harus i <(2 << n - 1) bukan i <(1 << n - 1).
bazeusz
Terima kasih @bazeusz, saya mengubahnya i < (1 << n)yang setara.
Andrew Mao
Karena operasi yang sedikit bijak digunakan, saya pikir ((i >> j) &1) == 1alih-alih (i >> j) % 2 == 1 dapat digunakan. Juga, longsudah ditandatangani, jadi, menurut Anda apakah check for overflow masuk akal?
Ravi Tiwari
9

Berikut adalah tutorial yang menjelaskan dengan tepat apa yang Anda inginkan, termasuk kodenya. Anda benar karena kompleksitasnya adalah O (2 ^ n).

Adamski
sumber
2
Bukankah kompleksitas (n * 2 ^ n)? Karena string biner memiliki panjang n, dan dalam setiap iterasi loop utama kami mengulang seluruh string biner.
Maggie
1
Tutorialnya bagus TAPI saya telah menggunakan teknik ini dalam memecahkan masalah HackerRank: itu hanya lulus setengah dari kasus uji, dan setengah lainnya gagal karena batas waktu atau menyebabkan kesalahan runtime.
Eugenia Ozirna
7

Saya datang dengan solusi lain berdasarkan ide @Harry He. Mungkin bukan yang paling elegan tapi ini dia yang saya pahami:

Mari kita ambil contoh sederhana klasik PowerSet dari SP (S) = {{1}, {2}, {3}}. Rumus yang kita ketahui untuk mendapatkan jumlah himpunan adalah 2 ^ n (7 + himpunan kosong). Untuk contoh ini 2 ^ 3 = 8 subset.

Untuk menemukan setiap subset kita perlu mengubah 0-7 desimal menjadi representasi biner yang ditunjukkan pada tabel konversi di bawah ini:

ConversionTable

Jika kita menelusuri tabel baris demi baris, setiap baris akan menghasilkan subset dan nilai setiap subset akan berasal dari bit yang diaktifkan.

Setiap kolom di bagian Nilai Bin sesuai dengan posisi indeks di Set input asli.

Ini kode saya:

public class PowerSet {

/**
 * @param args
 */
public static void main(String[] args) {
    PowerSet ps = new PowerSet();
    Set<Integer> set = new HashSet<Integer>();
    set.add(1);
    set.add(2);
    set.add(3);
    for (Set<Integer> s : ps.powerSet(set)) {
        System.out.println(s);
    }
}

public Set<Set<Integer>> powerSet(Set<Integer> originalSet) {
    // Original set size e.g. 3
    int size = originalSet.size();
    // Number of subsets 2^n, e.g 2^3 = 8
    int numberOfSubSets = (int) Math.pow(2, size);
    Set<Set<Integer>> sets = new HashSet<Set<Integer>>();
    ArrayList<Integer> originalList = new ArrayList<Integer>(originalSet);
    for (int i = 0; i < numberOfSubSets; i++) {
        // Get binary representation of this index e.g. 010 = 2 for n = 3
        String bin = getPaddedBinString(i, size);
        //Get sub-set
        Set<Integer> set = getSet(bin, originalList));
        sets.add(set);
    }
    return sets;
}

//Gets a sub-set based on the binary representation. E.g. for 010 where n = 3 it will bring a new Set with value 2
private Set<Integer> getSet(String bin, List<Integer> origValues){
    Set<Integer> result = new HashSet<Integer>();
    for(int i = bin.length()-1; i >= 0; i--){
        //Only get sub-sets where bool flag is on
        if(bin.charAt(i) == '1'){
            int val = origValues.get(i);
            result.add(val);
        }
    }
    return result;
}

//Converts an int to Bin and adds left padding to zero's based on size
private String getPaddedBinString(int i, int size) {
    String bin = Integer.toBinaryString(i);
    bin = String.format("%0" + size + "d", Integer.parseInt(bin));
    return bin;
}

}
Adolfo Perez
sumber
5

Jika Anda menggunakan Eclipse Collections (sebelumnya GS Collections ), Anda dapat menggunakan powerSet()metode ini di semua SetIterables.

MutableSet<Integer> set = UnifiedSet.newSetWith(1, 2, 3);
System.out.println("powerSet = " + set.powerSet());
// prints: powerSet = [[], [1], [2], [1, 2], [3], [1, 3], [2, 3], [1, 2, 3]]

Catatan: Saya seorang pelaku untuk Koleksi Eclipse.

Craig P. Motlin
sumber
Dapatkah Anda membagikan dan menjelaskan kode solusi Anda?
Konrad Höffner
3
Anda dapat melihat kode di sini: github.com/goldmansachs/gs-collections/blob/…
Craig P.
4

Saya mencari solusi yang tidak sebesar yang diposting di sini. Ini menargetkan Java 7, jadi akan membutuhkan beberapa paste untuk versi 5 dan 6.

Set<Set<Object>> powerSetofNodes(Set<Object> orig) {
    Set<Set<Object>> powerSet = new HashSet<>(),
        runSet = new HashSet<>(),
        thisSet = new HashSet<>();

    while (powerSet.size() < (Math.pow(2, orig.size())-1)) {
        if (powerSet.isEmpty()) {
            for (Object o : orig) {
                Set<Object> s = new TreeSet<>();
                s.add(o);
                runSet.add(s);
                powerSet.add(s);
            }
            continue;
        }
        for (Object o : orig) {
            for (Set<Object> s : runSet) {
                Set<Object> s2 = new TreeSet<>();
                s2.addAll(s);
                s2.add(o);
                powerSet.add(s2);
                thisSet.add(s2);
            }
        }
        runSet.clear();
        runSet.addAll(thisSet);
        thisSet.clear();
    }
    powerSet.add(new TreeSet());
    return powerSet;

Berikut beberapa contoh kode untuk diuji:

Set<Object> hs = new HashSet<>();
hs.add(1);
hs.add(2);
hs.add(3);
hs.add(4);
for(Set<Object> s : powerSetofNodes(hs)) {
    System.out.println(Arrays.toString(s.toArray()));
}
Ben
sumber
Bukankah powerSetofNodes () kehilangan "}" di akhir?
Peter Mortensen
3

Beberapa solusi di atas menderita saat ukuran set besar karena menghasilkan banyak sampah objek untuk dikumpulkan dan memerlukan penyalinan data. Bagaimana kita bisa menghindarinya? Kita dapat memanfaatkan fakta bahwa kita tahu seberapa besar ukuran kumpulan hasil (2 ^ n), pra-alokasikan array sebesar itu, dan tambahkan saja ke ujungnya, jangan pernah menyalin.

Percepatan tumbuh dengan cepat dengan n. Saya membandingkannya dengan solusi João Silva di atas. Di mesin saya (semua perkiraan pengukuran), n = 13 adalah 5x lebih cepat, n = 14 adalah 7x, n = 15 adalah 12x, n = 16 adalah 25x, n = 17 adalah 75x, n = 18 adalah 140x. Sehingga pembuatan / pengumpulan dan penyalinan sampah mendominasi dalam solusi besar yang tampaknya serupa.

Melakukan pra-alokasi array di awal tampaknya lebih menguntungkan dibandingkan membiarkannya tumbuh secara dinamis. Dengan n = 18, pertumbuhan dinamis membutuhkan waktu sekitar dua kali lebih lama secara keseluruhan.

public static <T> List<List<T>> powerSet(List<T> originalSet) {
    // result size will be 2^n, where n=size(originalset)
    // good to initialize the array size to avoid dynamic growing
    int resultSize = (int) Math.pow(2, originalSet.size());
    // resultPowerSet is what we will return
    List<List<T>> resultPowerSet = new ArrayList<List<T>>(resultSize);

    // Initialize result with the empty set, which powersets contain by definition
    resultPowerSet.add(new ArrayList<T>(0)); 

    // for every item in the original list
    for (T itemFromOriginalSet : originalSet) {

        // iterate through the existing powerset result
        // loop through subset and append to the resultPowerset as we go
        // must remember size at the beginning, before we append new elements
        int startingResultSize = resultPowerSet.size();
        for (int i=0; i<startingResultSize; i++) {
            // start with an existing element of the powerset
            List<T> oldSubset = resultPowerSet.get(i);

            // create a new element by adding a new item from the original list
            List<T> newSubset = new ArrayList<T>(oldSubset);
            newSubset.add(itemFromOriginalSet);

            // add this element to the result powerset (past startingResultSize)
            resultPowerSet.add(newSubset);
        }
    }
    return resultPowerSet;
}
George Fairbanks
sumber
3

Solusi berikut dipinjam dari buku saya " Coding Interviews: Questions, Analysis & Solutions ":

Beberapa bilangan bulat dalam larik dipilih yang menyusun kombinasi. Satu set bit digunakan, di mana setiap bit adalah singkatan dari integer dalam array. Jika karakter ke-i dipilih untuk kombinasi, bit ke-i adalah 1; jika tidak, nilainya 0. Misalnya, tiga bit digunakan untuk kombinasi larik [1, 2, 3]. Jika dua bilangan bulat pertama 1 dan 2 dipilih untuk membuat kombinasi [1, 2], bit yang sesuai adalah {1, 1, 0}. Demikian pula, bit yang terkait dengan kombinasi lain [1, 3] adalah {1, 0, 1}. Kita bisa mendapatkan semua kombinasi larik dengan panjang n jika kita bisa mendapatkan semua kemungkinan kombinasi n bit.

Sejumlah terdiri dari sekumpulan bit. Semua kemungkinan kombinasi n bit sesuai dengan angka dari 1 hingga 2 ^ n -1. Oleh karena itu, setiap angka dalam rentang antara 1 dan 2 ^ n -1 sesuai dengan kombinasi larik dengan panjang n . Misalnya, angka 6 terdiri dari bit {1, 1, 0}, jadi karakter pertama dan kedua dipilih dalam larik [1, 2, 3] untuk menghasilkan kombinasi [1, 2]. Demikian pula, angka 5 dengan bit {1, 0, 1} sesuai dengan kombinasi [1, 3].

Kode Java untuk mengimplementasikan solusi ini terlihat seperti di bawah ini:

public static ArrayList<ArrayList<Integer>> powerSet(int[] numbers) {
    ArrayList<ArrayList<Integer>> combinations = new ArrayList<ArrayList<Integer>>(); 
    BitSet bits = new BitSet(numbers.length);
    do{
        combinations.add(getCombination(numbers, bits));
    }while(increment(bits, numbers.length));

    return combinations;
}

private static boolean increment(BitSet bits, int length) {
    int index = length - 1;

    while(index >= 0 && bits.get(index)) {
        bits.clear(index);
        --index;
    }

    if(index < 0)
        return false;

    bits.set(index);
    return true;
}

private static ArrayList<Integer> getCombination(int[] numbers, BitSet bits){
    ArrayList<Integer> combination = new ArrayList<Integer>();
    for(int i = 0; i < numbers.length; ++i) {
        if(bits.get(i))
            combination.add(numbers[i]);
    }

    return combination;
}

Kenaikan metode meningkatkan angka yang direpresentasikan dalam satu set bit. Algoritme membersihkan 1 bit dari bit paling kanan hingga 0 bit ditemukan. Ia kemudian menetapkan 0 bit paling kanan ke 1. Misalnya, untuk meningkatkan angka 5 dengan bit {1, 0, 1}, ia membersihkan 1 bit dari sisi kanan dan menetapkan 0 bit paling kanan ke 1. Bit menjadi {1, 1, 0} untuk angka 6, yang merupakan hasil dari peningkatan 5 dengan 1.

Harry He
sumber
Dua hal yang saya modifikasi: perulangan di getCombination, alih-alih number.length (atau bits.size ()), seseorang dapat beralih ke bits.length (), yang sedikit mempercepat generasi. Akhirnya, saya mengurutkan subset berdasarkan ukuran untuk masalah saya membutuhkan itu.
BoLe
3

Berikut adalah solusi iteratif O (2 ^ n) yang mudah:

public static Set<Set<Integer>> powerSet(List<Integer> intList){

    Set<Set<Integer>> result = new HashSet();
    result.add(new HashSet());

    for (Integer i : intList){

        Set<Set<Integer>> temp = new HashSet();

        for(Set<Integer> intSet : result){

            intSet = new HashSet(intSet);
            intSet.add(i);                
            temp.add(intSet);
        }
        result.addAll(temp);
    }
    return result;
}
jump3r
sumber
Solusi ini juga menggunakan ruang O (2 ^ n) yang akan terlalu banyak untuk set input yang besar. Lebih baik mengikuti definisi rekursif, menggunakan tumpukan atau antrian sebagai pengganti rekursi.
rossb83
2
import java.util.Set;
import com.google.common.collect.*;

Set<Set<Integer>> sets = Sets.powerSet(ImmutableSet.of(1, 2, 3));
Bax
sumber
1

Jika S adalah himpunan hingga dengan N elemen, maka himpunan dari S berisi 2 ^ N elemen. Waktu untuk sekadar menghitung elemen pangkat adalah 2 ^ N, jadiO(2^N) juga batas bawah pada kompleksitas waktu (dengan penuh semangat) membangun set pangkat.

Sederhananya, setiap komputasi yang melibatkan pembuatan set kekuatan tidak akan diskalakan untuk nilai N. yang besar. Tidak ada algoritme cerdas yang akan membantu Anda ... selain menghindari kebutuhan untuk membuat rangkaian kekuatan!

Stephen C
sumber
1

Salah satu cara tanpa rekursi adalah sebagai berikut: Gunakan masker biner dan buat semua kombinasi yang mungkin.

public HashSet<HashSet> createPowerSet(Object[] array)
{
    HashSet<HashSet> powerSet=new HashSet();
    boolean[] mask= new boolean[array.length];

    for(int i=0;i<Math.pow(2, array.length);i++)
    {
        HashSet set=new HashSet();
        for(int j=0;j<mask.length;j++)
        {
            if(mask[i])
                set.add(array[j]);
        }
        powerSet.add(set);      

        increaseMask(mask);
    }

    return powerSet;
}

public void increaseMask(boolean[] mask)
{
    boolean carry=false;

    if(mask[0])
        {
            mask[0]=false;
            carry=true;
        }
    else
        mask[0]=true;

    for(int i=1;i<mask.length;i++)
    {
        if(mask[i]==true && carry==true)
        mask[i]=false;
        else if (mask[i]==false && carry==true)
        {
            mask[i]=true;
            carry=false;
        }
        else 
            break;

    }

}
Orestis
sumber
1

Algoritma:

Input: Set [], set_size 1. Dapatkan ukuran power set powet_set_size = pow (2, set_size) 2 Loop untuk counter dari 0 ke pow_set_size (a) Loop untuk i = 0 ke set_size (i) Jika bit ke-ith di counter adalah set Cetak elemen ke dari set untuk subset ini (b) Cetak separator untuk subset yaitu baris baru

#include <stdio.h>
#include <math.h>
 
void printPowerSet(char *set, int set_size)
{
    /*set_size of power set of a set with set_size
      n is (2**n -1)*/
    unsigned int pow_set_size = pow(2, set_size);
    int counter, j;
 
    /*Run from counter 000..0 to 111..1*/
    for(counter = 0; counter < pow_set_size; counter++)
    {
      for(j = 0; j < set_size; j++)
       {
          /* Check if jth bit in the counter is set
             If set then pront jth element from set */
          if(counter & (1<<j))
            printf("%c", set[j]);
       }
       printf("\n");
    }
}
 
/*Driver program to test printPowerSet*/
int main()
{
    char set[] = {'a','b','c'};
    printPowerSet(set, 3);
 
    getchar();
    return 0;
}

gaurav
sumber
1

Ini adalah solusi rekursif saya yang bisa mendapatkan set daya dari set apa pun menggunakan Java Generics. Ide utamanya adalah menggabungkan head dari array input dengan semua solusi yang mungkin dari sisa array sebagai berikut.

import java.util.LinkedHashSet;
import java.util.Set;

public class SetUtil {
    private static<T>  Set<Set<T>> combine(T head, Set<Set<T>> set) {
        Set<Set<T>> all = new LinkedHashSet<>();

        for (Set<T> currentSet : set) {
            Set<T> outputSet = new LinkedHashSet<>();

            outputSet.add(head);
            outputSet.addAll(currentSet);

            all.add(outputSet);
        }

        all.addAll(set);        

        return all;
    }

    //Assuming that T[] is an array with no repeated elements ...
    public static<T> Set<Set<T>> powerSet(T[] input) {
        if (input.length == 0) {
            Set <Set<T>>emptySet = new LinkedHashSet<>();

            emptySet.add(new LinkedHashSet<T>());

            return emptySet;
        }

        T head = input[0];
        T[] newInputSet = (T[]) new Object[input.length - 1];

        for (int i = 1; i < input.length; ++i) {
            newInputSet[i - 1] = input[i];
        }

        Set<Set<T>> all = combine(head, powerSet(newInputSet));

        return all;
    }

    public static void main(String[] args) {            
        Set<Set<Integer>> set = SetUtil.powerSet(new Integer[] {1, 2, 3, 4, 5, 6});

        System.out.println(set);
    }
}

Ini akan menghasilkan:

[[1, 2, 3, 4, 5, 6], [1, 2, 3, 4, 5], [1, 2, 3, 4, 6], [1, 2, 3, 4], [1, 2, 3, 5, 6], [1, 2, 3, 5], [1, 2, 3, 6], [1, 2, 3], [1, 2, 4, 5, 6], [1, 2, 4, 5], [1, 2, 4, 6], [1, 2, 4], [1, 2, 5, 6], [1, 2, 5], [1, 2, 6], [1, 2], [1, 3, 4, 5, 6], [1, 3, 4, 5], [1, 3, 4, 6], [1, 3, 4], [1, 3, 5, 6], [1, 3, 5], [1, 3, 6], [1, 3], [1, 4, 5, 6], [1, 4, 5], [1, 4, 6], [1, 4], [1, 5, 6], [1, 5], [1, 6], [1], [2, 3, 4, 5, 6], [2, 3, 4, 5], [2, 3, 4, 6], [2, 3, 4], [2, 3, 5, 6], [2, 3, 5], [2, 3, 6], [2, 3], [2, 4, 5, 6], [2, 4, 5], [2, 4, 6], [2, 4], [2, 5, 6], [2, 5], [2, 6], [2], [3, 4, 5, 6], [3, 4, 5], [3, 4, 6], [3, 4], [3, 5, 6], [3, 5], [3, 6], [3], [4, 5, 6], [4, 5], [4, 6], [4], [5, 6], [5], [6], []]
Hazem Saleh
sumber
1

Contoh implementasi lainnya:

 public static void main(String args[])
    {
        int[] arr = new int[]{1,2,3,4};
        // Assuming that number of sets are in integer range
        int totalSets = (int)Math.pow(2,arr.length);
        for(int i=0;i<totalSets;i++)
        {
            String binaryRep = Integer.toBinaryString(i);      
            for(int j=0;j<binaryRep.length();j++)
            {
                int index=binaryRep.length()-1-j;
                if(binaryRep.charAt(index)=='1')
                System.out.print(arr[j] +" ");       
            }
            System.out.println();
        }
    }
Sandeep
sumber
1

Ini adalah pendekatan saya dengan lambda.

public static <T> Set<Set<T>> powerSet(T[] set) {
      return IntStream
            .range(0, (int) Math.pow(2, set.length))
            .parallel() //performance improvement
            .mapToObj(e -> IntStream.range(0, set.length).filter(i -> (e & (0b1 << i)) != 0).mapToObj(i -> set[i]).collect(Collectors.toSet()))
            .map(Function.identity())
            .collect(Collectors.toSet());
        }

Atau secara paralel (lihat komentar paralel ()):

Ukuran set input: 18

Prosesor logis: 8 à 3.4GHz

Peningkatan kinerja: 30%

Werner
sumber
1

Himpunan bagian dari t adalah setiap himpunan yang dapat dibuat dengan menghilangkan nol atau lebih elemen dari t. Subset withoutFirst menambahkan subset dari t yang kehilangan elemen pertama dan for loop akan menangani penambahan subset dengan elemen pertama. Misalnya, jika t berisi elemen ["1", "2", "3"], missingFirst akan menambahkan [[""], ["2"], ["3"], ["2", "3 "]] dan loop for akan menempelkan" 1 "di depan elemen ini dan menambahkannya ke newSet. Jadi kita akan mendapatkan [[""], ["1"], ["2"], ["3"], ["1", "2"], ["1", "3"] , ["2", "3"], ["1", "2", "3"]].

public static Set<Set<String>> allSubsets(Set<String> t) {
        Set<Set<String>> powerSet = new TreeSet<>();
        if(t.isEmpty()) {
            powerSet.add(new TreeSet<>());
            return powerSet;
        }
        String first = t.get(0);
        Set<Set<String>> withoutFirst = allSubsets(t.subSet(1, t.size()));
        for (List<String> 1st : withoutFirst) {
            Set<String> newSet = new TreeSet<>();
            newSet.add(first);
            newSet.addAll(lst);
            powerSet.add(newSet);
        }
        powerSet.addAll(withoutFirst);
        return powerSet;
    }
Tn. H.
sumber
Harap pertimbangkan untuk menambahkan penjelasan singkat di sepanjang kode yang Anda berikan.
Mirza Sisic
Ini bahkan tidak dapat dikompilasi, tampaknya ditulis dalam beberapa versi Java fantasi. Settidak memiliki getmetode dengan indeks, atau subSetmetode; 1stbukan pengenal yang valid (saya kira lstitu dimaksudkan). Ubah semua set menjadi daftar dan hampir
terkompilasi
0
// input: S
// output: P
// S = [1,2]
// P = [], [1], [2], [1,2]

public static void main(String[] args) {
    String input = args[0];
    String[] S = input.split(",");
    String[] P = getPowerSet(S);
    if (P.length == Math.pow(2, S.length)) {
        for (String s : P) {
            System.out.print("[" + s + "],");
        }
    } else {
        System.out.println("Results are incorrect");
    }
}

private static String[] getPowerSet(String[] s) {
    if (s.length == 1) {
        return new String[] { "", s[0] };
    } else {
        String[] subP1 = getPowerSet(Arrays.copyOfRange(s, 1, s.length));
        String[] subP2 = new String[subP1.length];
        for (int i = 0; i < subP1.length; i++) {
            subP2[i] = s[0] + subP1[i];
        }
        String[] P = new String[subP1.length + subP2.length];
        System.arraycopy(subP1, 0, P, 0, subP1.length);
        System.arraycopy(subP2, 0, P, subP1.length, subP2.length);
        return P;
    }

}
Neyyadupakkam Sundarasekaran
sumber
Selamat datang di Stack Overflow. Anda mungkin ingin menyempurnakan jawaban ini sedikit dengan beberapa teks yang menjelaskan apa yang dilakukannya dan bagaimana itu memecahkan masalah penanya.
Lachlan Goodhew-Cook
0

Saya baru-baru ini harus menggunakan sesuatu seperti ini, tetapi membutuhkan sublist terkecil (dengan 1 elemen, lalu 2 elemen, ...) terlebih dahulu. Saya tidak ingin memasukkan yang kosong maupun daftar keseluruhan. Selain itu, saya tidak memerlukan daftar semua sublist yang dikembalikan, saya hanya perlu melakukan beberapa hal dengan masing-masing sublist.

Ingin melakukan ini tanpa rekursi, dan muncul dengan yang berikut (dengan "melakukan hal-hal" disarikan menjadi antarmuka fungsional):

@FunctionalInterface interface ListHandler<T> {
    void handle(List<T> list);
}


public static <T> void forAllSubLists(final List<T> list, ListHandler handler) {
    int     ll = list.size();   // Length of original list
    int     ci[] = new int[ll]; // Array for list indices
    List<T> sub = new ArrayList<>(ll);  // The sublist
    List<T> uml = Collections.unmodifiableList(sub);    // For passing to handler

    for (int gl = 1, gm; gl <= ll; gl++) {  // Subgroup length 1 .. n-1
        gm = 0; ci[0] = -1; sub.add(null);  // Some inits, and ensure sublist is at least gl items long

        do {
                ci[gm]++;                       // Get the next item for this member

                if (ci[gm] > ll - gl + gm) {    // Exhausted all possibilities for this position
                        gm--; continue;         // Continue with the next value for the previous member
                }

                sub.set(gm, list.get(ci[gm]));  // Set the corresponding member in the sublist

                if (gm == gl - 1) {             // Ok, a sublist with length gl
                        handler.handle(uml);    // Handle it
                } else {
                        ci[gm + 1] = ci[gm];    // Starting value for next member is this 
                        gm++;                   // Continue with the next member
                }
        } while (gm >= 0);  // Finished cycling through all possibilities
    }   // Next subgroup length
}

Dengan cara ini, juga mudah untuk membatasinya ke sublist dengan panjang tertentu.

tijmen
sumber
0
public class PowerSet {
    public static List<HashSet<Integer>> powerset(int[] a) {
        LinkedList<HashSet<Integer>> sets = new LinkedList<HashSet<Integer>>();
        int n = a.length;
        for (int i = 0; i < 1 << n; i++) {
            HashSet<Integer> set = new HashSet<Integer>();
            for (int j = 0; j < n; j++) {
                if ((1 << j & i) > 0)
                    set.add(a[j]);
            }
            sets.add(set);
        }
        return sets;
    }

    public static void main(String[] args) {
        List<HashSet<Integer>> sets = PowerSet.powerset(new int[]{ 1, 2, 3 });
        for (HashSet<Integer> set : sets) {
            for (int i : set)
                System.out.print(i);
            System.out.println();
        } 
    }
}
Selim Ekizoglu
sumber
0

Namun solusi lain - dengan java8 + streaming api Ini malas dan teratur sehingga mengembalikan subset yang benar ketika digunakan dengan "limit ()".

 public long bitRangeMin(int size, int bitCount){
    BitSet bs = new BitSet(size);
    bs.set(0, bitCount);
    return bs.toLongArray()[0];
}

public long bitRangeMax(int size, int bitCount){
    BitSet bs = BitSet.valueOf(new long[]{0});
    bs.set(size - bitCount, size);
    return bs.toLongArray()[0];
}

public <T> Stream<List<T>> powerSet(Collection<T> data)
{
    List<T> list = new LinkedHashSet<>(data).stream().collect(Collectors.toList());
    Stream<BitSet> head = LongStream.of(0).mapToObj( i -> BitSet.valueOf(new long[]{i}));
    Stream<BitSet> tail = IntStream.rangeClosed(1, list.size())
            .boxed()
            .flatMap( v1 -> LongStream.rangeClosed( bitRangeMin(list.size(), v1), bitRangeMax(list.size(), v1))
                    .mapToObj(v2 -> BitSet.valueOf(new long[]{v2}))
                    .filter( bs -> bs.cardinality() == v1));

    return Stream.concat(head, tail)
            .map( bs -> bs
                    .stream()
                    .mapToObj(list::get)
                    .collect(Collectors.toList()));
}

Dan kode kliennya adalah

@Test
public void testPowerSetOfGivenCollection(){
    List<Character> data = new LinkedList<>();
    for(char i = 'a'; i < 'a'+5; i++ ){
        data.add(i);
    }
    powerSet(data)
            .limit(9)
            .forEach(System.out::print);

}

/ * Cetakan: [] [a] [b] [c] [d] [e] [a, b] [a, c] [b, c] * /

ekobir
sumber
0

Kita bisa menulis set daya dengan atau tanpa menggunakan rekursi. Berikut ini upaya tanpa rekursi:

public List<List<Integer>> getPowerSet(List<Integer> set) {
    List<List<Integer>> powerSet = new ArrayList<List<Integer>>();
    int max = 1 << set.size();
    for(int i=0; i < max; i++) {
        List<Integer> subSet = getSubSet(i, set);
        powerSet.add(subSet);
    }
    return powerSet;
}

private List<Integer> getSubSet(int p, List<Integer> set) {
    List<Integer> subSet = new ArrayList<Integer>();
    int position = 0;
    for(int i=p; i > 0; i >>= 1) {
        if((i & 1) == 1) {
            subSet.add(set.get(position));
        }
        position++;
    }
    return subSet;
}
YuVi
sumber
0

Berikut ini untuk menghasilkan satu set daya. Idenya adalah pertama = S[0]dan set yang lebih kecil menjadi S[1,...n].

Hitung semua subset dari tinySet dan letakkan di semua subset.

Untuk setiap subset di semua subset, klon dan tambahkan terlebih dahulu ke subset.

ArrayList<ArrayList<Integer>> getSubsets(ArrayList<Integer> set, int index){
    ArrayList<ArrayList<Integer>> allsubsets;
    if(set.size() == index){
        allsubsets = new ArrayList<ArrayList<Integer>>();
        allsubsets.add(new ArrayList<Integer>()); // the empty set 
    }else{
        allsubsets = getSubsets(set, index+1);
        int item = set.get(index);

        ArrayList<ArrayList<Integer>> moresubsets = new ArrayList<ArrayList<Integer>>();

        for(ArrayList<Integer> subset: allsubsets){
            ArrayList<Integer> newsubset = new ArrayList<Integer>();

            newsubset.addAll(subset);
            newsubset.add(item);
            moresubsets.add(newsubset);

        }

        moresubsets.addAll(moresubsets);

    }

    return allsubsets;
}
Tidak ada
sumber
0
package problems;

import java.util.ArrayList;
import java.util.List;

public class SubsetFinderRecursive {
    public static void main(String[] args) {
        //input
        int[] input = new int[3];
        for(int i=0; i<input.length; i++) {
            input[i] = i+1;
        }
        // root node of the tree
        Node root = new Node();

        // insert values into tree
        for(int i=0; i<input.length; i++) {
            insertIntoTree(root, input[i]);
        }

        // print leaf nodes for subsets
        printLeafNodes(root);
    }

    static void printLeafNodes(Node root) {

        if(root == null) {
            return;
        }

        // Its a leaf node
        if(root.left == null && root.right == null) {
            System.out.println(root.values);
            return;
        }

        // if we are not at a leaf node, then explore left and right

        if(root.left !=null) {
            printLeafNodes(root.left);
        }

        if(root.right != null) {
            printLeafNodes(root.right);
        }
    }

    static void insertIntoTree(Node root, int value) {

        // Error handling
        if(root == null) {
            return;
        }

        // if there is a sub tree then go down
        if(root.left !=null && root.right != null) {
            insertIntoTree(root.left, value);
            insertIntoTree(root.right, value);
        }

        // if we are at the leaf node, then we have 2 choices
        // Either exclude or include
        if(root.left == null && root.right == null) {
            // exclude
            root.left = new Node();
            root.left.values.addAll(root.values);
            // include
            root.right = new Node();
            root.right.values.addAll(root.values);
            root.right.values.add(value);
            return;
        }
    }

}

class Node {
    Node left;
    Node right;
    List<Integer> values = new ArrayList<Integer>();
}
Prakash Devta
sumber