2

Recently, I was asked to devise a function that would take a single string containing any of 1's, 0's, and ?'s (ex: "10?10?1", "00???11", "????", etc) as an input, and return a list of strings containing all the unique one-zero permutations of the input string.

For an input of "10?1?", the answer would be the list containing "10010", "10110", "10011", and "10111".

I was able to devise a function that did this, but it was brute force in nature and I am interested in a cleaner function that's O(2^n) in complexity. Providing an algorithm and/or implementation would be greatly appreciated, thank you!

templatetypedef
  • 362,284
  • 104
  • 897
  • 1,065
  • 3
    We're much more likely to be able to help you if you take a crack at the problem yourself and [describe what you've tried](http://whathaveyoutried.com). Check the Stack Overflow [question checklist](http://meta.stackexchange.com/questions/156810/stack-overflow-question-checklist) for more information on asking the right questions. Good luck and happy coding! – Christian Ternus Nov 01 '13 at 03:15
  • Especially with homework, or something similar. – Paul Draper Nov 01 '13 at 03:16
  • 3
    The answer is quite simple. Ignore the fixed 1s and 0s and count only the ?s. For N ? characters, increment an N-bit binary number through all its possibilities. Eg, for 3 ?s, increment through 000, 001, 010, 011, 100, 101, 110, and 111. Now substitute those bit patterns for the ?s. – Hot Licks Nov 01 '13 at 03:27

7 Answers7

2

I don't think you can do much better than a "brute force" implementation. For any such string that is provided containing N question marks, there will be 2^N unique permutations. Really, all you can do is to try all the different strings in whichever order you prefer. As to an algorithm:

  • Get pointers to all the places in the string where there is a question mark and store in an array.
  • Get an unsigned integer variable of bits that is longer than the number of question marks (use a long long to be safe); set to 0.
  • The bits in the variable represent all the possible combinations for the question marks. So use bitwise operations to substitute 1s and 0s in for the question marks, and each time increment the variable by 1.
  • Repeat 2^N times.
Zach Stark
  • 565
  • 3
  • 8
  • 1
    I think by brute force he meant `O(2^(size of string))` instead of `O(2^(number of question marks))`. – rliu Nov 01 '13 at 04:49
2

You can think of it as a tree where each node is a bit. Each question mark gives birth to 2 nodes: 0 and 1. Anything that is not a question mark is just a node with the same value. For example, for an input of 10?1?, the tree would expand like this:

enter image description here

Here's a C implementation:

void generate_str(char *str, int pos) {
    if (str[pos] == '\0') {
        printf("%s\n", str);
        return;
    }
    if (str[pos] == '?') {
        str[pos] = '0';
        generate_str(str, pos+1);
        str[pos] = '1';
        generate_str(str, pos+1);
        str[pos] = '?'; /* We can get back to this branch because of an earlier '?' */
    }
    else {
        generate_str(str, pos+1);
    }
}

Note that you must set a position back to '?' after exploring that branch, because you may be coming from another branch, and later you will need to recognize this same position as having a question mark again.

You can call this function like this:

int main(void) {
    char test[] = "10?1?";
    generate_str(test, 0);
    return 0;
}

You can't do any better than O(2^n), since you have to at least print the output.

Filipe Gonçalves
  • 20,783
  • 6
  • 53
  • 70
1

it will console such strings

 arr = "4646555?45656?564465?";
    function A(arr){var k = arr.indexOf("?");
    if(k != -1){
        R = arr.slice(0,k);
        L = arr.slice(k+1,arr.length);
        let M = R +"0"+ L;
        let N = R +"1"+ L;


        if(M.indexOf("?") != -1) A(M);
        else console.log(M)
        if(N.indexOf("?") != -1) A(N);
        else console.log(N)
    }
    }
    A(arr)
mukund patel
  • 1,039
  • 10
  • 31
1

I have a recursive solution for this

input_str = "10??01"

# 100001
# 100101
# 101001
# 101101

def solution(res, a, n):
  if n == 1 and a[0] != "?":
    print(res+a[0])
    return

  elif n == 1 and a[0] == "?":
    print(res+"0")
    print(res+"1")
    return


  if a[0] != "?":
    solution(res+a[0], a[1: ], len(a[1: ]))

  elif a[0] == "?":
    solution(res+"0", a[1: ], len(a[1: ]))
    solution(res+"1", a[1: ], len(a[1: ]))


solution("", input_str, len(input_str))
Jai
  • 3,211
  • 2
  • 17
  • 26
0

The general idea:

  • Create a function that takes a string or character array and a position.

  • Start off at position 0.

  • Increase the position until we find a ? at the position in the string.

  • If we're at the end of the string, output it and return.

  • Otherwise set the character at the position to 1 and recurse from the next position, then to 0 and recurse.

Complexity: O(size of string + 2^(number of question marks))

Bernhard Barker
  • 54,589
  • 14
  • 104
  • 138
0
var arr = "00?11?01";
var l = arr.match(/[?]/g).length; //no of question marks
var l1 = Math.pow(2, l); // 2^l
for (var i = 0; i < l1; i++) {
    var num = Number(i).toString(2); //convert to binary
    while (num.length < l) { num = '0' + num }; //append required zeros
    var j = -1;
    console.log(arr.replace(/[?]/g, function() {j++; return num[j];}));
}
0

Written in Java but can easily transformed to c++.

The basis is to separate the question marks ? to single values. Then put a single value (0 instead of all ?) in the list of combinations. Then iterate oven and over the list of combination, each time multiplying the number of values it holds using bitwise or on of the separated question marks ?.

We're doing the multiplication d times, where d is the number of question marks. Thus, we're running it roughly 2^d time, thus O(2^d). Smaller than O(2^n), if n is the input size.

The space complexity is the returned array - O(n * 2^d). 2^d Strings. Each string with the size of the input - n.

* I'f left out the calculation of merges if the input is larger than 64 bits.

public class BinaryCombinationsForQuestionMark {

    public static void main(String[] args) {
        System.out.println(Arrays.toString(getAllCombinations("1??")));
    }

    // TODO: If larger than 64 bit, separate to 64 and merge to original sizes
    public static int[] getAllCombinations(String input) {
        // TODO: Validate input
        // Doing up to 64 bits
        int numWithZerosAsQuestions = convertToNumWithQuestionsAsZeros(input);
        int[] separated = separateToOnesAsQuestions(input);

        List<Integer> combinations = new ArrayList<>();
        combinations.add(numWithZerosAsQuestions);
        for (int separate : separated) {
            // Prevents ConcurrentModificationException
            int size = combinations.size();
            for (int i = 0; i < size; i++) {
                int combination = combinations.get(i);
                combinations.add(combination | separate);
            }
        }
        return combinations.stream().mapToInt(i -> i).toArray();
    }

    private static int[] separateToOnesAsQuestions(String input) {
        ArrayList<Integer> separated = new ArrayList<>();
        for (int i = input.length() - 1; i >= 0; --i) {
            char c = input.charAt(i);
            if (c == '?') {
                separated.add(1 << input.length() - 1 - i);
            }
        }
        return separated.stream().mapToInt(i -> i).toArray();
    }

    private static int convertToNumWithQuestionsAsZeros(String input) {
        int num = 0;
        for (int i = 0; i < input.length(); ++i) {
            num <<= 1;
            char c = input.charAt(i);
            if (c == '1') num |= 1;
        }
        return num;
    }
}

Cheers.

AlikElzin-kilaka
  • 34,335
  • 35
  • 194
  • 277