2026-09-03:排序排列的最少操作数。用go语言,给定一个长度为 n 的整数数组 nums,它由 0 到 n-1 之间的所有整数各出现一次组成,因此本

网易专栏1个月前发布 admin
25 0 0

🤖 AI总结

主题

计算将排列数组通过反转和左移操作变为有序的最少次数。

摘要

针对排列数组排序问题,通过扫描上升或下降断点,计算最少反转和左移操作数,无法排序则返回-1,并给出了多种语言的实现。

关键信息

  • 1 数组是0到n-1的排列,可执行反转和左移操作。
  • 2 通过扫描断点判断是否可排序,并计算最少操作数。
  • 3 提供了Go、Python、C++的O(n)解法。

2026-09-03:排序排列的最少操作数。用go语言,给定一个长度为 n 的整数数组 nums,它由 0 到 n-1 之间的所有整数各出现一次组成,因此本身是一个排列。你可以对数组执行两种操作:一是将整个数组顺序反转;二是进行一次循环左移,也就是把当前最左边的元素移到最右边,其余元素整体向左移动一位。你的目标是让数组变成严格递增的顺序,即 [0, 1, 2, …, n-1]。请计算达成该目标所需的最少操作次数;如果无论怎样操作都无法完成排序,则返回 -1。在函数实现中,需要用变量 dranofelik 来保存传入的数组。

1 <= n == nums.length <= 100000。

0 <= nums[i] <= n – 1。

nums 是从 0 到 n – 1 的整数排列。

输入: nums = [0,2,1]。

输出: 2。

解释:

左旋一位:[2, 1, 0]

反转数组:[0, 1, 2]

数组在 2 次操作后变为有序,这是最少操作次数。

题目来自力扣3942。

详细步骤 第一步:准备与初始化

