leetcode
leetcode 2401 ~ 2450
使数组成为递增数组的最少右移次数

使数组成为递增数组的最少右移次数

难度:

标签:

题目描述

You are given a 0-indexed array nums of length n containing distinct positive integers. Return the minimum number of right shifts required to sort nums and -1 if this is not possible.

A right shift is defined as shifting the element at index i to index (i + 1) % n, for all indices.

 

Example 1:

Input: nums = [3,4,5,1,2]
Output: 2
Explanation: 
After the first right shift, nums = [2,3,4,5,1].
After the second right shift, nums = [1,2,3,4,5].
Now nums is sorted; therefore the answer is 2.

Example 2:

Input: nums = [1,3,5]
Output: 0
Explanation: nums is already sorted therefore, the answer is 0.

Example 3:

Input: nums = [2,1,4]
Output: -1
Explanation: It's impossible to sort the array using right shifts.

 

Constraints:

  • 1 <= nums.length <= 100
  • 1 <= nums[i] <= 100
  • nums contains distinct integers.

代码结果

运行时间: 28 ms, 内存: 16.0 MB


/*
 题目思路:
 使用Java Stream来简化代码。
 利用Stream生成一个顺序流,模拟右移操作并判断是否为递增数组。
 使用IntStream.iterate生成从0到n的流,对每一个右移次数,生成一个新的数组,并检查其是否为递增。
 如果存在递增的情况,则返回相应的右移次数;否则,返回-1。
*/
import java.util.stream.IntStream;

public class SolutionStream {
    public int minRightShifts(int[] nums) {
        int n = nums.length;
        return IntStream.range(0, n)
                .filter(shift -> IntStream.range(0, n - 1)
                        .allMatch(i -> nums[(i + shift) % n] < nums[(i + shift + 1) % n]))
                .findFirst()
                .orElse(-1);
    }
}

解释

方法:

该题解通过首先检查数组中的断点(即当前元素比前一个元素小的位置)来确定数组的非递增部分的起点。如果没有找到这样的断点,说明数组已经是递增的,直接返回0。找到断点后,算法检查从这个断点开始的数组是否可以通过一次循环变成递增数组。它通过遍历断点开始的数组,并检查是否每个元素都小于其后继元素来实现。如果在某点发现非递增序列,则返回-1,表示无法通过右移操作使数组递增。如果通过所有检查,返回从数组起始位置到断点的距离作为最小右移次数。

时间复杂度:

O(n)

空间复杂度:

O(1)

代码细节讲解

🦆
在题解中你是如何确定数组的'非递增断点'位置的?这个方法是否总是准确无误?
在题解中,非递增断点的位置是通过遍历数组并检查每对相邻元素来确定的。如果找到第一对相邻元素,其中后一个元素小于前一个元素,那么后一个元素的位置被标记为非递增断点。这种方法在确定首个非递增断点上是准确的,因为它直接响应数组中第一个出现逆序的位置。然而,它仅关注第一个逆序点,可能会忽略后续的逆序情况,但对于解决这个特定问题是足够的。
🦆
题解中提到如果没有找到非递增的断点,则数组已经是递增的。这个结论是否对所有情况都适用,包括数组中只有一个元素的情况?
是的,这个结论对所有情况都适用,包括数组中只有一个元素的情况。如果数组只有一个元素,由于没有相邻的元素比较,自然不会存在元素小于前一个元素的情况,因此,这样的单元素数组默认是递增的,返回0移动次数是正确的。
🦆
题解中使用了表达式`(s+i)%n`来实现数组的循环访问。这种方法在什么情况下可能会出现问题?
表达式`(s+i)%n`用于循环访问数组,确保算法可以从断点处开始检查并绕回数组的起始处继续比较。这种循环访问方法理论上适用于任何情况,不会出现问题,只要数组的长度`n`是正整数。这种方法确保即使索引超过数组长度,也能正确地回到数组的开始,进行循环比较。
🦆
题解中提到如果从断点开始的数组不能通过完整循环变为递增数组就返回-1。请问这是否意味着即使部分元素通过右移可以形成递增序列,也会因为其他元素的不匹配而整体失败?
是的,题解中的方法确实意味着即使部分元素通过右移可以形成递增序列,如果整个数组不能通过一次完整的循环检查形成完全的递增序列,则整体会判定为失败,返回-1。这种方法确保只有当整个数组可以通过单次右移变为递增时才认为操作成功。这样做是为了确保解决方案的全局有效性,而不仅仅是局部的递增。

相关问题