The problem is to implement a function that outputs all possible combinations of the characters in a string (with length ranging from one to the length of the string). Unlike permutations, two combinations are considered to be the same if they contain the same characters, but in a different order. Another way to define the problem is to find the power set of the characters of the string (excluding the empty set).
Like the previous exercise, this one is also from the book Programming Interviews Exposed by John Mongan and Noah Suojanen[1]\(\).
To begin with, let’s consider an example. What are the combinations of the string “abcde”? Since the ordering of the letters within the combinations don’t matter, let’s keep the letters in the same order as in the original string. Also, for now, let’s include the empty string as one of the combinations, for simplicity. Then it’s clear that there are \(2^{5} = 32\) combinations, since each of the \(5\) letters can be either included or excluded. (For an input string of length \(n\), there will be \(2^{n}\) combinations, including the empty string.)
The letter “a” will be included in half of the combinations, and excluded in the other half. (Of course, this is also true of each of the other letters.) In fact, those combinations that exclude “a” are just the combinations of the string “bcde”, and those that include “a” are exactly these same combinations, but prefixed with “a”. This gives an obvious recursive solution to the problem.
Expressed in Scheme, the program looks like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | (define (power-set the-set) (if (null? the-set) '(()) (let ( (power-set-of-subset (power-set (cdr the-set))) (prepend-excluded (lambda (subset) (cons (car the-set) subset))) ) (append power-set-of-subset (map prepend-excluded power-set-of-subset) ) ) ) ) (define (combinations the-string) (map (lambda (s) (apply string s)) (cdr (power-set (string->list the-string))) ) ) (define test-input "abcde") (display (combinations test-input)) |
The combinations function just converts the input string to a list of letters, applies power-set to the list, and converts the result back into a list of strings. (The empty set is excluded by applying cdr, since it is the first item in the list returned by power-set by design.)
The power-set function is pretty straightforward. It computes the power set of the subset that excludes the first letter (with a recursive call), then returns a set consisting of the elements of this power set along with these elements prepended with the excluded letter. The base case is slightly tricky: the power set of the empty set is not the empty set, but a set containing only the empty set.
(Aside: I wish that the higher-order functions map and fold/reduce had better names — especially “map”, a word that is used for just too many things.)
The same program can be written in Python as follows:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | def combinations(input_string): def combinations_helper(set_of_chars): if set_of_chars == "": return [""] else: combinations_of_subset = combinations_helper(set_of_chars[1:]) combinations_of_subset.extend( map( lambda t: set_of_chars[0] + t, combinations_of_subset) ) return combinations_of_subset return combinations_helper(input_string)[1:] test_input = "abcde" print combinations(test_input) |
The Python program uses string manipulation operations (string slicing, concatenation) instead of treating the input as a list as the Scheme program does. The idea, however, is exactly the same.
There are probably more efficient ways to write these programs in these languages. In particular, the conversions between strings and lists (in Scheme) and the string manipulation operations (in Python) may be expensive.
What I like about the idea behind the above programs is that the result of the computation for the combinations excluding a character are re-used when computing the combinations including it. This saves on a lot of recursive calls.
The “obvious” solution to the same problem in C++ is the following:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | #include<iostream> #include<string.h> using namespace std; void print_combinations_helper(char *input, char *output, int len, int depth, int start) { // The variable depth holds the recursion depth, or, equivalently, // the index into the output string of the character that's being // generated. The variable start is the index of the first of // the still available letters. // At the current depth, cycle through the still available letters. for( int i = start; i < len; i++ ) { output[depth] = input[i]; print_combinations_helper(input, output, len, depth+1, i+1); } output[depth] = '\ 0'; cout << output << endl; } void print_combinations(char *input) { // Allocate a new character buffer to hold the output. (Assume // that this always succeeds, or that error handling is being // taken care of elsewhere.) int len = strlen(input); char *output = new char[len+1]; // Recursively print the combinations, starting with the first // character. print_combinations_helper(input, output, len, 0, 0); // Free the memory for the output buffer. delete output; } int main() { char test_input[] = "abcde"; print_combinations(test_input); } |
The above program actually also prints out the empty string as one of the combinations, but this can be easily fixed by an if clause, or by relocating the cout statement (lines 18–19) inside the loop (at line 16, and substituting depth+1 for depth). The reason that I didn’t write the program that way is because then the combinations would have been output in a very different order compared to the above Scheme/Python programs. (The way it’s written now, the output is actually in exactly the reverse order, but that’s good enough for comparison purposes.)
While the recursive function is called only \(n+1\) times in the Scheme/Python programs (once for each character and once more for the empty set), the C++ program makes a total of \(2^{n}\) calls to the recursive helper function. On the other hand, while the Scheme/Python programs have to keep \(2^{n}\) items in memory (each of which is \(O(n)\) in size), the C++ program prints each combination as soon as it has been computed and thus uses only \(O(n)\) memory.
Personally, I prefer the solution used in the Scheme program because I find it conceptually much more elegant. It would also be preferably if recursive function calls are expensive for some reason. However, the solution used in the C++ program is better if memory is limited, or if the combinations do not need to be retained in memory after they have been printed.
Of course, one can write the first program in C++ or the second one in Scheme, but the point is that the two solutions are, in some sense, the more “natural” ones for their respective languages.
– davinci 11803

Write a program to read array values and display output as given below….
there are N no of values and N no of arrays..
Input
Enter no of arrays: 2
value of first array:1,2
value of second array:3,4
enter array {{1,2}{3,4}}
output:
13
14
23
24
can u help me out wit s\dis prog???????????
No, I’m not doing your homework for you.
– davinci