The problem can be divided into two tasks: (1) find all subsequences of an array of digits and (2) pack and unpack integers into digits.
Let's consider the subsequences of the array {a, b, c}
. You can generate them by walking through the array from left to right and follow two paths: One where you include the current element in a subsequence and one where you don't.
That leads to a recursive approach tat we can represent as a tree:
{}
/ \
{} {a}
/ \ / \
{} {b} {a} {ab}
/ \ / \ / \ / \
{} {c} {b} {bc} {a} {ac} {ab} {abc}
When we branch left, we skip the current element and when we go right, we include the element. The elements themselves are the depth of the tree: On the first level we treat element a
, on the next b
and on the last c
.
The bottom row has all subsequences. This includes the empty sequence and the full sequence, which you don't want. But let's include them for now. (The arrays in the bottom row are usually called a power set, which is a nice web-searchable term.)
I mentioned recursion, which entails recursive functions, and functions are out.
So we need to tackle the problem another way. Let's turn the tree on its side. A dash denotes that the element was skipped. The notation on the right uses another notation: 0
means the element was skipped, 1
means the element was included:
- - - 000
- - c 001
- b - 010
- b c 011
a - - 100
a - c 101
a b - 110
a b c 111
I hope the codes on the right look familiar, because that's how you count from 000
to 111
in binary. That's a nice way to enumerate our elements. Now we need a way to tell which bits are set in each number.
The rightmost bit is set when the number is odd. We can find out about the other bits by repeatedly dividing the number by two, which in binary is a shift to the right, discarding the rightmost bit.
Now how to extract the digits from the original number? That number is a decimal number; it's in base 10. We can use the same approach as for finding the bits in the binary number, because the bits 0 and 1 are the binary digits.
Start with the number. The last digit is the result of taking the remainder after a division by 10. Then divide the number by ten until it is zero. This code yields the digits from right to left. So does the code for finding the bits, which means we can find whether a bit is set and which digit to print in a single loop, always taking the rightmost bit and if it is set, print the rightmost digit of the original number.
The empty and the full subsequences are the first and last items in the enumeration. If you don't want them, skip them.
That leaves the problem of the duplicated subsequences if the digit has repeated digits. I don' see an easy way to solve this except user3629249's suggestion to create the subsequence anyway and later check whether is has already been printed.
An easy way to do this is to keep an array of the subsequences. That array has max
entries. After you have filled that array, sort it and then print it, but skip entries that are equal to the previous entry.
Here's an example implementation that uses an array of digits so that the original number doesn't have to be decomposed each time. It uses the sorting function qsort
from <stdlib.h>
, which requires a sorting function:
#include <stdlib.h>
#include <stdio.h>
#define NUM 412131
typedef unsigned int uint;
int uintcmp(const void *pa, const void *pb)
{
const uint *a = pa;
const uint *b = pb;
return (*a > *b) - (*a < *b);
}
int main(void)
{
uint digit[20]; // array of digits
size_t ndigit = 0; // length of array
uint num = NUM;
uint max = 1;
size_t i;
while (num) {
digit[ndigit++] = num % 10;
num /= 10;
max *= 2;
}
uint res[max]; // array of subsequences
for (i = 0; i < max; i++) {
uint mask = i; // mask for bit detection
uint j = ndigit; // index into digit array
uint s = 0;
while (j--) {
if (mask % 2) s = s*10 + digit[j];
mask /= 2;
}
res[i] = s;
}
qsort(res, max, sizeof(*res), uintcmp);
for (i = 1; i < max - 1; i++) {
if (res[i] != res[i - 1]) printf("%u\n", res[i]);
}
return 0;
}