将所有奇数定位元素移动到左半边,甚至定位到右半边

时间:2012-09-09 11:24:35

标签: performance algorithm data-structures time-complexity in-place

给定一个具有正整数和负整数的数组,将所有奇数索引元素移到左边,甚至将索引元素移到右边。

问题的难点在于在维持秩序的同时就地进行。

e.g。

7, 5, 6, 3, 8, 4, 2, 1

输出应为:

5, 3, 4, 1, 7, 6, 8, 2

如果顺序无关紧要,我们可以使用快速排序的partition()算法。

如何在O(N)中完成?

5 个答案:

答案 0 :(得分:7)

  1. 获得大小为3 k +1
  2. 的最大子阵列
  3. 将循环引导算法应用于该子阵列的各个部分,从位置1,3,9开始... 3 k-1 :将元素移动到子阵列中的正确位置(子阵列左侧的偶数索引元素,奇数索引 - 右侧),替换元素也应移动到其正确位置等,直到此过程返回到起始位置。 This paper给出了数论解释,为什么这样选择起始位置会将子阵列改组为正确的顺序。
  4. 使用步骤1和2递归处理数组的其余部分。
  5. 现在我们只需要将重新排序的部分加在一起。从整个数组末尾的较小子数组开始。要交换子阵列的一半,请使用反向算法:reverse(reverse(a),reverse(b));或者,对于相同大小的子阵列,使用成对交换。
  6. 现在所有偶数位置元素都在左侧。为了使它们在右边,根据需要,交换元素i和i + N / 2,所有i = 0 .. N / 2-1。
  7. 算法就位,时间复杂度为O(N)。

    示例:

    0 1 2 3 4  5 6 7 8 9   10 11 (the original array)
    0 1 2 3 4  5 6 7 8 9 # 10 11 (split to sub-arrays)
    0 2 4 3 8  1 6 5 7 9 # 10 11 (first cycle leader iteration, starting with 1)
    0 2 4 6 8  1 3 5 7 9 # 10 11 (second cycle leader iteration, starting with 3)
    0 2 4 6 8  9 7 5 3 1 # 10 11(2nd half of 1st part& 1st half of 2nd part reversed)
    0 2 4 6 8 10 1 3 5 7    9 11 (both halves reversed together)
    

    此算法的变化,不需要第5步:

    • 在步骤1中,获得大小为3 k -1的最大子阵列。
    • 在步骤2中,将偶数索引元素移动到子数组的右侧,奇数索引 - 向左移动。使用起始位置0,2,8,... 3 k-1 -1进行循环引导算法。

    这是不同的O(N log N)就地算法,不需要数论证明:

    1. 将数组重新解释为一系列单元素2 * 2矩阵,转置这些矩阵。
    2. 将结果重新解释为一系列双元素2 * 2矩阵并转置它们。
    3. 当矩阵大小小于数组大小时继续。
    4. 现在我们只需要将重新排序的部分加在一起(与以前的算法完全相同)。
    5. 交换阵列左右两半的元素(与以前的算法完全相同)。
    6. 示例:

      0  1   2 3   4 5   6 7  (the original array)
      [0 2] [1 3] [4 6] [5 7] (first transposition)
      [0 2] [4 6] [1 3] [5 7] (second transposition)
      

      此问题只是In-place matrix transposition的一个特例。

答案 1 :(得分:1)

我试图实施,因为Evgeny Kluev说,结果如下:

#pragma once

#include <iterator>
#include <algorithm>
#include <type_traits>
#include <limits>
#include <deque>
#include <utility>

#include <cassert>

template< typename Iterator >
struct perfect_shuffle_permutation
{

    static_assert(std::is_same< typename std::iterator_traits< Iterator >::iterator_category, std::random_access_iterator_tag >::value,
                  "!");

    using difference_type = typename std::iterator_traits< Iterator >::difference_type;
    using value_type = typename std::iterator_traits< Iterator >::value_type;

