1

Imagine you have two binary strings, a and b, given as input. a and b are both of the same length.
The objective is to find the minimum number of flips required to make a equal b, WITHOUT a ever having three of the same bit consecutively (e.g. 000 or 111 appearing anywhere in a is disallowed). Also, you may flip only one bit at a time. The input strings also never have three of the same bit appearing consecutively when they are given. b is immutable.

For example:
a = 0011
b = 0101

0011 -> 0010 -> 0110 -> 0100 -> 0101 (output: 4)

You could not go from 0011 to 0111, because then there would be three 1 bits in the string.

I'm not sure how to approach solving this problem, honestly. I think that a solution may involve dynamic programming, through.

  • There is the naive bruteforce approach of doing a breadth-first-search from a, and stopping when you arrive at b. The complexity is `2**k` where k is the answer (the minimum number of flips). Then there is the "smart bruteforce" approach of doing a breadth-first-search from a, and a breadth-first-search from b, and stopping when they intersect each-other. The complexity is `2**(k/2 + 1)` which is already a huge gain. – Stef Feb 22 '23 at 11:00
  • I feel as though there may be some cases where if you just stop upon arriving at `b`, it won't actually be the minimum amount of flips required, i.e., there may be another solution which requires less bit flips. I do not know how to solve this problem efficiently. – d0057b5bfe0ab457028b6ce41b86b6 Feb 22 '23 at 17:40
  • No. The whole point of breadth-first-search is that it explores the shortest paths first. When you've reached b, you've reached it via the shortest path. – Stef Feb 23 '23 at 10:00

1 Answers1

0

well, i came back to this problem after a break and it wasn't actually hard. here's what i came up with:

function flip(c) {
    switch (c) {
        case "0": return "1";
        case "1": return "0";
        default: throw new Error("invalid character");
    }
}
function cloneFlip(str, idx) {
    let arr = str.split("");
    let c = arr[idx];
    arr[idx] = flip(c);
    return arr.join("");
}

function three(str) {
    for (let idx = 0; idx < str.length - 2; ++idx) {
        if (["000", "111"].includes(str.substring(idx, idx + 3))) {
            return true;
        }
    }
    return false;
}

function doStep(a, seen, currMut, queue/*, prev*/) {
    let length = a.length;

    for (let idx = 0; idx < length; ++idx) {
        let str = cloneFlip(a, idx);
        if (three(str)) {
            continue;
        }

        if (!seen.has(str)) {
            seen.add(str);
            queue.push([str, currMut]);
            /*let p = prev[str];
            if (!p || currMut - 1 < p.step) {
                prev[str] = { a, step: currMut - 1, };
            }*/
        }
    }

    return;
}

function go(a, b) {
    if (a.length != b.length) {
        throw new Error("length mismatch");
    }

    let queue = [];
    let seen = new Set(a);
    doStep(a, seen, 1, queue);

    let arr = [];
    while (queue.length) {
        let [str, muts] = queue.shift();
        if (str === b) {
            return muts;
        }
        doStep(str, seen, muts + 1, queue);
    }

    throw new Error("unreachable");
}