数组 A 是 [0, 1, ..., N - 1] 的一种排列,N 是数组 A 的长度。全局倒置指的是 i,j 满足 0 <= i < j < N 并且 A[i] > A[j] ,局部倒置指的是 i 满足 0 <= i < N 并且 A[i] > A[i+1] 。
当数组 A 中全局倒置的数量等于局部倒置的数量时,返回 true 。
示例 1:
输入: A = [1,0,2]
输出: true
解释: 有 1 个全局倒置,和 1 个局部倒置。
示例 2:
输入: A = [1,2,0]
输出: false
解释: 有 2 个全局倒置,和 1 个局部倒置。
注意:
A 是 [0, 1, ..., A.length - 1] 的一种排列
A 的长度在 [1, 5000]之间
这个问题的时间限制已经减少了。
方法一:两层循环暴力(按理说n只有5000,暴力是肯定能过的,但是出题人故意卡时间了)
class Solution {
public boolean isIdealPermutation(int[] A) {
int sum1=0,sum2=0;
for(int i=0;i<A.length;i++) {
if(i+1<A.length && A[i]>A[i+1])
sum2++;
for(int j=i+1;j<A.length;j++)
if(A[i]>A[j]) sum1++;
}
return sum1==sum2;
}
}
方法二:树状数组(归并排序也可以)
对于局部倒置我们直接遍历一遍就行,而全局导致仔细看其实就是求的数组的逆序数呀,这还不简单吗,树状数组或者归并排序完美解决,ok了。
class Solution {
class node implements Comparable<node>{
int val;
int index;
public node(int val,int index) {
this.val=val;
this.index=index;
}
@Override
public int compareTo(node o) {
// TODO 自动生成的方法存根
if(val==o.val)
return index-o.index;
return val-o.val;
}
}
int[] c;
int sum1,sum2;
public boolean isIdealPermutation(int[] A) {
sum1=0;sum2=0;
int n=A.length;
c=new int[n+1];
node[] arr=new node[n];
for(int i=0;i<n;i++) {
arr[i]=new node(A[i],i+1);
if(i+1<n && A[i]>A[i+1])
sum2++;
}
Arrays.parallelSort(arr);
for(int i=0;i<n;i++) {
update(arr[i].index,n);
sum1+=query(arr[i].index-1);
}
sum1=n*(n-1)/2-sum1;
return sum1==sum2;
}
private void update(int x,int n) {
while(x<=n) {
c[x]++;
x+=x&-x;
}
}
private int query(int x) {
int res=0;
while(x>0) {
res+=c[x];
x-=x&-x;
}
return res;
}
}
方法三:最小值。想想什么时候sum1才不等于sum2,不就是存在j >= i+2
的 A[i] > A[j]的情况嘛,我们可以从后往前遍历记录最小值,如果存在以上情况直接return false即可。
class Solution {
public boolean isIdealPermutation(int[] A) {
int mn=A.length;
int sum1=0,sum2=0;
for(int i=A.length-1;i>=2;i--) {
mn=Math.min(mn, A[i]);
if(A[i-2]>mn) return false;
}
return true;
}
}
方法四:线性搜索(官方题解的一个方法)
假设有一个长度为 n,其中元素为 0 到 n-1 的数组。对于这种数组,定义 理想 排列为该数组的一个不存在非局部倒置的排列。
对于 理想 排列,0 应该在哪里呢? 如果 0 的下标大于等于 2,一定会有 A[0] > A[2] = 0,这是一个非局部倒置。所以 0 只能出现在下标 0 或者下标 1。当 A[1] = 0,显然 A[0] = 1,否则就会有 A[0] > A[j] = 1,这也是一个非局部倒置。当 A[0] = 0,这时候问题就转化成了一个子问题。
根据上述讨论,可以归纳出 理想 数组的充分必要条件为 Math.abs(A[i] - i) <= 1。
class Solution {
public boolean isIdealPermutation(int[] A) {
for(int i=0;i<A.length;i++)
if(Math.abs(A[i]-i)>1)
return false;
return true;
}
}