给你一个数组 nums 。nums 的源数组中,所有元素与 nums 相同,但按非递减顺序排列。
如果 nums 能够由源数组轮转若干位置(包括 0 个位置)得到,则返回 true;否则,返回 false 。
源数组中可能存在 重复项 。
注意: 数组 A 在轮转 x 个位置后得到长度相同的数组 B ,使得对于每一个有效的下标 i,满足 B[i] == A[(i+x) % A.length]。
示例 1:
输入:nums = [3,4,5,1,2]
输出:true
解释:[1,2,3,4,5] 为有序的源数组。
可以轮转 x = 2 个位置,使新数组从值为 3 的元素开始:[3,4,5,1,2] 。
示例 2:
输入:nums = [2,1,3,4]
输出:false
解释:源数组无法经轮转得到 nums 。
示例 3:
输入:nums = [1,2,3]
输出:true
解释:[1,2,3] 为有序的源数组。
可以轮转 x = 0 个位置(即不轮转)得到 nums 。
提示:
1 <= nums.length <= 1001 <= nums[i] <= 100
分析: 如果一个数组是由非递减数组轮转得到的,那么它整体上应该由两段非递减区间组成。第一段:轮转后排在前面的较大部分;第二段:轮转后排在后面的较小部分。 其中左右两段各自都是非递减的,并且左段的最小值也应该大于等于右段的最大值。
因此,核心思路是找到数组中第一次出现下降的位置,即可以看作轮转断点的位置。如果整个数组中没有下降位置,说明数组本身就是非递减的,可以认为它是轮转 0 次得到的,直接返回 true。
如果找到了下降位置,则需要判断两件事:第一,断点右侧是否仍然保持非递减;第二,左半段和右半段拼接起来后,是否满足轮转数组的大小关系。
由于数组长度最大为 100,可以遍历整个数组,检查每个点是否满足断点情况。
cpp
class Solution {
public:
bool check(vector<int>& nums) {
int n=nums.size(),l_mini=nums[0],l_maxn=0,r_mini=101,r_maxn=nums[n-1],f=0,pos=0;
for(int i=1;i+1<n&&!f;++i)
{
if(nums[i]>=nums[i-1])
{
if(nums[i]>nums[i+1])
l_maxn=nums[i],r_mini=nums[i+1],f=1,pos=i+1;
else if(nums[i]>=nums[i+1])
continue;
}
else l_maxn=nums[i-1],r_mini=nums[i],f=1,pos=i+1;
}
if(f)
{
for(int i=pos+1;i<n;++i)
{
if(nums[i]<nums[i-1])return false;
}
}
if(!f||(l_mini>=r_maxn&&l_mini<=l_maxn&&r_mini<=r_maxn))return true;
return false;
}
};