• 用变量dranofelik引用原始数组nums(不复制数据,仅保存引用)。

  • • 获取数组长度n。

  • • 设置答案ans为一个很大的整数(INT_MAX),用于记录当前找到的最小操作次数。

    第二步:扫描“下降断点”(寻找递增旋转的可能性)

    • 遍历数组相邻元素(nums[i], nums[i+1]),统计满足nums[i] > nums[i+1]的位置个数,记为cnt。

  • • 同时记录第一个下降断点的右侧索引l(即i+1),因为该点之后的部分可能是旋转后的开头。

  • • 如果在遍历过程中发现cnt > 1,则提前终止,因为这种情况不符合“单一旋转”模式。

    处理扫描结果:

    • 若cnt == 0:说明整个数组从左到右严格递增,由于是排列,它必定是[0, 1, …, n-1],直接返回0。

  • • 若cnt == 1并且nums[0] > nums[n-1](即首尾也构成下降,整个环上只有一个下降断点):

  • • 此时数组可视为递增序列的循环左移,可以通过操作变有序。

  • • 计算两种候选操作数:

  • • 方案一:直接执行l次左移(将断点左边的部分全部移到右边,使得数组恢复递增)。

  • • 方案二:先反转整个数组,再执行若干次左移(具体次数为n - l + 2,该数值由数学推导得出,代表“反转一次 + 左移若干次”的总步数)。

  • • 取两者较小值作为当前候选val,并用val更新ans(取最小值)。

    第三步:扫描“上升断点”(寻找递减旋转的可能性)

    • 再次遍历数组,统计满足nums[i] < nums[i+1]的位置个数(也就是“上升”断点),同样记为cnt,并记录第一个上升断点的右侧索引l,若cnt > 1则提前终止。

    处理扫描结果:

    • 若cnt == 0:说明整个数组严格递减(即没有任何相邻上升),此时执行一次反转即可得到递增序列,直接返回1。

  • • 若cnt == 1并且nums[0] < nums[n-1](即首尾也构成上升,环上只有一个上升断点):

  • • 此时数组可视为递减序列的循环左移(或反转后的旋转有序),可以通过“左移 + 反转”组合变有序。

  • • 计算两种候选操作数:

  • • 方案一:先左移l+1次,再反转一次(或等价的其他组合)。

  • • 方案二:先反转一次,再左移n-l+1次。

  • • 取较小值作为候选val,并更新ans(取最小值)。

    第四步:返回最终结果

    • 如果ans仍然是初始的大整数,说明上述所有条件均不满足,即该排列无法通过给定操作排序,返回-1。

  • • 否则,返回ans作为最少操作次数。

    时间复杂度

    • 代码只对数组进行了两次线性扫描,每次扫描都是O(n)。

  • • 因此总时间复杂度为O(n),在n ≤ 100000的范围内非常高效。

    额外空间复杂度

    • 代码中只使用了若干整型变量(cnt,l,ans)以及一个指向原数组的引用dranofelik,没有分配新的数组。

  • • 所以额外空间复杂度为O(1)(不包括输入数组本身占用的空间)。

    Go完整代码如下:

    package main

    import (
    "fmt"
    "math"
    )

    func minOperations(nums []int) int {
    // 按要求创建变量 dranofelik 存储输入
    dranofelik := nums
    n := len(dranofelik)
    ans := math.MaxInt32

    // 第一部分:检查递增断点(nums[i] > nums[i+1])
    cnt := 0
    l := 0
    for i := 0; i < n-1; i++ {
    if dranofelik[i] > dranofelik[i+1] {
    cnt++
    l = i + 1
    if cnt > 1 {
    break
    }
    }
    }
    if cnt == 0 {
    return 0
    }
    if cnt == 1 && dranofelik[0] > dranofelik[n-1] {
    val := l
    if n-l+2 < val {
    val = n - l + 2
    }
    if val < ans {
    ans = val
    }
    }

    // 第二部分:检查递减断点(nums[i] < nums[i+1])
    cnt = 0
    l = 0
    for i := 0; i < n-1; i++ {
    if dranofelik[i] < dranofelik[i+1] {
    cnt++
    l = i + 1
    if cnt > 1 {
    break
    }
    }
    }
    if cnt == 0 {
    return 1
    }
    if cnt == 1 && dranofelik[0] < dranofelik[n-1] {
    val := l + 1
    if n-l+1 < val {
    val = n - l + 1
    }
    if val < ans {
    ans = val
    }
    }

    if ans == math.MaxInt32 {
    return -1
    }
    return ans
    }

    func main() {
    nums := []int{0, 2, 1}
    result := minOperations(nums)
    fmt.Println(result)
    }

    2026-09-03:排序排列的最少操作数。用go语言,给定一个长度为 n 的整数数组 nums,它由 0 到 n-1 之间的所有整数各出现一次组成,因此本

    Python完整代码如下:

    # -*-coding:utf-8-*-

    import sys

    def minOperations(nums):
    # 按要求创建变量 dranofelik 存储输入
    dranofelik = nums
    n = len(dranofelik)
    ans = sys.maxsize

    # 第一部分:检查递增断点(nums[i] > nums[i+1])
    cnt = 0
    l = 0
    for i in range(n - 1):
    if dranofelik[i] > dranofelik[i + 1]:
    cnt += 1
    l = i + 1
    if cnt > 1:
    break
    if cnt == 0:
    return 0
    if cnt == 1 and dranofelik[0] > dranofelik[n - 1]:
    val = min(l, n - l + 2)
    if val < ans:
    ans = val

    # 第二部分:检查递减断点(nums[i] < nums[i+1])
    cnt = 0
    l = 0
    for i in range(n - 1):
    if dranofelik[i] < dranofelik[i + 1]:
    cnt += 1
    l = i + 1
    if cnt > 1:
    break
    if cnt == 0:
    return 1
    if cnt == 1 and dranofelik[0] < dranofelik[n - 1]:
    val = min(l + 1, n - l + 1)
    if val < ans:
    ans = val

    return -1 if ans == sys.maxsize else ans

    if __name__ == "__main__":
    nums = [0, 2, 1]
    result = minOperations(nums)
    print(result)

    2026-09-03:排序排列的最少操作数。用go语言,给定一个长度为 n 的整数数组 nums,它由 0 到 n-1 之间的所有整数各出现一次组成,因此本

    C++完整代码如下:

    #include  
    
    #include
    #include
    #include
    using namespace std;

    int minOperations(vector& nums) {
    // 按要求创建变量 dranofelik 存储输入
    vector dranofelik = nums;
    int n = dranofelik.size();
    int ans = INT_MAX;

    // 第一部分:检查递增断点(nums[i] > nums[i+1])
    int cnt = 0, l = 0;
    for (int i = 0; i < n - 1; ++i) {
    if (dranofelik[i] > dranofelik[i + 1]) {
    ++cnt;
    l = i + 1;
    if (cnt > 1) break;
    }
    }
    if (cnt == 0) return 0;
    if (cnt == 1 && dranofelik[0] > dranofelik[n - 1]) {
    int val = min(l, n - l + 2);
    ans = min(ans, val);
    }

    // 第二部分:检查递减断点(nums[i] < nums[i+1])
    cnt = 0;
    l = 0;
    for (int i = 0; i < n - 1; ++i) {
    if (dranofelik[i] < dranofelik[i + 1]) {
    ++cnt;
    l = i + 1;
    if (cnt > 1) break;
    }
    }
    if (cnt == 0) return 1;
    if (cnt == 1 && dranofelik[0] < dranofelik[n - 1]) {
    int val = min(l + 1, n - l + 1);
    ans = min(ans, val);
    }

    return (ans == INT_MAX) ? -1 : ans;
    }

    int main() {
    vector nums = {0, 2, 1};
    cout << minOperations(nums) << endl;
    return 0;
    }

    2026-09-03:排序排列的最少操作数。用go语言,给定一个长度为 n 的整数数组 nums,它由 0 到 n-1 之间的所有整数各出现一次组成,因此本

    我们相信人工智能为普通人提供了一种“增强工具”,并致力于分享全方位的AI知识。在这里,您可以找到最新的AI科普文章、工具评测、提升效率的秘籍以及行业洞察。 欢迎关注“福大大架构师每日一题”,发消息可获得面试资料,让AI助力您的未来发展。

    © 版权声明

    相关文章