Fastest algorithm for circle shift N sized array for M position

后端 未结 24 2974
温柔的废话
温柔的废话 2020-11-28 05:33

What is the fastest algorithm for circle shifting array for M positions?
For example, [3 4 5 2 3 1 4] shift M = 2 positions should be [1 4 3 4 5 2 3

相关标签:
24条回答
  • 2020-11-28 05:57

    Here is a nother one (C++):

    void shift_vec(vector<int>& v, size_t a)
    {
        size_t max_s = v.size() / a;
        for( size_t s = 1; s < max_s; ++s )
            for( size_t i = 0; i < a; ++i )
                swap( v[i], v[s*a+i] );
        for( size_t i = 0; i < a; ++i )
            swap( v[i], v[(max_s*a+i) % v.size()] );
    }
    

    Of course it is not nearly as elegant as the famous reverse-three-times solution, but depending on the machine it can be similary fast.

    0 讨论(0)
  • 2020-11-28 06:00

    C arrayShiftRight function. If shift is negative the function shifts array left. It is optimized for less memory usage. Running time is O(n).

    void arrayShiftRight(int array[], int size, int shift) {
        int len;
    
        //cut extra shift
        shift %= size;
    
        //if shift is less then 0 - redirect shifting left
        if ( shift < 0 ) {
            shift += size;
        }
    
        len = size - shift;
    
        //choosing the algorithm which needs less memory
        if ( shift < len ) {
            //creating temporary array
            int tmpArray[shift];
    
            //filling tmp array
            for ( int i = 0, j = len; i < shift; i++, j++ ) {
                tmpArray[i] = array[j];
            }
    
            //shifting array
            for ( int i = size - 1, j = i - shift; j >= 0; i--, j-- ) {
                array[i] = array[j];
            }
    
            //inserting lost values from tmp array
            for ( int i = 0; i < shift; i++ ) {
                array[i] = tmpArray[i];
            }
        } else {
            //creating temporary array
            int tmpArray[len];
    
            //filling tmp array
            for ( int i = 0; i < len; i++ ) {
                tmpArray[i] = array[i];
            }
    
            //shifting array
            for ( int i = 0, j = len; j < size; i++, j++ ) {
                array[i] = array[j];
            }
    
            //inserting lost values from tmp array
            for ( int i = shift, j = 0; i < size; i++, j++ ) {
                array[i] = tmpArray[j];
            }
        }
    }
    
    0 讨论(0)
  • 2020-11-28 06:03

    Similar to @IsaacTurner and not that elegant due to unnecessary copying, but implementation is quite short.

    The idea - swap element A on index 0 with the element B which sits on destination of A. Now B is first. Swap it with the element C which sits on destination of B. Continue until the destination is not at 0.

    If the greatest common divisor is not 1 then you're not finished yet - you need to continue swapping, but now using index 1 at your starting and end point.

    Continue until your starting position is not the gcd.

    int gcd(int a, int b) => b == 0 ? a : gcd(b, a % b);
    
    public int[] solution(int[] A, int K)
    {
        for (var i = 0; i < gcd(A.Length, K); i++)
        {
            for (var j = i; j < A.Length - 1; j++)
            {
                var destIndex = ((j-i) * K + K + i) % A.Length;
                if (destIndex == i) break;
                var destValue = A[destIndex];
                A[destIndex] = A[i];
                A[i] = destValue;
            }
        }
    
        return A;
    }
    
    0 讨论(0)
  • 2020-11-28 06:05

    This algorithm runs in O(n) time and O(1) space. The idea is to trace each cyclic group in the shift (numbered by nextGroup variable).

    var shiftLeft = function(list, m) {
        var from = 0;
        var val = list[from];
        var nextGroup = 1;
        for(var i = 0; i < list.length; i++) {
            var to = ((from - m) + list.length) % list.length;
            if(to == from)
                break;
    
            var temp = list[to];
            list[to] = val;
            from = to;
            val = temp;
    
            if(from < nextGroup) {
                from = nextGroup++;
                val = list[from];
            }
        }
        return list;
    }
    
    0 讨论(0)
  • 2020-11-28 06:05

    Depending on the data structure you use, you can do it in O(1). I think the fastest way is to hold the array in the form of a linked list, and have a hash table that can translate between "index" in the array to "pointer" to the entry. This way you can find the relevant heads and tails in O(1), and do the reconnection in O(1) (and update the hash table after the switch in O(1)). This of course would be a very "messy" solution, but if all you're interested in is the speed of the shift, that will do (on the expense of longer insertion and lookup in the array, but it will still remain O(1))

    If you have the data in a pure array, I don't think you can avoid O(n).

    Coding-wise, it depends on what language you are using.

    In Python for example, you could "slice" it (assume n is the shift size):

    result = original[-n:]+original[:-n]
    

    (I know that hash lookup is in theory not O(1) but we're practical here and not theoretical, at least I hope so...)

    0 讨论(0)
  • 2020-11-28 06:05

    This method will do this work :

    public static int[] solution1(int[] A, int K) {
        int temp[] = new int[A.length];
    
        int count = 0;
    
        int orignalItration = (K < A.length) ? K :(K%A.length); 
    
    
        for (int i = orignalItration; i < A.length; i++) {
            temp[i] = A[count++];
        }
        for (int i = 0; i < orignalItration; i++) {
            temp[i] = A[count++];
        }
    
        return temp;
    }
    
    0 讨论(0)
提交回复
热议问题