【问题标题】:A left rotation operation on an array of size n shifts对大小为 n 的数组的左旋转操作移位
【发布时间】:2019-08-16 16:21:36
【问题描述】:

我尝试在一个大小为 n 的数组上实现左旋转。 例如,我有

数组 = {1,2,3,4,5};

我有班次:

班次 = 2;

处理完数组后,它必须如下所示:

数组 = {3,4,5,1,2};

我用两个 for 循环实现了它:

var array = new int[]{1,2,3,4,5};
var shifts =3;
var temp = 0;
for(var j = 0; j < shifts; j++){
     temp = array[0];
     for(var i = 0; i < array.Length -1; i++){
         array[i] = array[i + 1];
     }
     array[array.Length-1] = temp;
}
for(var i =0 ; i< array.Length; i++){
    System.Console.Write(array[i]+ " ");
}
 Console.Read();

它正在工作,但它没有通过数组中有大量数字的一些测试,我得到因超时而终止错误;

有没有办法实现一循环左旋转?

【问题讨论】:

  • 谷歌搜索 30 秒后:this
  • 如果可以接受生成新数组,那么 Patrick 的解决方案对于大型数组会更快。如果您需要执行就地移位,那么您可以使用该解决方案的组合将第一个“移位”元素提取到临时数组中,然后在单个循环中循环遍历数组,通过“移位”移动元素,然后插入最后的临时值。
  • @PaulF,如果可以使用IEnumerable&lt;T&gt; 进一步操作,则可以通过排除.ToArray() 来避免新数组。

标签: c# arrays rotation


【解决方案1】:
import java.util.*;
 public class ArrayRotation{
     public static void main(String[] args) {
         Scanner sc=new Scanner(System.in);
         System.out.println("enter size of array:");
         int n=sc.nextInt();                                         
         int arr[]=new int[n];
         System.out.println("enter elements:");
         for(int i=0;i<n;i++)
         arr[i]=sc.nextInt();
         System.out.println("enter shifts:");
         int d=sc.nextInt();
         int arr1[]=new int[d];
         for(int i=0;i<d;i++)
         arr1[i]=arr[i];
        System.out.println("Array after rotating");
        for(int i=d;i<n;i++)
          System.out.print(arr[i]+" ");
        for(int i=0;i<d;i++)
         System.out.print(arr1[i]+" ");
}

}

【讨论】:

  • 为什么用java做c#解决方案?
【解决方案2】:

使用具有移位量大小的旋转缓冲区使其工作。

static void ShiftLeft(int[] array, int shifts)
{
    int length = array.Length;
    int actualShifts = shifts % length;
    if (actualShifts == 0) return;
    int[] buffer = new int[actualShifts];
    Array.Copy(array, buffer, actualShifts);
    int indexAddition = actualShifts - (length % actualShifts);
    for (int i = length - 1; i >= 0; i--)
    {
        int current = array[i];
        int bufferIndex = (i + indexAddition) % actualShifts;
        array[i] = buffer[bufferIndex];
        buffer[bufferIndex] = current;
    }
}

编辑:正如@canton7 所指出的,循环缓冲区增加了不必要的复杂性。下面应该做,基本上是@canton7的答案,尽管@canton7由于缓冲区较小,他的答案仍然更有效:

int length = array.Length;
int actualShifts = shifts % length;
if (actualShifts == 0) return;
int[] buffer = new int[actualShifts];
Array.Copy(array, buffer, actualShifts);
Array.Copy(array, actualShifts, array, 0, length - actualShifts);
Array.Copy(buffer, 0, array, length - actualShifts, actualShifts);

【讨论】:

  • “这可以在一个循环中完成,第二个向后运行” - 这似乎仍然是两个循环 - 内部循环一次移动 1,所以可能需要与原始解决方案一样长的时间。
  • @PaulF 编辑了我的答案以包含一个循环。以前的效率非常低。
  • 你测试过这个解决方案吗?尝试将 1-10 的序列移动 2 或 3
  • 有趣 - 因为我得到 3,4,5,6,7,8,9,10, 2, 1 & 4,5,6,7,8,9,10, 3,1 , 2 - 见dotnetfiddle.net/jV0FJu
  • 这看起来比仅仅调用Array.Copy要复杂得多。您的整个循环可以替换为Array.Copy(array, actualShifts, array, 0, length - actualShifts); Array.Copy(buffer, 0, array, length - actualShifts, actualShifts);
【解决方案3】:

这是作弊,但 LINQ 解决方案可能是:

var array = Enumerable.Range(0, 100).ToArray();
var shiftBy = 2;
var shifted = array.Skip(shiftBy).Concat(array.Take(shiftBy)).ToArray();

如果您的任务只是以这种转换方式“查看”数组,为避免创建新数组,请排除结尾 .ToArray() 并直接遍历 IEnumerable&lt;int&gt;

【讨论】:

  • 感谢您的回答,您的解决方案很棒,但我必须使用循环来做到这一点。
  • @UladzimirKhadakouski 如果您有特定要求,例如“仅使用循环来实现”,那么 需要 在您的问题中。你不能让人们浪费时间回答你的问题,然后才告诉他们他们的答案是无效的,因为你从来没有说过一些条件!
  • @canton7 是的,伙计,我下次会这样做,无论我为这个答案投票并且帕特里克获得了声誉,所以他实际上并没有浪费时间
【解决方案4】:

我认为这与就地旋转数组一样有效。适用于左右旋转,取决于rotateBy 的符号:

private static void Rotate<T>(T[] array, int rotateBy)
{
    rotateBy %= array.Length;
    // Nothing to do?
    if (rotateBy == 0)
        return;
    // Normalize it to a right rotation
    if (rotateBy < 0)
        rotateBy = array.Length + rotateBy;
    // Allocate the smallest possible temp array
    if (rotateBy > array.Length / 2)
    {
        T[] temp = new T[array.Length - rotateBy];
        Array.Copy(array, 0, temp, 0, array.Length - rotateBy);
        Array.Copy(array, array.Length - rotateBy, array, 0, rotateBy);
        Array.Copy(temp, 0, array, rotateBy, array.Length - rotateBy);
    }
    else
    {
        T[] temp = new T[rotateBy];
        Array.Copy(array, array.Length - rotateBy, temp, 0, rotateBy);
        Array.Copy(array, 0, array, rotateBy, array.Length - rotateBy);
        Array.Copy(temp, 0, array, 0, rotateBy);  
    }
}

【讨论】:

  • 您还可以检查 rotateBy == 0 并立即退出 - 保存将整个数组复制到临时数组并再次返回。
  • @PaulF 谢谢。还要确保它分配尽可能小的临时数组。
猜你喜欢
  • 1970-01-01
  • 2021-04-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-08-09
相关资源
最近更新 更多