Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Interview question, recursion + backtracking

This question was asked in interview and deals with recursion/backtracking. Suppose we have two arrays of booleans:bool* source and bool* target,each of them the same length n(source/target/n are given as arguments). The goal of the question is to transform source to target using operation switch.

  • If there are several transforns: present any one of them
  • If there is no solution: assert that there is no solution

Definition: operation switch(int i, bool* arr) inverts the value at arr[i] and arr[i-1] and arr[i+1] (if these indices are in the range 0...n-1).

In other words, switch operation will usually flip three bits (i and its neighbors), but only two at the ends.

For example:

  • switch(0,arr) will switch the values of arr[0] and arr[1] only
  • switch(n-1,arr) will switch the values of arr[n-1] and arr[n-2] only

Thank you in advance for the suggestions about the algorithm.

like image 331
Yakov Avatar asked Sep 03 '11 08:09

Yakov


People also ask

What is recursion with backtracking?

Difference between Recursion and Backtracking: In recursion, the function calls itself until it reaches a base case. In backtracking, we use recursion to explore all the possibilities until we get the best result for the problem.

Is backtracking important for interview?

To ace your coding interview for a software engineering job, you'll need to understand backtracking. Backtracking is a technique that solves a problem by exploring possible solutions to its sub-problems, abandoning any that will not lead to a valid solution.

Why do backtracking algorithms use recursion?

Backtracking uses recursion to solve it's problems. It does so by exploring all the possiblities of any problem, unless it finds the best and feasible solution to it. Recursion occurs when a function calls itself repeatedly to split a problem into smaller sub-problems, until it reaches the base case.

Is recursion asked in interview?

Recursion is the first step of the FAST Method. Suffice to say, it is absolutely essential that you be prepared to solve recursion interview questions in your interview. It is almost guaranteed that you will see at least one or two recursive problems at any given onsite interview.


2 Answers

Using backtracking you can have O(n) solution. Why?

  1. At single index you have at worst one switch
  2. Swicth at index can change only self and two neigboughrs.

Starting at left an moving right and backtracking is best approach.

At any time time you have to go back at most by two steps. For instance if you are at index n, you can change only index n-1, but not index n-2 and once Or more precisely when you reach index n+2 you only have to check index n.

You can have at worst 2 solutions.

Solution (in python)

def light(arr,n):
    for i in range(max([0,n-1]),min([len(arr),n+2])):
        arr[i] = not arr[i]
    return arr

goal = [True]*500
def trackback(arr,index,moves):
    if index == len(arr):
        if arr == goal:
            print(moves)
        return

    if index > 1:
        if arr[index-2] != goal[index-2]:
            return
    #print(arr,index,moves)
    #do not make switch
    trackback(arr,index+1,moves)
    #make switch
    moves=moves+[index]
    arr=light(arr,index)
    trackback(arr,index+1,moves)
    arr=light(arr,index) #undo move


arr=[False]*500
trackback(arr,0,[])

output