    perfect_shuffle_permutation()
    {
        for (difference_type power3_ = 1; power3_ < std::numeric_limits< difference_type >::max() / 3; power3_ *= 3) {
            powers3_.emplace_back(power3_ + 1);
        }
        powers3_.emplace_back(std::numeric_limits< difference_type >::max());
    }

    void
    forward(Iterator _begin, Iterator _end) const
    {
        return forward(_begin, std::distance(_begin, _end));
    }

    void
    backward(Iterator _begin, Iterator _end) const
    {
        return backward(_begin, std::distance(_begin, _end));
    }

    void
    forward(Iterator _begin, difference_type const _size) const
    {
        assert(0 < _size);
        assert(_size % 2 == 0);
        difference_type const left_size_ = *(std::upper_bound(powers3_.cbegin(), powers3_.cend(), _size) - 1);
        cycle_leader_forward(_begin, left_size_);
        difference_type const rest_ = _size - left_size_;
        if (rest_ != 0) {
            Iterator middle_ = _begin + left_size_;
            forward(middle_, rest_);
            std::rotate(_begin + left_size_ / 2, middle_, middle_ + rest_ / 2);
        }
    }

    void
    backward(Iterator _begin, difference_type const _size) const
    {
        assert(0 < _size);
        assert(_size % 2 == 0);
        difference_type const left_size_ = *(std::upper_bound(powers3_.cbegin(), powers3_.cend(), _size) - 1);
        std::rotate(_begin + left_size_ / 2, _begin + _size / 2, _begin + (_size + left_size_) / 2);
        cycle_leader_backward(_begin, left_size_);
        difference_type const rest_ = _size - left_size_;
        if (rest_ != 0) {
            Iterator middle_ = _begin + left_size_;
            backward(middle_, rest_);
        }
    }

private :

    void
    cycle_leader_forward(Iterator _begin, difference_type const _size) const
    {
        for (difference_type leader_ = 1; leader_ != _size - 1; leader_ *= 3) {
            permutation_forward permutation_(leader_, _size);
            Iterator current_ = _begin + leader_;
            value_type first_ = std::move(*current_);
            while (++permutation_) {
                assert(permutation_ < _size);
                Iterator next_ = _begin + permutation_;
                *current_ = std::move(*next_);
                current_ = next_;
            }
            *current_ = std::move(first_);
        }
    }

    void
    cycle_leader_backward(Iterator _begin, difference_type const _size) const
    {
        for (difference_type leader_ = 1; leader_ != _size - 1; leader_ *= 3) {
            permutation_backward permutation_(leader_, _size);
            Iterator current_ = _begin + leader_;
            value_type first_ = std::move(*current_);
            while (++permutation_) {
                assert(permutation_ < _size);
                Iterator next_ = _begin + permutation_;
                *current_ = std::move(*next_);
                current_ = next_;
            }
            *current_ = std::move(first_);
        }
    }

    struct permutation_forward
    {

        permutation_forward(difference_type const _leader, difference_type const _size)
            : leader_(_leader)
            , current_(_leader)
            , half_size_(_size / 2)
        { ; }

        bool
        operator ++ ()
        {
            if (current_ < half_size_) {
                current_ += current_;
            } else {
                current_ = 1 + (current_ - half_size_) * 2;
            }
            return (current_ != leader_);
        }

        operator difference_type () const
        {
            return current_;
        }

    private :

        difference_type const leader_;
        difference_type current_;
        difference_type const half_size_;

    };

    struct permutation_backward
    {

        permutation_backward(difference_type const _leader, difference_type const _size)
            : leader_(_leader)
            , current_(_leader)
            , half_size_(_size / 2)
        { ; }

        bool
        operator ++ ()
        {
            if ((current_ % 2) == 0) {
                current_ /= 2;
            } else {
                current_ = (current_ - 1) / 2 + half_size_;
            }
            return (current_ != leader_);
        }

