2

Googling around for a while to find subsets of a String, i read wikipedia and it mentions that

.....For the whole power set of S we get:

{ } = 000 (Binary) = 0 (Decimal)
{x} = 100 = 4
{y} = 010 = 2
{z} = 001 = 1
{x, y} = 110 = 6
{x, z} = 101 = 5
{y, z} = 011 = 3
{x, y, z} = 111 = 7

Is there a possible way to implement this through program and avoid recursive algorithm which uses string length?

What i understood so far is that, for a String of length n, we can run from 0 to 2^n - 1 and print characters for on bits.
What i couldn't get is how to map those on bits with the corresponding characters in the most optimized manner

PS : checked thread but couldnt understood this and c++ : Power set generated by bits

Community
  • 1
  • 1
NoobEditor
  • 15,563
  • 19
  • 81
  • 112
  • hi, i don't have time currently but i want to discuss it with you later. can you share contact info? – Juvanis Jul 11 '14 at 08:08
  • @Juvanis : that's the most amazing comment i ever saw on SO....didn't know what to reply at first :) drop an answer when you have time.....no hurries mate!! or LinkedIn URL i can give if that suits you :) – NoobEditor Jul 11 '14 at 08:14
  • Please consider marking as correct one of the answers. – Konrad Höffner Jul 16 '14 at 11:34

2 Answers2

1

The idea is that a power set of a set of size n has exactly 2^n elements, exactly the same number as there are different binary numbers of length at most n.

Now all you have to do is create a mapping between the two and you don't need a recursive algorithm. Fortunately with binary numbers you have a real intuitive and natural mapping in that you just add a character at position j in the string to a subset if your loop variable has bit j set which you can easily do with getBit() I wrote there (you can inline it but for you I made a separate function for better readability).

P.S. As requested, more detailed explanation on the mapping: If you have a recursive algorithm, your flow is given by how you traverse your data structure in the recursive calls. It is as such a very intuitive and natural way of solving many problems.

If you want to solve such a problem without recursion for whatever reason, for instance to use less time and memory, you have the difficult task of making this traversal explicit.

As we use a loop with a loop variable which assumes a certain set of values, we need to make sure to map each value of the loop variable, e.g. 42, to one element, in our case a subset of s, in a way that we have a bijective mapping, that is, we map to each subset exactly once. Because we have a set the order does not matter, so we just need whatever mapping that satisfies these requirements.

Now we look at a binary number, e.g. 42 = 32+8+2 and as such in binary with the position above:

543210
101010

We can thus map 42 to a subset as follows using the positions:

  • order the elements of the set s in any way you like but consistently (always the same in one program execution), we can in our case use the order in the string
  • add an element e_j if and only if the bit at position j is set (equal to 1).

As each number has at least one digit different from any other, we always get different subsets, and thus our mapping is injective (different input -> different output).

Our mapping is also valid, as the binary numbers we chose have at most the length equal to the size of our set so the bit positions can always be assigned to an element in the set. Combined with the fact that our set of inputs is chosen to have the same size (2^n) as the size of a power set, we can follow that it is in fact bijective.

import java.util.HashSet;
import java.util.Set;

public class PowerSet
{

    static boolean getBit(int i, int pos) {return (i&1<<pos)>0;}

    static Set<Set<Character>> powerSet(String s)
    {
        Set<Set<Character>> pow = new HashSet<>();
        for(int i=0;i<(2<<s.length());i++)
        {
            Set<Character> subSet = new HashSet<>();
            for(int j=0;j<s.length();j++)
            {
                if(getBit(i,j)) {subSet.add(s.charAt(j));}
            }
            pow.add(subSet);
        }
        return pow;

    }

    public static void main(String[] args)
    {System.out.println(powerSet("xyz"));}

}
Konrad Höffner
  • 11,100
  • 16
  • 60
  • 118
  • from `Fortunately..........there ` you wrote everything without a break and i am not able to understand, can you rephrase for a *Noob* to understand! :) – NoobEditor Jul 11 '14 at 09:30
1

Here is easy way to do it (pseudo code) :-

for(int i=0;i<2^n;i++) {

  char subset[];
  int k = i;
  int c = 0;
  while(k>0) {

    if(k%2==1) {
       subset.add(string[c]);
    }
    k = k/2;
    c++;
  } 

  print subset;
}

Explanation :- The code divides number by 2 and calculates remainder which is used to convert number to binary form. Then as you know only selects index in string which has 1 at that bit number.

Vikram Bhat
  • 6,106
  • 3
  • 20
  • 19