Интервью, рекурсия + возвращение - PullRequest
14 голосов
/ 03 сентября 2011

Этот вопрос был задан в интервью и касается рекурсии / возврата. Предположим, у нас есть два массива логических значений: bool* source и bool* target, каждый из которых имеет одинаковую длину n (источник / цель / n указаны в качестве аргументов). Цель этого вопроса - преобразовать source в target с помощью операции switch .

  • Если есть несколько трансформ: представьте любое из них
  • Если решения не существует: утверждать, что решения не существует

Определение: операция switch(int i, bool* arr) инвертирует значение в arr [i] и arr [i-1] и arr [i + 1] (если эти индексы находятся в диапазоне 0 ... n -1). * * одна тысяча двадцать-три

Другими словами, операция switch обычно переворачивает три бита ( i и его соседей), но только два на концах.

Например:

  • switch (0, arr) будет переключать только значения arr [0] и arr [1]
  • switch (n-1, arr) переключит значения только arr [n-1] и arr [n-2]

Заранее спасибо за предложения по алгоритму.

Ответы [ 3 ]

5 голосов
/ 03 сентября 2011

Используя возврат, вы можете получить решение O (n). Почему?

  1. На один индекс у вас в худшем случае один переключатель
  2. Swicth по индексу может изменить только сам и два соседа.

Начиная слева, лучше всего двигаться вправо и вернуться назад.

В любое время вы должны вернуться максимум на два шага. Например, если вы находитесь в индексе n, вы можете изменить только индекс n-1, но не индекс n-2, и один раз. Точнее, когда вы достигнете индекса n + 2, вам нужно только проверить индекс n.

У вас может быть в худшем случае 2 решения.

Решение (в питоне)

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,[])

выход

[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]

Вы видите, что самым простым решением было бы просто запустить два цикла for. Первое решение установить первый свет / выключатель, а второй нет. Все остальные переключения затем решаются

#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()
4 голосов
/ 03 сентября 2011

Насколько я понимаю, главное наблюдение состоит в том, что нам никогда не нужно выполнять более одного переключения в любой позиции.Это связано с тем, что переключение дважды - это то же самое, что переключение вообще не так, поэтому все четные переключатели эквивалентны переключателям 0, а все нечетные переключатели равны 1 переключателю.

Другое дело, что порядок переключателей нене имеет значения.переключение i-го и i + 1-го элементов аналогично переключению i + 1-го и затем i-го.Шаблон, полученный в конце, один и тот же.

Используя эти два наблюдения, мы можем просто попробовать все возможные способы применения переключения к массиву длины n.Это можно сделать рекурсивно (то есть выполнить переключение по индексу i / не выполнить переключение по индексу i, а затем попробовать i + 1) или перечислить все 2 ** nn битовые маски и использовать их для применения переключателей до тех пор, пока один из них не создастцелевое значение.

Ниже приведено описание моего решения.Я упаковал массивы в целые и использовал их в качестве битовых масок для упрощения операций.Это распечатывает индексы, которые необходимо переключить, чтобы получить целевой массив, и печатает «Невозможно», если цель недоступна.

#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;
}
1 голос
/ 05 сентября 2011

Откат не требуется.

Легко видеть, что для N = 3k и N = 3k + 1 (k> 0) возможно переключить каждый отдельный бит, поэтому для этих размеров решение всегда существует. Легко придумать один, складывая решения для каждого бита, который нам нужно перевернуть.

Для 3k + 2 элементов возможно перевернуть некоторые биты по отдельности, а другие попарно. А именно, мы можем перевернуть либо биты 2, 5, 8 ... по отдельности, либо любые два из 0, 1, 3, 4, 6, ... одновременно. Таким образом, решение существует только тогда и только тогда, когда в позициях 0, 1, 3, 4, 6, 8 есть четное число битов, которые необходимо перевернуть. Опять же, легко придумать алгоритм для каждой пары битов. Добавьте их, чтобы получить решение.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...