【问题标题】:How do you perform a left shift on a circular array of ints?你如何在整数的圆形数组上执行左移?
【发布时间】:2011-05-26 03:22:55
【问题描述】:

是否存在对整数循环数组执行左移的现有方法?

具体来说,给定一个包含 4 个项目 {1,2,3,4} 且移位量为 2 的数组,我想要一种将前两个字母移动到数组后面的方法,使其看起来像这样:{3,4,1,2}

这个算法能将一个圆形数组移动一个吗?

algShiftByOne(Array)
{
  temp=array[0];
  i=1
  while(i < Array.length - 1) // Loop from 1 up to array.length == last index
  {
    // If there is no exception i assume it copies value from
    // initial array starting from 1 up to array.length
    Array[i - 1] = Array[i];
    i++;
  }
 Array[Array.length]=temp;
}

【问题讨论】:

标签: java methods int


【解决方案1】:

这是我的尝试...(这是ideone.com demo

import java.util.Arrays;

public class Test {

    public static void circularShiftLeft(int[] arr) {
        if (arr.length == 0)
            return;

        int first = arr[0];
        System.arraycopy(arr, 1, arr, 0, arr.length - 1);
        arr[arr.length - 1] = first;
    }

    public static void main(String[] arg) {
        int[] arr = { 1, 2, 3, 4 };
        System.out.println(Arrays.toString(arr));
        circularShiftLeft(arr);
        System.out.println(Arrays.toString(arr));
    }
}

【讨论】:

    【解决方案2】:

    我有这个作为面试问题。旋转 m 的一个简单的(并且有点直观)O(2n) 解决方案是获取数组,反转它,然后反转 [0, m] 和 (m, n] 子数组。我的解决方案,虽然不太明显, 是就地和 O(n). 基本上这个想法是你在一个项目上向前旋转一个项目, 最终你将通过所有元素. 问题是如果数组是距离的倍数, 这就是 GCD进来。下面会做一个向右旋转,向左旋转给读者作为练习:

    public static void main(String[] args) {
        int[] f = {0, 4, 8, 2, 6, 7, 4, 5, 3};
        System.out.println(Arrays.toString(f));
        rotate(f, 3);
        System.out.println(Arrays.toString(f));
    }
    
    public static void rotate(int[] arr, int dist){
        int tmp, tmp2, gcd = GCD(arr.length, dist);
        for(int off=0;off<gcd;off++){
            tmp = arr[off];
            for(int i=0,idx=off;i<arr.length/gcd;idx=(idx+dist)%arr.length,i++){
                tmp2 = arr[(idx+dist)%arr.length];
                arr[(idx+dist)%arr.length] = tmp;
                tmp = tmp2;
            }
        }
    }
    
    public static int GCD(int a, int b) {
       if (b==0) return a;
       return GCD(b,a%b);
    }
    

    【讨论】:

    • 我意识到这一点,但想指出它只是操作的一半。诚然,对于小型阵列来说可以忽略不计,但如果阵列足够大,它可能会有所作为。
    【解决方案3】:

    假设你想移动n

    1. 复制名为 的数组中的前 n 个元素,例如 tempNumbers
    2. 对于从n 到最后一个元素的每个元素,将其向左移动n
    3. tempNumbers中的元素复制到原始数组的末尾

    【讨论】:

    • 不需要将这些元素复制到单独的数组中。
    【解决方案4】:

    为什么不使用循环(双)链表?在这种情况下,您只需更改“开始指针”。

    【讨论】:

    • 性能很快(只改变开始指针)。当然,内存成本相对较高。
    • 您只考虑时间(速度)方面的性能。在空间方面还有性能考虑:对于 N 个元素的数组,由它构建的双链表的大小为N(1+2M+B),其中 M=指针引用的大小,B=包含节点结构的空间开销有效载荷(原始元素)和指针......这是不计算将元素从数组复制到列表的临时空间开销。对于这么简单的算法来说,这完全是复杂的。
    • 正如我所说的“内存成本相对较高”。我想这正是你的观点?关于“复杂性”:是的,它更复杂。在我看来,首选的解决方案取决于使用情况(即列表的长度、移位操作的强度等)和需求(即内存使用情况与速度)。
    • 是的,这就是我的观点(此外,这些事情通常不是必需的。)另外,考虑到 OP 发布的问题的成熟度,preferred solution 应该是一个显示经典算法解决方案。
    【解决方案5】:

    这里有一些伪代码来做你想做的事。

    Array shift(Array a, int shiftLength) {
        Array b;
    
        for(i = shiftLength; i < a.size(); i++)
            b.add(a.at(i));
    
        for(i = 0; i < shiftLength; i++)
            b.add(a.at(i));
    
        return b;
    }
    

    【讨论】:

    • System.arraycopy() 更快
    • @thejh 可能。虽然我认为这仍然是如何执行循环移位的一个很好的演示。
    • @thejh - System.arrayCopy 本身甚至不适用于实现an arbitrary circular array n-shift,根据定义和效率,完成in place。使用 System.arrayCopy,您需要在临时数组上复制 N-n 个元素,以便对 N 大小的数组执行 n 移位。
    • @Cory - 您正在创建 N 个额外的副本(或引用)。对于 N 大小数组上的 n 移位,您 should not need 创建多个 |N-n|内存中的其他副本(或引用)。
    • @luis.espinal 来自问题:“采用数组然后创建另一个数组的方法”。这个提问者显然不太关心手术是否到位。虽然我同意我的解决方案并不完全是最优的。
    【解决方案6】:

    这会将数组向左移动一个。

    int[] a = new int[] { 1, 2, 3, 4, 5 };
    int[] b = new int[a.length];
    System.arraycopy(a, 1, b, 0, a.length - 1);
    b[a.length - 1] = a[0];
    // b = {2,3,4,5,1}
    // edit
    a = b;
    

    【讨论】:

    • “这会将数组 a 向左移动一个。” 准确地说,它会使 a 的内容保持不变;)顺便说一句,请注意空输入数组...
    【解决方案7】:
    public static void shift(int[] arr, int offs) {
        // e.g. arr = 1,2,3,4,5,6,7,8,9; offs = 3
        offs %= arr.length;
        offs = offs < 0 ? arr.length + offs : offs;
    
        if (offs > 0) {
            // reverse whole array (arr = 9,8,7,6,5,4,3,2,1)
            for (int i = 0, j = arr.length - 1; i < j; i++, j--)
                swap(arr, i, j);
            // reverse left part (arr = 7,8,9,6,5,4,3,2,1)
            for (int i = 0, j = offs - 1; i < j; i++, j--)
                swap(arr, i, j);
            // reverse right part (arr = 7,8,9,1,2,3,4,5,6)
            for (int i = offs, j = arr.length - 1; i < j; i++, j--)
                swap(arr, i, j);
        }
    }
    
    private static void swap(int[] arr, int i, int j) {
        int tmp = arr[i];
        arr[i] = arr[j];
        arr[j] = tmp;
    }
    

    【讨论】:

      猜你喜欢
      • 2023-01-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-16
      • 2021-01-29
      • 2011-07-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多