[1, 4, 7, 10, 13, 16, 19, 22, 25, 28, 31, 34, 37, 40, 43, 46, 49, 52, 55, 58, 61, 64, 67, 70, 73, 76, 79, 82, 85, 88, 91, 94, 97, 100, 103, 106, 109, 112, 115, 118, 121, 124, 127, 130, 133, 136, 139, 142, 145, 148, 151, 154, 157, 160, 163, 166, 169, 172, 175, 178, 181, 184, 187, 190, 193, 196, 199, 202, 205, 208, 211, 214, 217, 220, 223, 226, 229, 232, 235, 238, 241, 244, 247, 250, 253, 256, 259, 262, 265, 268, 271, 274, 277, 280, 283, 286, 289, 292, 295, 298, 301, 304, 307, 310, 313, 316, 319, 322, 325, 328, 331, 334, 337, 340, 343, 346, 349, 352, 355, 358, 361, 364, 367, 370, 373, 376, 379, 382, 385, 388, 391, 394, 397, 400, 403, 406, 409, 412, 415, 418, 421, 424, 427, 430, 433, 436, 439, 442, 445, 448, 451, 454, 457, 460, 463, 466, 469, 472, 475, 478, 481, 484, 487, 490, 493, 496, 499]
[0, 3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 36, 39, 42, 45, 48, 51, 54, 57, 60, 63, 66, 69, 72, 75, 78, 81, 84, 87, 90, 93, 96, 99, 102, 105, 108, 111, 114, 117, 120, 123, 126, 129, 132, 135, 138, 141, 144, 147, 150, 153, 156, 159, 162, 165, 168, 171, 174, 177, 180, 183, 186, 189, 192, 195, 198, 201, 204, 207, 210, 213, 216, 219, 222, 225, 228, 231, 234, 237, 240, 243, 246, 249, 252, 255, 258, 261, 264, 267, 270, 273, 276, 279, 282, 285, 288, 291, 294, 297, 300, 303, 306, 309, 312, 315, 318, 321, 324, 327, 330, 333, 336, 339, 342, 345, 348, 351, 354, 357, 360, 363, 366, 369, 372, 375, 378, 381, 384, 387, 390, 393, 396, 399, 402, 405, 408, 411, 414, 417, 420, 423, 426, 429, 432, 435, 438, 441, 444, 447, 450, 453, 456, 459, 462, 465, 468, 471, 474, 477, 480, 483, 486, 489, 492, 495, 498]

You can see that simplest solution would be just running two for loops. First solution set first light/switch and second does not. All remaining switching are then decided

#do not switch first light
for i in range(1,len(goal)+1):
    if goal[n-1] != arr[n-1]:
        light(arr,n)
check_solution()

#switch first light
switch(arr,n)
for i in range(1,len(goal)+1):
    if goal[n-1] != arr[n-1]:
        light(arr,n)
check_solution()
like image 177
Luka Rahne Avatar answered Oct 11 '22 01:10

Luka Rahne


As far as I understand the problem, the main observation is that we never need to perform more than one switch on any position. This is because switching twice is the same as not switching at all, so all even switches are equivalent to 0 switches and all odd switches are as good as 1 switch.

Another thing is that the order of the switches don't matter. switching the i-th and i+1-th elements is the same as switching i+1-th and then the i-th. The pattern obtained at the end is the same.

Using these two observations, we can simply try out all possible ways of applying switch to the n length array. This can be done recursively (i.e. doing a switch at index i/not doing a switch at index i and then trying out i+1) or by enumerating all 2**n n bit bitmask and using them to apply switches until one of them creates the target value.

Below is my hack at the solution. I have packed the arrays into ints and used them as bitmasks to simplify the operations. This prints out the indices that need to be switched to get the target array and prints "Impossible" if the target is not obtainable.

#include <cstdio>

int flip(int mask, int bit){
    return mask^(1<<bit);
}

int switch_(int mask, int index, int n){
    for(int i=-1;i<=+1;i++){
        if ((index+i)>=0 && (index+i)<n) mask=flip(mask,index+i);
    }
    return mask;
}

int apply(int source, int flips, int n){
    int result=source;
    for(int i=0;i<n;i++){
        if (flips&(1<<i)) result=switch_(result,i,n);
    }
    return result;
}

void solve(int source, int target, int n){
    bool found=false;
    int current=0;
    int flips=0;
    for(flips=0;flips<(1<<n) && !found;flips++){
        current=apply(source,flips,n);
        found=(current==target);
    }
    if (found){
        flips--;
        for(int i=0;i<n;i++){
            if (flips&(1<<i)) printf("%d ",n-i-1); //prints the indices in descending order
        }
        printf("\n");
    }
    else{
        printf("Impossible\n");
    }
}

int array2int(int* arr, int n){
    int ret=0;
    for(int i=0;i<n;i++){
        ret<<=1;
        if (arr[i]==1) ret++;
    }
    return ret;
}
int main(){
    int source[]={0,0,0,0};
    int target[]={1,1,1,1};
    int n=4;
    solve(array2int(source,n),array2int(target,n),n);
    return 0;
}
like image 43
MAK Avatar answered Oct 11 '22 02:10

MAK