        operator difference_type () const
        {
            return current_;
        }

    private :

        difference_type const leader_;
        difference_type current_;
        difference_type const half_size_;

    };

    std::deque< difference_type > powers3_;

};

答案 2 :(得分:0)

我修改了代码here以获得此算法:

void PartitionIndexParity(T arr[], size_t n)
{
    using std::swap;
    for (size_t shift = 0, k; shift != n; shift += k)
    {
        k = (size_t)pow(3, ceil(log(n - shift) / log(3)) - 1) + 1;
        for (size_t i = 1; i < k; i *= 3)  // cycle-leader algorithm
        {
            size_t j = i;
            do { swap(arr[(j = j / 2 + (j % 2) * (k / 2)) + shift], arr[i + shift]); } while (j != i);
        }

        for (size_t b = shift / 2, m = shift, e = shift + (k - k / 2), i = m; shift != 0 && k != 0; )  // or just use std::rotate(arr, b, m, e)
        {
            swap(arr[b++], arr[i++]);
            if (b == m && i == e) { break; }
            if (b == m) { m = i; }
            else if (i == e) { i = m; }
        }
    }
}

答案 3 :(得分:0)

这是Peiyush Jain算法的Java实现:

public static <T> void outShuffle(T[] array) {
    if (array == null) {
       return;
    }

    inShuffle(array, 1, array.length - 1);
}

进行彻头彻尾的洗牌非常简单:

$(document).ready(function () {
    // CHANGE THIS LINE --> Try adding the "input" and remove the quotes (not 100% necessary)
    $("input[name=personal_theme_color]").click(function () {
        // CHANGE THIS LINE --> Use "$(this)" to localize the selection
        var ptcval = $(this).val();
        // ADD THIS LINE --> Make "var color" a preset
        // You could also just do "var color;"
        var color = "#FFF";

        switch (ptcval) {
            case "pink":
                // CHANGE THIS LINE --> adding "var color" here will only work if click "pink"
                color = '#e91e63';
                break;

            case "purple":
                color = '#9c27b0';
                break;

            case "deep-purple":
                color = "#673ab7";
                break;

            case "indigo":
                color = "#3f51b5";
                break;

            case "light-blue":
                color = "#03a9f4";
                break;

            case "cyan":
                color = "#00bcd4";
                break;

            case "green":
                color = "#4caf50";
                break;

            case "light-green":
                color = "#8bc34a";
                break;

            case "lime":
                color = "#cddc39";
                break;

            case "yellow":
                color = "#ffeb3b";
                break;

            case "amber":
                color = "#ffc107";
                break;

            case "orange":
                color = "#ff9800";
                break;

            case "deep-orange":
                color = "#ff5722";
                break;

            case "brown":
                color = "#9e9e9e";
                break;

            case "grey":
                color = "#9e9e9e";
                break;
        }

        $('.nav-wrapper').animate({
            backgroundColor : color
        });
        $('footer').animate({
            backgroundColor : color
        });

        $.ajax({
            type: "POST",
            url: 'jsp/update_user_theme.php',
            // CHANGE THIS LINE --> send an object instead of string
            data: { theme: ptcval },
            cache: false,
            success: function (response) {
                alert('Updated successfully');
            }
        });
    });
});

答案 4 :(得分:0)

public class OddToLeftEvenToRight {

    private static void doIt(String input){

        char[] inp = input.toCharArray();
        int len = inp.length;

        for(int j=1; j< len; j++)
        {
            for(int i=j; i<len-j; i+=2)
            {

                swap(inp, i, i+1);

            }
        }

        System.out.print(inp);

    }

    private static void swap(char[] inp, int i, int j) {

        char tmp = inp[i];
        inp[i]= inp[j];
        inp[j]=tmp;

    }

    public static void main(String[] args)
    {

        doIt("a1b");
    }

}

该程序在O(n ^ 2)中完成。