如何有效地旋转阵列?

时间:2016-07-20 13:28:44

标签: c# algorithm

给定一个n整数数组和一个数字d,在数组上执行左旋转。然后将更新的数组打印为一行以空格分隔的整数。

示例输入:

  

5 4
  1 2 3 4 5

第一行包含两个以空格分隔的整数,表示n(整数)和d(必须执行的左旋转数)的相应值。 第二行包含n空格分隔的整数,用于描述数组初始状态的各个元素。

示例输出:

  

5 1 2 3 4

static void Main(String[] args)
{
    string[] arr_temp = Console.ReadLine().Split(' ');
    int n = Int32.Parse(arr_temp[0]);
    int d = Int32.Parse(arr_temp[1]);

    string[] arr = Console.ReadLine().Split(' ');
    string[] ans = new string[n];

    for (int i = 0; i < n; ++i)
    {
        ans[(i + n - d) % n] = arr[i];
    }

    for (int j = 0; j < n; ++j)
    {
        Console.Write(ans[j] + " ");
    }
}

如何使用更少的内存来解决这个问题?

17 个答案:

答案 0 :(得分:3)

其实你问过两个问题:

  

如何高效旋转数组?

  

如何使用更少内存来解决此问题?

通常效率和低内存使用是互斥的。所以我将回答你的第二个问题,仍然在该内存约束下提供最有效的实现。

以下方法可用于左(通过负计数)或右(通过正计数)旋转。它使用 O(1)空间(单个元素)和 O(n * min(d,n - d))数组元素复制操作( O(min) (d,n - d))数组块复制操作)。在最坏的情况下,它执行 O(n / 2)块复制操作。

算法正在利用

这一事实
  

rotate_left(n,d)== rotate_right(n,n - d)

这是:

var array = Enumerable.Range(1, 5).ToArray(); // { 1, 2, 3, 4, 5 } 
array.Rotate(-4); // { 5, 1, 2, 3, 4 } 

示例用法,例如:

{{1}}

答案 1 :(得分:3)

在大多数情况下,这将使用更少的内存,因为第二个数组仅与移位一样大。

public static void Main(string[] args)
{
    int[] n = { 1, 2, 3, 4, 5 };
    LeftShiftArray(n, 4);
    Console.WriteLine(String.Join(",", n));
}

public static void LeftShiftArray<T>(T[] arr, int shift)
{
    shift = shift % arr.Length;
    T[] buffer = new T[shift];
    Array.Copy(arr, buffer, shift);
    Array.Copy(arr, shift, arr, 0, arr.Length - shift);
    Array.Copy(buffer, 0, arr, arr.Length - shift, shift);
}

答案 2 :(得分:1)

你真的需要移动物体吗?如果没有,你可以改为改变索引。

答案 3 :(得分:1)

我已经通过以下代码解决了Hackerrank的挑战。希望能帮助到你。

using System;
using System.Collections.Generic;
using System.IO;
using System.Text;

namespace ConsoleApp1
{
class ArrayLeftRotationSolver
{
    TextWriter mTextWriter;
    public ArrayLeftRotationSolver()
    {
         mTextWriter = new StreamWriter(@System.Environment.GetEnvironmentVariable("OUTPUT_PATH"), true);

    }

    public void Solve()
    {

        string[] nd = Console.ReadLine().Split(' ');

        int n = Convert.ToInt32(nd[0]);

        int d = Convert.ToInt32(nd[1]);

        int[] a = Array.ConvertAll(Console.ReadLine().Split(' '), aTemp => Convert.ToInt32(aTemp))
        ;
        int[] result = rotLeft(a, d);

        mTextWriter.WriteLine(string.Join(" ", result));

        mTextWriter.Flush();
        mTextWriter.Close();
    }

    private int[] rotLeft(int[] arr, int shift)
    {
        int n = arr.Length;
        shift %= n;
        int[] vec = new int[n];
        for (int i = 0; i < n; i++)
        {
            vec[(n + i - shift) % n] = arr[i];
        }
        return vec;
    }

    static void Main(string[] args)
    {
         ArrayLeftRotationSolver solver = new ArrayLeftRotationSolver();
         solver.Solve();
    }
}

}

