Перестройте массив так, чтобы arr [i] стал arr [arr [i]] с O (1) дополнительным пространством

Задача состоит в том, чтобы переупорядочить массив так, чтобы arr[i] стал arr[arr[i]] с дополнительным пространством O(1).

Пример:

2 1 3 5 4 0 

становится:

3 1 5 0 4 2

Я могу придумать решение O(n²). Решение O(n) было представлено здесь:

  • Увеличить каждый элемент массива arr[i] на (arr[arr[i]] % n)*n.
  • Разделите каждый элемент на n.

Но это очень ограничено, так как это вызовет переполнение буфера.

Может ли кто-нибудь придумать улучшение?

Ответ 1

Если значения в массиве все положительные (или все отрицательные), один из способов избежать переполнения может заключаться в том, чтобы запускать циклы перестановок и использовать знак integer для маркирования индексированных индексов. (В качестве альтернативы, если длина массива меньше 2 ^ (количество бит для одного элемента массива - 1), вместо использования знака, мы могли бы сдвинуть все значения на один бит влево и использовать первый бит для обозначения посещенных индексов.) Этот алгоритм приводит к как меньшим итерациям, так и меньшим изменениям исходных значений массива во время выполнения, чем алгоритм, который вы просите улучшить.

JSFiddle: http://jsfiddle.net/alhambra1/ar6X6/

Код JavaScript:

function rearrange(arr){
    var visited = 0,tmp,indexes,zeroTo

    function cycle(startIx){
        tmp = {start: startIx, value: arr[startIx]}
        indexes = {from: arr[startIx], to: startIx}

        while (indexes.from != tmp.start){
            if (arr[indexes.from] == 0)
                zeroTo = indexes.to
            if (indexes.to == visited){
                visited++
                arr[indexes.to] = arr[indexes.from]
            } else {
                arr[indexes.to] = -arr[indexes.from]
            }
            indexes.to = indexes.from
            if (indexes.from != tmp.start)
                indexes.from = arr[indexes.from]
        }

        if (indexes.to == visited){
            visited++
            arr[indexes.to] = tmp.value
        } else {
            arr[indexes.to] = -tmp.value
        }
    }

    while (visited < arr.length - 1){
        cycle(visited)

        while (arr[visited] < 0 || visited == zeroTo){
            arr[visited] = -arr[visited]
            visited++
        }
    }

    return arr
}