Vikash
Vikash

Reputation: 2163

Removing an input from a recursive method

Good morning! I received a problem statement to write a method that returns all possible combinations of a String input passed, e.g.

if ABC is passed then it returns [A, AB, BC, ABC, AC, B, C] if ABCD is passed then it returns [A, AB, BC, CD, ABC, AC, ACD, B, BCD, BD, ABD, AD, C, D, ABCD]

means AB and BA are always taken same, ABC, BAC and ACB are also same.

I ended up writing below code and it seems to working though (not sure).

public static Set<String> getAnyPermutations(String s,String strInput) {
    Set<String> resultSet = new HashSet<>();
    char[] inp = strInput.toCharArray();
    for(int i=0; i<inp.length; i++) {
        String temp =s+String.valueOf(inp[i]);
        resultSet.add(temp);
        if(i+1<=inp.length)
            resultSet.addAll(getAnyPermutations(temp, String.valueOf(Arrays.copyOfRange(inp, i+1, inp.length))));
    }
    return resultSet; 
}

My question is, I want to remove the first param(String s) from the method as using it for interal comutations only, or if that is not possible then making sure that user always pass a "" value or I can reset it to "" for the first(non-recursive) call of this method. I am going confused how to do that inside a recursive funtion. Also please add comment if you have doubt it can fail other than this situation.

Conditions, All has to be done inside this function only, no other method can be created.

Upvotes: 2

Views: 144

Answers (4)

slim
slim

Reputation: 41223

You can rewrite this particular algorithm so that it doesn't need to carry a state through to the recursively called invocation.

(Java-centric pseudocode):

Set<String> getAnyPermutations(String str) {
    if(str.length() == 0) {
        return Collections.emptySet();
    }

    String head = str.substring(0,1);
    String tail = str.substring(1);

    Set<String> permutationsOfTail = getAnyPermutations(tail);

    Set<String> result = new HashSet();

    // Head on its own
    // For input 'ABC', adds 'A'
    result.add(head);

    // All permutations that do not contain head
    // For input 'ABC', adds 'B', 'C', 'BC'
    result.addAll(permutationsOfTail);

    // All permutations that contain head along with some other elements
    // For input 'ABC', adds 'AB, 'AC', 'ABC'
    for(String tailPerm : permutationsOfTail) {
       result.add(head + tailPerm);
    }

    return result;
}

This meets your aim of not creating any extra methods -- but note that it would be cleaner code if the for loop was extracted into a new method Set<String> prefixEachMember(String prefix, Set<String> strings) allowing result.addAll(prefixEachMember(head,permutationsOfTail)).


However it's not always possible to do this, and sometimes you do want to carry state. One way is the way you've asked to avoid, but I'm going to include it in my answer because it's a clean and common way of achieving the aim.

 public Foo myMethod(Bar input) {
      return myMethod(new HashSet<Baz>(), input);
 }

 private Foo myMethod(Set<Baz> state, Bar input) {
      if(...) {
          return ...;
      } else {
          ...
          return myMethod(..., ...); 
      }
 }

Here, the first method is your public API, in which the collector/state parameter is not required. The second method is a private worker method, which you initially call with an empty state object.

Another option is to refer to an object field. I would recommend against this, however, because it gets confusing when recursive code refers to a global object.

Upvotes: 2

danbanica
danbanica

Reputation: 3038

You can always transform a recursive method into its iterative equivalent - e.g. see Way to go from recursion to iteration.

In the iterative version it's easy to not expose the state parameter (you now just need to initialize it at the beginning of the iterative method).

This is not very practical in general (but I believe that the purpose of the question is more theoretical, otherwise it's always a good solution to just expose another method).

Furthermore, in this particular situation you might consider this simple iterative approach (though it is not obtained by directly translating the given code):

public static Set<String> getAnyPermutations(String strInput) {
    Set<String> resultSet = new HashSet<>();
    char[] inp = strInput.toCharArray();

    for (int bitMask = 0; bitMask < (1 << inp.length); bitMask++) {
        StringBuilder str = new StringBuilder();
        for (int i = 0; i < inp.length; i++) {
            if ((bitMask & (1 << i)) != 0) {
                str.append(inp[i]);
            }
        }

        if (str.length() > 0) {
            resultSet.add(str.toString());
        }
    }

    return resultSet;
}

Upvotes: 2

Darshan Mehta
Darshan Mehta

Reputation: 30819

You can change the current method to be a private one and interface it with a public method with one argument e.g.:

private static Set<String> getAnyPermutations(String s,String strInput) {
    Set<String> resultSet = new HashSet<>();
    char[] inp = strInput.toCharArray();
    for(int i=0; i<inp.length; i++){
        String temp =s+String.valueOf(inp[i]);
        resultSet.add(temp);
        if(i+1<=inp.length)
            resultSet.addAll(getAnyPermutations(temp, String.valueOf(Arrays.copyOfRange(inp, i+1, inp.length))));
    }
    return resultSet; 
}

Now, you can expose a one argument method to the user which in turn will call the above method, e.g.:

public static Set<String> getAnyPermutations(String strInput) {
    return getAnyPermutations("", strInput);
}

Update

If you can't create any other method at all then the only alternative would be to use var-args. However, that requires change in the implementation and doesn't actually restrict the user from passing multiple values.

Upvotes: 2

T.J. Crowder
T.J. Crowder

Reputation: 1074475

All has to be done inside this function only, no other function can be created.

Then you can't do it. The function has no (reasonable)* way of knowing whether it called itself or was called by another function.

There are lots of solutions involving creating another function. One that might fit your requirements, depending on how they're actually expressed, would be to have the function define a lambda to do the work, and have the lambda call itself. E.g., getAnyPermutations wouldn't actually be recursive, it would contain a recursive function.

But that may be out of bounds depending on the exact meaning of the quote above, since the lambda is another function, just not one that can be accessed from the outside.


* The unreasonable way is by examining a stack trace, which you can get from Thread.currentThread().getStackTrace.

Upvotes: 4

Related Questions