答案 4 :(得分:1)

这个问题可能会有些棘手,但如果熟悉队列和堆栈,也可以采用简单的解决方案。 我要做的就是定义一个Queue(它将包含给定的数组)和一个Stack。 接下来,我只需要将出队索引推入堆栈,并将弹出的索引排入队列,最后返回队列。 听起来令人困惑?检查以下代码:

static int[] rotLeft(int[] a, int d) {

    Queue<int> queue = new Queue<int>(a);
    Stack<int> stack = new Stack<int>();

    while(d > 0)
    {
        stack.Push(queue.Dequeue());
        queue.Enqueue(stack.Pop());
        d--;            
    }

    return queue.ToArray();
}

答案 5 :(得分:0)

这是非常直接的答案。 主要是你如何选择起始索引。

    public static List<int> rotateLeft(int d, List<int> arr) {
        int n = arr.Count;
        List<int> t = new List<int>();
        int h = d;

        for (int j = 0; j < n; j++)
        { 
            if ((j + d) % n == 0)
            {
                h = 0;
            }
           
            t.Add(arr[h]);
            h++;
        } 

        return t;
    }

使用此代码,我已成功提交黑客等级问题,

答案 6 :(得分:0)

如果查看约束,您将看到d <= n(旋转数<=数组中的元素数)。因此,可以在1行中解决。

static int[] rotLeft(int[] a, int d)
{
    return a.Skip(d).Concat(a.Take(d)).ToArray();
}

答案 7 :(得分:0)

这是什么?

 public static void RotateArrayAndPrint(int[] n, int rotate)
    {
         for (int i = 1; i <= n.Length; i++)
        {
            var arrIndex = (i + rotate) > n.Length ? n.Length - (i + rotate) : (i + rotate);
            arrIndex = arrIndex < 0 ? arrIndex * -1 : arrIndex;
            var output = n[arrIndex-1];
            Console.Write(output + " ");
        }
    }

答案 8 :(得分:0)

O(1)空间,O(n)时间解

我认为从理论上讲这是最佳的,因为它可以进行一次就地交换和每个内部循环1个临时变量交换。

但是我怀疑O(d)空间解决方案在现实生活中会更快,这是因为更少的代码分支(更少的CPU命令管道重置)和缓存位置(主要是顺序访问与d元素步骤相比)。

static int[] RotateInplaceLeft(int[] a, int d)
{
    var swapCount = 0;

    //get canonical/actual d    
    d = d % a.Length;
    if(d < 0) d += a.Length;
    if(d == 0) return a;

    for (var i = 0; swapCount < a.Length; i++) //we're done after a.Length swaps
    {
        var dstIdx = i; //we need this becasue of ~this: https://youtu.be/lJ3CD9M3nEQ?t=251 
        var first = a[i]; //save first element in this group

        for (var j = 0; j < a.Length; j++)
        {
            var srcIdx = (dstIdx + d) % a.Length;
            if(srcIdx == i)// circled around 
            {
                a[dstIdx] = first;
                swapCount++;
                break; //hence we're done with this group
            }
            a[dstIdx] = a[srcIdx];
            dstIdx = srcIdx;
            swapCount++;
        }
    }
    return a;
}

答案 9 :(得分:0)

这是我的尝试。这很容易,但是由于某些原因,它在大数据块上超时:

        int arrayLength = arr.Length;
        int tmpCell = 0;
        for (int rotation = 1; rotation <= d; rotation++)
        {
            for (int i = 0; i < arrayLength; i++)
            {
                if (arr[i] < arrayElementMinValue || arr[i] > arrayElementMaxValue)
                {
                    throw new ArgumentException($"Array element needs to be between {arrayElementMinValue} and {arrayElementMaxValue}");
                }
                if (i == 0)
                {
                    tmpCell = arr[0];
                    arr[0] = arr[1];
                }
                else if (i == arrayLength - 1)
                {
                    arr[arrayLength - 1] = tmpCell;
                }
                else
                {
                    arr[i] = arr[i + 1];
                }
            }
        }

