最近在准备华为OD机考双机位C卷时遇到一道关于"优雅数组"的编程题,题目要求用Java实现特定条件的数组操作。这类题型在算法面试中非常典型,主要考察候选人对数组处理、边界条件把控和代码优雅度的综合能力。
所谓优雅数组,是指满足以下条件的整数数组:
举个例子,[1,3,2]就是一个典型的优雅数组,而[1,2,3,2,1]也是符合条件的。这类问题在实际业务中可能对应着寻找数据序列中的关键转折点,比如股票价格峰值检测、传感器数据异常点定位等场景。
首先需要明确题目要求的三个核心条件:
最直观的解法是线性扫描法,时间复杂度O(n),空间复杂度O(1)。具体步骤:
需要特别注意的边界情况包括:
java复制public class GracefulArray {
public static boolean isGracefulArray(int[] arr) {
if (arr == null || arr.length < 3) {
return false;
}
int peakIndex = -1;
// 寻找峰顶
for (int i = 1; i < arr.length - 1; i++) {
if (arr[i] > arr[i-1] && arr[i] > arr[i+1]) {
if (peakIndex != -1) {
return false; // 多个峰顶
}
peakIndex = i;
}
}
if (peakIndex == -1) {
return false; // 无峰顶
}
// 检查左侧严格递增
for (int i = 1; i <= peakIndex; i++) {
if (arr[i] <= arr[i-1]) {
return false;
}
}
// 检查右侧严格递减
for (int i = peakIndex + 1; i < arr.length; i++) {
if (arr[i] >= arr[i-1]) {
return false;
}
}
return true;
}
}
可以通过单次遍历优化性能:
java复制public static boolean isGracefulArrayOptimized(int[] arr) {
if (arr == null || arr.length < 3) return false;
int state = 0; // 0:初始 1:上升 2:下降
int peakCount = 0;
for (int i = 1; i < arr.length; i++) {
if (arr[i] == arr[i-1]) return false;
if (arr[i] > arr[i-1]) {
if (state == 2) return false; // 下降后又上升
state = 1;
} else {
if (state == 1) {
peakCount++;
if (peakCount > 1) return false;
}
state = 2;
}
}
return peakCount == 1;
}
java复制@Test
public void testGracefulArray() {
// 标准优雅数组
assertTrue(isGracefulArray(new int[]{1,3,2}));
assertTrue(isGracefulArray(new int[]{1,2,3,2,1}));
// 非优雅数组
assertFalse(isGracefulArray(new int[]{1,2,3})); // 无峰顶
assertFalse(isGracefulArray(new int[]{3,2,1})); // 无峰顶
assertFalse(isGracefulArray(new int[]{1,3,2,4,1})); // 多个峰顶
assertFalse(isGracefulArray(new int[]{1,2,2,1})); // 相邻相等
}
java复制@Test
public void testEdgeCases() {
// 边界情况
assertFalse(isGracefulArray(null));
assertFalse(isGracefulArray(new int[]{}));
assertFalse(isGracefulArray(new int[]{1}));
assertFalse(isGracefulArray(new int[]{1,2}));
// 峰顶在边界
assertFalse(isGracefulArray(new int[]{3,2,1,2})); // 峰顶不能在最右
assertFalse(isGracefulArray(new int[]{2,1,2,3})); // 峰顶不能在最左
}
虽然时间复杂度相同,但优化版本常数因子更小,在大数据量时性能更好。
忽略相邻元素相等的情况
峰顶位置判断不准确
边界条件处理不足
虽然这是道算法题,但类似的模式识别在实际开发中有广泛应用:
理解这类基础算法问题,能帮助我们在面对更复杂的业务场景时快速找到解决方案。比如在开发一个实时监控系统时,可能需要类似的算法来检测指标异常。