
本文介绍一种高效、鲁棒的方法,用于判断一个整数数组是否由严格递减序列经若干次顺时针旋转得到,并给出完整实现与关键逻辑解析。
本文介绍一种高效、鲁棒的方法,用于判断一个整数数组是否由严格递减序列经若干次顺时针旋转得到,并给出完整实现与关键逻辑解析。
要判断一个数组是否为严格递减序列的顺时针旋转结果(例如 [6,5,4,3,2,1] 旋转两次得 [2,1,6,5,4,3]),核心在于识别“旋转断点”——即唯一可能出现升序的位置,并验证其前后是否满足递减连续性及首尾衔接关系。
✅ 判定逻辑(三步法)
- 至多一个“上升点”:在严格递减序列的旋转数组中,元素应整体呈“下降-下降-…-下降”趋势,仅允许一处 arr[i] > arr[i−1](即旋转导致的“断点”,如 [2,1,6,5,4,3] 中 1→6 是唯一升序);若出现 ≥2 次升序,则直接返回 false。
- 断点必须是“最小值跃迁到最大值”:该升序位置 i 应满足 arr[i] 是全局最小值,arr[i−1] 是全局最大值(即原递减序列的首尾相接)。因此,若存在断点,必有 arr[n−1] >= arr[0](因为旋转后末尾元素应 ≥ 原始首元素,即新序列末尾 ≤ 原始最小值,而首元素是原最大值)。
- 边界处理:长度 ≤1 的数组视为平凡满足条件;无升序点说明数组本身严格递减(即旋转 0 次),也合法。
⚠️ 注意:原题中 43,44,11,10,9 失败的根本原因是 44 > 43 构成第一个升序点,但此时 arr[n−1] = 9
✅ 优化实现(O(n) 时间,O(1) 空间)
public static boolean isSortedAndRotated(int[] arr) {
int n = arr.length;
if (n arr[i-1])
for (int i = 1; i arr[i - 1]) {
if (breakIndex != -1) { // 已存在升序点,再出现则非法
return false;
}
breakIndex = i;
}
}
// 无升序点:原数组严格递减,合法
if (breakIndex == -1) return true;
// 有升序点:必须满足末尾 ≤ 首元素(即 arr[n-1] = arr[0]?不!注意方向:
// 原递减序列:[max, ..., min] → 顺时针旋转后形如 [x, ..., min, max, ..., y]
// 断点处为 min→max,故 arr[breakIndex-1] 是 max,arr[breakIndex] 是 min
// 因此要求:arr[n-1] =2 ✅
// 非法:[43,44,11,10,9] → 断点 i=1 (43→44),arr[0]=43, arr[n-1]=9 → 9= arr[0]?等等,3>=2 成立,9>=43 不成立 → 所以条件是 arr[n-1] >= arr[0]?
// 错![2,1,6,5,4,3] 中 arr[n-1]=3, arr[0]=2 → 3>=2 ✔;[43,44,11,10,9] 中 9>=43? ✘ → 拒绝,正确。
// 但注意:[5,4,3,2,1](无断点)应返回 true,此时不检查该条件。
// 因此最终条件:若存在断点,则必须 arr[n-1] >= arr[0] —— 这保证了旋转后“尾部不小于头部”,即最小值在断点处,最大值在头部,末尾属于后半段,应 ≥ 原首部(即新首部)?需统一视角。
// ✅ 经典解法共识(LeetCode风格):
// 对于“是否为递增序列的旋转”,检查:至多一个下降点 + arr[n-1] = arr[0]
return arr[n - 1] >= arr[0];
}
✅ 完整可运行示例
import java.util.Scanner;
public class Main {
public static boolean isSortedAndRotated(int[] arr) {
int n = arr.length;
if (n arr[i - 1]) {
breaks++;
if (breaks > 1) return false;
}
}
// 允许0个或1个上升点;若有1个,则必须满足末尾≥首位(闭环约束)
return breaks == 0 || arr[n - 1] >= arr[0];
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int t = sc.nextInt();
while (t-- > 0) {
int n = sc.nextInt();
int[] arr = new int[n];
for (int i = 0; i <h3>✅ 测试用例验证</h3>
| 输入数组 | 期望输出 | 说明 |
|---|---|---|
| [2,1,6,5,4,3] | Yes | 递减序列 [6,5,4,3,2,1] 顺时针转2位 |
| [44,43,11,10,9] | Yes | 原序列即递减,旋转0次 |
| [43,44,11,10,9] | No | 44>43 是上升点,但 9 |
| [5,4,3,2,1] | Yes | 无上升点,纯递减 |
| [1,2,3,4,5] | No | 全上升,非递减旋转 |
? 总结
- 关键洞察:顺时针旋转的严格递减数组,最多含一个“上升断点”,且末尾元素必须不小于首元素(arr[n−1] ≥ arr[0])。
- 时间复杂度:O(n),仅一次遍历;空间复杂度:O(1)。
- 避免常见错误:不要依赖寻找最大值索引分割数组(易受重复值/边界干扰),直接扫描相邻关系更健壮。
- 本方法可无缝扩展至判断“递增序列的旋转”(只需将 > 改为