答案 10 :(得分:0)

使用IEnumerables更好吗?由于它不会执行所有这些数学运算,因此不会分配那么多数组,等等

public static int[] Rotate(int[] elements, int numberOfRotations)
{
    IEnumerable<int> newEnd = elements.Take(numberOfRotations);
    IEnumerable<int> newBegin = elements.Skip(numberOfRotations);
    return newBegin.Union(newEnd).ToArray();
}

如果您实际上不需要返回数组,甚至可以删除.ToArray()并返回IEnumerable

用法:

void Main()
{
    int[] n = { 1, 2, 3, 4, 5 };
    int d = 4;
    int[] rotated = Rotate(n,d);
    Console.WriteLine(String.Join(" ", rotated));
}

答案 11 :(得分:0)

一个古老的问题,但我想我将仅使用一个中间数组(如果包含LINQ Take表达式,则为2)来添加另一种可能的解决方案。该代码向右旋转,而不是向左旋转,但是仍然可能有用。

public static Int32[] ArrayRightRotation(Int32[] A, Int32 k)
    {
        if (A == null)
        {
            return A;
        }

        if (!A.Any())
        {
            return A;
        }

        if (k % A.Length == 0)
        {
            return A;
        }

        if (A.Length == 1)
        {
            return A;
        }

        if (A.Distinct().Count() == 1)
        {
            return A;
        }

        for (var i = 0; i < k; i++)
        {
            var intermediateArray = new List<Int32> {A.Last()};
            intermediateArray.AddRange(A.Take(A.Length - 1).ToList());
            A = intermediateArray.ToArray();
        }

        return A;
    }

答案 12 :(得分:0)

将项目置于位置0,并在末尾添加。删除位置0处的项目。重复n次。

List<int> iList = new List<int>(); 

    private void shift(int n)
    {
        for (int i = 0; i < n; i++)
        {
            iList.Add(iList[0]);
            iList.RemoveAt(0);
        }


    }

答案 13 :(得分:0)

希望这会有所帮助。

public static int[] leftrotation(int[] arr, int d)
    {

        int[] newarr = new int[arr.Length];
        var n = arr.Length;
        bool isswapped = false;
        for (int i = 0; i < n; i++)
        {
            int index = Math.Abs((i) -d);
            if(index == 0)
            {
                isswapped = true;
            }

            if (!isswapped)
            {
                int finalindex = (n) - index;
                newarr[finalindex] = arr[i];
            }
            else
            {
                newarr[index] = arr[i];
            }
        }
        return newarr;
    }

答案 14 :(得分:0)

我曾尝试在C#中使用堆栈和队列来实现输出,如下所示:

public int[] rotateArray(int[] A, int rotate)
{
    Queue<int> q = new Queue<int>(A);
    Stack<int> s;
    while (rotate > 0)
    {
        s = new Stack<int>(q);
        int x = s.Pop();
        s = new Stack<int>(s);
        s.Push(x);
        q = new Queue<int>(s);
        rotate--;
    }
    return q.ToArray();
}

答案 15 :(得分:0)

我也试过这个,下面是我的方法...... 谢谢

public static int[] RotationOfArray(int[] A, int k)
  {
      if (A == null || A.Length==0)
          return null;
      int[] result =new int[A.Length];
      int arrayLength=A.Length;
      int moveBy = k % arrayLength;
      for (int i = 0; i < arrayLength; i++)
      {
          int tmp = i + moveBy;
          if (tmp > arrayLength-1)
          {
              tmp =  + (tmp - arrayLength);
          }
          result[tmp] = A[i];             
      }        
      return result;
  }

答案 16 :(得分:-1)

假设我有一个整数'Arr'数组。要旋转数组'n',您可以执行以下操作:

static int[] leftRotation(int[] Arr, int n)
{
    int tempVariable = 0;
    Queue<int> TempQueue = new Queue<int>(a);
      for(int i=1;i<=d;i++)
       {
           tempVariable = TempQueue.Dequeue();
           TempQueue.Enqueue(t);
    }

    return TempQueue.ToArray();`
}

如果有任何意见,请告诉我。谢谢!