【算法解析】将数组右移使其递增的最少次数(Python实现)
在日常算法练习中,我们常常会遇到关于数组旋转和排序的问题。本文将深入探讨一个典型问题:“通过最少右移次数,使一个数组变为递增数组”。我们将从题意分析、思路探索、代码实现到最优解优化一一讲解。
🧩 题目描述
给定一个长度为 n 的数组 nums,其中所有元素互不相同且为正整数。我们每次可以将整个数组右移一位,也就是说数组中每个元素 nums[i] 会变成 nums[(i + 1) % n]。我们需要找出使得数组变为严格递增数组所需的最少右移次数。如果无法通过任何右移操作使数组变为递增数组,返回 -1。
✏️ 示例解释
示例 1:
输入:nums = [3, 4, 5, 1, 2]
输出:2
解释:
第一次右移后 => [2, 3, 4, 5, 1]
第二次右移后 => [1, 2, 3, 4, 5] ✅
示例 2:
输入:nums = [1, 3, 5]
输出:0 ✅
示例 3:
输入:nums = [2, 1, 4]
输出:-1 ❌
解释:无法通过右移得到一个递增数组。
🎯 解题思路
要判断一个数组是否可以通过若干次右移操作成为递增数组,我们可以将这个问题转化为找**“断点”**的问题。
👉 什么是断点?
一个“断点”是数组中前一个数比后一个数大的地方。也就是说,当我们在某个 i 处发现 nums[i] > nums[i+1](考虑循环意义,即 (i+1) % n),我们就认为这是一处断点。
✅ 合法的递增数组满足以下条件:
- 最多只有一个断点。
- 从断点位置进行右移,可以使数组重新排列为递增的形式。
💡 解法一:暴力模拟(不推荐)
尝试所有可能的右移次数(最多 n 次),每次判断数组是否为严格递增。时间复杂度是 O(n2)O(n^2),效率低下,适合面试时思考过程,不建议实际使用。
⚡ 解法二:线性扫描断点(推荐)
class Solution:
def minimumRightShifts(self, nums: List[int]) -> int:
cliff, ans = 0, 0
n = len(nums)
if n == 1: return 0
for i in range(n):
if nums[i] > nums[(i + 1) % n]:
cliff += 1
ans = i + 1
if cliff > 1:
return -1
if cliff == 0:
return 0
# 检查旋转后的是否真的递增
rotated = nums[ans:] + nums[:ans]
for i in range(1, n):
if rotated[i] <= rotated[i - 1]:
return -1
return n - ans
🧠 思路细节:
- 记录“断点”数量
cliff。 - 若
cliff == 0:数组本身递增,返回 0。 - 若
cliff == 1:记录断点后的位置ans,尝试从该位置旋转,验证旋转后数组是否递增。 - 若
cliff > 1:说明存在多个下降趋势,不可能变为递增数组,返回 -1。
✅ 正确性验证
nums = [3, 4, 5, 1, 2],断点在索引 2,n - (2 + 1) = 2,答案正确。nums = [1, 3, 5],无断点,返回 0,答案正确。nums = [2, 1, 4],断点在索引 0,但旋转后为[1, 4, 2],不递增,返回 -1。
⏱️ 时间与空间复杂度
- 时间复杂度:O(n),只遍历一次数组和一次判断是否递增。
- 空间复杂度:O(n)(因为需要构造
rotated数组用于判断)。
✨ 总结
这个问题看似简单,却包含了多个关键点:
- 需要理解旋转数组的性质;
- 必须判断是否只有一个断点;
- 注意旋转后的数组不一定符合严格递增的要求,需要额外验证。
这道题训练了我们数组遍历技巧和边界判断能力,同时还体现了从暴力思维到最优解的算法优化路径,是一道很有价值的面试题。
🔚 附完整代码(可直接使用)
class Solution:
def minimumRightShifts(self, nums: List[int]) -> int:
cliff, ans = 0, 0
n = len(nums)
if n == 1: return 0
for i in range(n):
if nums[i] > nums[(i + 1) % n]:
cliff += 1
ans = i + 1
if cliff > 1:
return -1
if cliff == 0:
return 0
# 验证旋转后的数组是否递增
rotated = nums[ans:] + nums[:ans]
for i in range(1, n):
if rotated[i] <= rotated[i - 1]:
return -1
return n - ans
💬 有任何疑问或者其他优化思路,欢迎留言一起讨论!你还可以尝试自己用其他语言(如 C++ / Java)实现这个思路。
1062

被折叠的 条评论
为什么被折叠?



