You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

HackerRank数组左旋转问题:自定义实现遇阻求助

解决数组左旋转的思路补全与问题解答

嘿,你的思路其实挺棒的——通过判断旋转次数来切换旋转方向,减少操作次数,这个优化点很聪明!咱们一步步来把这个实现补全,同时解决你遇到的几个问题:

一、先修正旋转次数d的计算逻辑

你原来处理d大于数组长度的方式有点小问题,更通用的做法是用取模运算来得到最小的有效旋转次数,因为旋转n次(n等于数组长度)相当于没旋转。比如数组长度为4,旋转5次等价于旋转1次,用d % aLength就能直接得到这个结果。另外还要处理d为0的情况(比如取模后结果为0),直接返回原数组即可。

修正后的这部分逻辑可以改成:

int aLength = a.length;
// 先处理特殊情况:数组为空或无需旋转
if (aLength == 0 || d == 0) {
    return a;
}
// 计算最小有效旋转次数
d = d % aLength;
// 如果旋转次数等于数组长度,直接返回原数组(其实上面的取模已经覆盖了这个情况,不过保留也没问题)
if (d == aLength) {
    return a;
}

二、实现左/右旋转的数组赋值逻辑

你卡在了元素赋值环节,核心是要正确计算每个元素在新数组中的位置,避免IndexOutOfBoundsException。咱们分两种情况实现:

情况1:执行左旋转(当d <= aLength/2时)

左旋转d次的本质是:把原数组前d个元素移到数组末尾。比如数组[1,2,3,4]左旋转1次后变成[2,3,4,1]。

赋值逻辑可以这样写:

int[] newArray = new int[aLength];
for (int i = 0; i < aLength; i++) {
    // 原数组索引i的元素,在新数组中的位置是 (i - d + aLength) % aLength
    // 加aLength是为了避免i-d出现负数,再取模保证索引合法
    newArray[(i - d + aLength) % aLength] = a[i];
}

或者换一种更直观且高效的方式(用原生数组复制方法):

// 复制原数组d到末尾的元素到新数组开头
System.arraycopy(a, d, newArray, 0, aLength - d);
// 复制原数组开头到d的元素到新数组末尾
System.arraycopy(a, 0, newArray, aLength - d, d);

情况2:执行右旋转(当d > aLength/2时)

此时我们可以把左旋转d次转换成右旋转k次,其中k = aLength - d(比如数组长度4,左旋转3次=右旋转1次)。右旋转k次的本质是把原数组最后k个元素移到数组开头。

赋值逻辑示例:

int k = aLength - d;
int[] newArray = new int[aLength];
// 复制原数组最后k个元素到新数组开头
System.arraycopy(a, aLength - k, newArray, 0, k);
// 复制原数组开头到aLength-k的元素到新数组后半部分
System.arraycopy(a, 0, newArray, k, aLength - k);

或者用循环的方式:

int k = aLength - d;
int[] newArray = new int[aLength];
for (int i = 0; i < aLength; i++) {
    // 原数组索引i的元素,在新数组中的位置是 (i + k) % aLength
    newArray[(i + k) % aLength] = a[i];
}

三、关于IndexOutOfBoundsException和try-catch的疑问

你遇到的越界问题,本质是索引计算错误导致的(比如没有处理负数、没有取模)。通过上面的数学计算或者System.arraycopy的参数控制,完全可以避免这个异常,所以这里使用try-catch属于过度设计。

捕获异常不仅会增加不必要的代码复杂度,还可能掩盖你逻辑上的错误(比如索引计算错误)。更好的做法是通过严谨的逻辑保证索引始终在0到aLength-1的范围内。

完整的实现代码

把上面的逻辑整合起来,完整的方法如下:

static int[] rotLeft(int[] a, int d) {
    int aLength = a.length;
    // 处理特殊情况:无需旋转
    if (aLength == 0 || d == 0) {
        return a;
    }
    // 计算最小有效旋转次数
    d = d % aLength;
    if (d == 0) {
        return a;
    }
    
    int[] newArray = new int[aLength];
    boolean rotateRight = d > aLength / 2;
    
    if (rotateRight) {
        // 转为右旋转k次
        int k = aLength - d;
        System.arraycopy(a, aLength - k, newArray, 0, k);
        System.arraycopy(a, 0, newArray, k, aLength - k);
    } else {
        // 执行左旋转
        System.arraycopy(a, d, newArray, 0, aLength - d);
        System.arraycopy(a, 0, newArray, aLength - d, d);
    }
    
    return newArray;
}

总结

你的思路完全可行,通过切换旋转方向来减少操作次数是个很实用的优化点。只要把索引计算逻辑理清楚,就能顺利解决赋值和越界的问题,不需要依赖try-catch来处理可避免的异常。

内容的提问来源于stack exchange,提问作者Matt

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.09 14:02:29