Generating power set recursively without any loops

前端 未结 8 1250
执笔经年
执笔经年 2020-12-16 18:50

How do you write a recursive method PowerSet(String input) that prints out all possible combinations of a string that is passed to it?

For example: PowerSet(\"abc\")

相关标签:
8条回答
  • 2020-12-16 18:57
    void powerSet(int * ar, int *temp, int n, int level,int index)
    {
        if(index==n) return;
    
        int i,j;
        for(i=index;i<n;i++)
        {
        temp[level]=ar[i];
    
        for(j=0;j<=level;j++)
        printf("%d ",temp[j]);
        printf("   - - -  t\n");
    
        powerSet(ar, temp, n, level+1,i+1);
        }
    }
    
    int main()
    {
        int price[] = {1,2,3,7};
        int temp[4] ={0};
    
        int n = sizeof(price)/sizeof(price[0]);
    
        powerSet(price, temp, n, 0,0);
    
    
        return 0;
    }
    
    0 讨论(0)
  • 2020-12-16 19:02

    Just for fun, a version that does powersets of any set stored in a LinkedList (to make it easy to remove the head element). Java 8 streams do the functional part:

    static <T> LinkedList<LinkedList<T>> powerset(LinkedList<T> elements) {
      if (elements.isEmpty()) 
        return copyWithAddedElement(new LinkedList<>(), new LinkedList<>());
      T first = elements.pop();
      LinkedList<LinkedList<T>> powersetOfRest = powerset(elements);
      return Stream.concat(
          powersetOfRest.stream(), 
          powersetOfRest.stream().map(list -> copyWithAddedElement(list, first)))
              .collect(Collectors.toCollection(LinkedList::new));
    }
    
    static <T> LinkedList<T> copyWithAddedElement(LinkedList<T> list, T elt) {
      list = new LinkedList<>(list);
      list.push(elt);
      return list;
    }
    

    This is inspired by the following Common Lisp, which shows that the right language can make things simpler:

    (defun powerset (set)
      (cond ((null set) '(()))
            (t (let ((powerset-of-rest (powerset (cdr set))))
              (append powerset-of-rest
                      (mapcar #'(lambda (x) (cons (car set) x)) 
                              powerset-of-rest))))))
    
    0 讨论(0)
  • 2020-12-16 19:04

    Based on the info here, here is solution in C#.

    NOTE: the loop in the main function is just to print the result into the console value. No loops used in the PowerSet method.

        public static void Main(string[] args)
        {
    
            string input = "abbcdd";
    
    
            Dictionary < string, string> resultSet = new Dictionary<string, string>();
    
            PowerSet(input, "", 0, resultSet);
    
            //apply sorting 
            var resultSorted = resultSet.OrderBy(l => l.Key.Length).ThenBy(l=>l.Key);
    
            //print values
            foreach(var keyValue in resultSorted)
            {
                Console.Write("{{{0}}}, ",keyValue.Key);
            }
    
    
        }
    
        /// <summary>
        /// Computes the powerset of a string recursively
        /// based on the Algorithm http://www.ideserve.co.in/learn/generate-all-subsets-of-a-set-recursion
        /// </summary>
        /// <param name="input">Original input string</param>
        /// <param name="temp">Temporary variable to store the current char for the curr call</param>
        /// <param name="depth">The character position we are evaluating to add to the set</param>
        /// <param name="resultSet">A hash list to store the result</param>
        public static void PowerSet(string input, string temp, int depth, Dictionary<string, string> resultSet)
        {
    
            //base case
            if(input.Length == depth)
            {
                //remove duplicate characters
                string key = new string(temp.ToCharArray().Distinct().ToArray());
    
                //if the character/combination is already in the result, skip it
                if (!resultSet.ContainsKey(key))
                    resultSet.Add(key, key);
    
                return;//exit 
            }
    
            //left
            PowerSet(input, temp, depth + 1, resultSet);
    
            //right
            PowerSet(input, temp + input[depth], depth + 1, resultSet);
    
        }
    
    0 讨论(0)
  • 2020-12-16 19:10

    A recursive version of the generic solution proposed by João Silva :

    public static <T> Set<Set<T>> powerSet2(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()));
        addSets(sets, powerSet(rest), head);
        return  sets;
    }
    
    private static <T> void addSets(Set<Set<T>> sets, Set<Set<T>> setsToAdd, T head) {
        Iterator<Set<T>> iterator = setsToAdd.iterator();
        if (iterator.hasNext()) {
            Set<T> set = iterator.next();
            iterator.remove();
            Set<T> newSet = new HashSet<T>();
            newSet.add(head);
            newSet.addAll(set);
            sets.add(newSet);
            sets.add(set);
            addSets(sets, setsToAdd, head);
        }
    }
    

    I extract the recursive addSets method to transform the original for loop:

    for (Set<T> set : powerSet(rest)) {
        Set<T> newSet = new HashSet<T>();
        newSet.add(head);
        newSet.addAll(set);
        sets.add(newSet);
        sets.add(set);
    }
    
    0 讨论(0)
  • 2020-12-16 19:11

    Simple solution but with poor time complexity(2^n) is as following(just keep one thing in mind once we have to avoid(i.e. 0) and once we have to take it(i.e. 1):

    public HashSet<int[]> powerSet(int n) {
        return calcPowerSet(n-1, new HashSet<int[]>(), new int[n]);
    }
    
    private HashSet<int[]> calcPowerSet(int n, HashSet<int[]> result, int []set) {
        if(n < 0) {
            result.add(set.clone());
            return null;
        }
        else {
            set[n] = 0;
            calcPowerSet(n-1, result, set);
            set[n] = 1;
            calcPowerSet(n-1, result, set);
            return result;
        }
    }
    
    0 讨论(0)
  • 2020-12-16 19:15

    The powerset of abcd is the union of the power-sets of abc, abd, acd (plus the set abcd itself*).

     P(`abcd`) = {`abcd`} + P(`abc`) + P(`abd`) + P(`acd`) + P(`bcd`)
    

    * Note that the empty set, which is a member of P(abcd) is also a member of P(abc), P(abd), ... so the equivalence stated above holds.

    Recursively, P(abc) = {abc} + P(ab) + P(ac), and so on

    A first approach, in pseudocode, could be:

    powerset(string) {
      add string to set;
      for each char in string {
       let substring = string excluding char,
       add powerset(substring) to set
      }
      return set;      
    }
    

    The recursion ends when the string is empty (because it never enters the loop).

    If your really want no loops, you will have to convert that loop to another recursion. Now we want to generate ab, ac and cb from abc

    powerset(string) {
      add string to set;
      add powerset2(string,0) to set;
      return set
    }
    
    powerset2(string,pos) {
      if pos<length(string) then
        let substring = (string excluding the char at pos)
        add powerset(substring) to set
        add powerset2(string,pos+1) to set
      else 
        add "" to set
      endif
      return set
    }
    

    Another approach implement a recursive function P that either removes the first character from its argument, or does not. (Here + means set union, . means concatenation and λ is the empty string)

    P(abcd) = P(bcd) + a.P(bcd)
    P(bcd)  = P(cd)  + b.P(cd)
    P(cd)   = P(d)   + c.P(d)
    P(d)    = λ+d //particular case
    

    Then

    P(d)    = λ+d
    R(cd)   = P(d)  + c.P(d)  = λ + d + c.(λ+d) = λ + d + c + cd
    R(bcd)  = P(cd) + b.P(cd) = λ + d + c + cd + b.(λ + d + c + cd)
                              = λ + d + c + cd + b + bd + bc + bcd
    P(abcd) =  λ +  d +  c +  cd +  b +  bd +  bc +  bcd 
            + aλ + ad + ac + acd + ab + abd + abc + abcd 
    

    If loops were allowed, then P is out power-set function. Otherwise, we would need a one-parameter loopless function for concatenating a given character to a given set of strings (which obviously are two things).

    Some tweak could be possible by playing with String.replace (if a String result is desired, or by replacing Set with List (so that the "additional" parameter is actually the first element in the list).

    0 讨论(0)
提交回复
热议问题