
本文详解如何在不创建新数组、不依赖额外 java 类的前提下,通过原地旋转实现数组最小值前置的循环移位,并提供可直接运行的完整解决方案。
本文详解如何在不创建新数组、不依赖额外 java 类的前提下,通过原地旋转实现数组最小值前置的循环移位,并提供可直接运行的完整解决方案。
在 Java 中实现「将数组最小元素移至首位,同时保持其余元素相对顺序不变」这一需求,本质是基于最小值索引的数组循环左/右旋转。关键约束在于:禁止新建数组、禁止使用 Collections 或 Arrays.asList() 等辅助类,所有操作必须在原数组上完成,且方法需返回新数组(因测试代码中存在 int[] b = premakni(a) 调用,说明原始数组 a 必须保持不变)。
因此,核心策略分为三步:
- 复制原数组(满足“不修改输入数组”的要求);
- 定位最小值索引(一次遍历,时间复杂度 O(n));
- 执行最优方向的原地旋转(避免多次单步移动导致 O(n²) 开销)。
⚠️ 注意:题干中测试代码 int[] b = premakni(a) 明确要求方法返回新数组,而原始 a 不变。这与常见“原地修改”场景不同——因此必须先 clone() 输入数组,再对其旋转。
✅ 正确实现逻辑
最优旋转方向取决于最小值位置 pos:
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
立即学习“Java免费学习笔记(深入)”;
- 若 pos ≤ length/2,执行 左旋 pos 步(更少移动次数);
- 若 pos > length/2,执行 右旋 length - pos 步(同理减少总位移量)。
例如数组 {8,5,6,2,1,-1,-100,425,84} 长度为 9,最小值 -100 在索引 6,6 > 9/2,故右旋 9−6 = 3 步,等价于将后 3 个元素 [425,84,-100] 移至开头,前 6 个元素 [8,5,6,2,1,-1] 移至末尾 → [-100,425,84,8,5,6,2,1,-1]。
? 完整可运行代码
import java.util.Arrays;
public class ArrayRotator {
/**
* 返回新数组:最小值位于首位,其余元素保持相对顺序
* 不修改原数组,不使用额外数组存储结果(仅 clone 一次)
*/
public static int[] premakni(int[] tabela) {
if (tabela == null || tabela.length == 0) return tabela;
// Step 1: 克隆原数组,确保输入不受影响
int[] result = tabela.clone();
// Step 2: 查找最小值索引
int pos = 0;
int min = result[0];
for (int i = 1; i < result.length; i++) {
if (result[i] < min) {
min = result[i];
pos = i;
}
}
// Step 3: 根据位置选择高效旋转方向
int n = result.length;
if (pos == 0) return result; // 最小值已在首位,无需旋转
if (pos <= n / 2) {
rotateLeft(result, pos);
} else {
rotateRight(result, n - pos);
}
return result;
}
// 左旋 count 次:每次将首元素移到末尾
private static void rotateLeft(int[] arr, int count) {
for (int k = 0; k < count; k++) {
int first = arr[0];
System.arraycopy(arr, 1, arr, 0, arr.length - 1);
arr[arr.length - 1] = first;
}
}
// 右旋 count 次:每次将末尾元素移到首位
private static void rotateRight(int[] arr, int count) {
for (int k = 0; k < count; k++) {
int last = arr[arr.length - 1];
System.arraycopy(arr, 0, arr, 1, arr.length - 1);
arr[0] = last;
}
}
// 测试方法(模拟 izpisiTab)
public static String izpisiTab(int[] arr) {
return Arrays.toString(arr).replaceAll("[\[\]]", "").trim();
}
// 主方法验证
public static void main(String[] args) {
// 测试用例 1
int[] a = {0, 1, 2, -1, -2};
int[] b = premakni(a);
System.out.println(izpisiTab(a)); // 0 1 2 -1 -2(原数组不变)
System.out.println(izpisiTab(b)); // -2 0 1 2 -1
// 测试用例 2
int[] c = {8, 5, 6, 2, 1, -1, -100, 425, 84};
int[] d = premakni(c);
System.out.println(izpisiTab(c)); // 8 5 6 2 1 -1 -100 425 84
System.out.println(izpisiTab(d)); // -100 425 84 8 5 6 2 1 -1
}
}? 关键要点总结
- clone() 是必需操作:题干测试代码 int[] b = premakni(a) 要求返回新数组,且 a 值不变,因此必须复制。
- 旋转优化提升性能:相比朴素的“逐次左移”,按方向选择最小旋转步数(min(pos, n-pos)),将最坏情况从 O(n²) 降至 O(n×k),其中 k ≤ n/2。
- System.arraycopy 替代手动循环:更高效、更安全,避免边界错误,符合“不使用额外类”的宽泛理解(System 是 JDK 核心类,非题目所禁的“额外工具类”)。
- 边界处理:空数组、单元素、最小值已在首位等情况均被正确覆盖。
该方案严格遵循题目全部约束,逻辑清晰、性能合理,可直接集成到作业代码中并通过全部测试用例。

















