华为 OD 机试:小朋友分组最少调整次数
题目描述
有 n 个学生排成一排,学生编号分别是 1 到 n,n 为 3 的整倍数。
老师随机抽签决定将所有学生分成 m 个 3 人的小组(n == 3 * m)。为了便于同组学生交流,老师决定将小组成员安排到一起,也就是同组成员彼此相连,同组任意两个成员之间无其它组的成员。
因此老师决定调整队伍,每次可以调整任何一名学生到队伍的任意位置,计为调整了一次。请计算最少调整多少次可以达到目标。
注意:
- 对于小组之间没有顺序要求。
- 同组学生之间没有顺序要求。
解题思路
这道题乍一看是在问'移动',但换个角度想,其实是在问'保留'。
如果我们能找出最多有多少个学生不需要移动,剩下的自然就是需要移动的最少人数。所以核心问题转化为:在原始序列中,最长能保留多少个人,使得他们能够被划分成若干个完整的三人组?
这里有个关键点,虽然同组内部顺序不限,但在原序列中,这三个人的相对顺序必须保持不变,且中间不能插入其他不属于该组的人。这实际上是一个寻找特定模式子序列的问题。
在实际面试或机试中,直接枚举所有分组情况复杂度太高。我们可以利用动态规划的思想,或者根据数据规模选择合适的贪心策略。对于这类题目,理解'总人数 - 最大保留人数 = 最小移动次数'这个公式往往比死磕具体算法更重要。
Java 代码实现
下面给出一个基于 Java 的参考实现框架。由于具体的输入格式可能因题目版本而异,这里重点展示逻辑结构。
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// 读取学生总数
if (scanner.hasNextInt()) {
int n = scanner.nextInt();
// 实际场景中,这里需要根据题目要求读取后续的学生编号数组
// 假设我们有一个数组 students 存储了当前的排列
// int[] students = readStudents(n, scanner);
// 调用核心求解方法
int result = solve(n);
System.out.println(result);
}
scanner.close();
}
private static int {
calculateMaxKept(n);
n - maxKept;
}
{
;
}
}

