915.分割数组
题目描述
给定一个数组 nums ,将其划分为两个连续子数组 left 和 right, 使得:
left 中的每个元素都小于或等于 right 中的每个元素。
left 和 right 都是非空的。
left 的长度要尽可能小。
在完成这样的分组后返回 left 的 长度 。
用例可以保证存在这样的划分方法。
示例图片
解题思路
方法:首先根据题目描述,我们很快的能发现:
1.分割数组的那个位置一定在整个数组的最小值和最大值之间。
2.最小值一定在最大值的左边。
3.left数组的最大值总是比right数组的最小值要小。
因此,不妨先找到数组最大值和最小值的位置,同时,找到最小值位置之前的最大值,和最大值位置之后的最小值(有点绕,好好理解)。例如示例1,最小值是0,最大值是8, 最小值之前的最大值是5,最大值之后的最小值是6。
然后,在最小值和最大值位置之间,我们利用类似快速排序算法的方式,分别向左和向右遍历,知道两个遍历指针相邻,则找到分割数组的位置。
代码
int partitionDisjoint(int* nums, int numsSize){
int min=nums[0]; int max=nums[0]; //整个数组的最大值和最小值
int l_max=nums[0]; int r_min=nums[numsSize-1]; //左右数组的最大值和最小值
int i,j;
int low=0; int high=numsSize-1;
if(numsSize<=2){ return 1; }
//找整个数组最大值和最小值的位置
for(i=1;i<numsSize;i++){
if(min>=nums[i]){ min=nums[i]; low=i; }
if(max<=nums[i]){ max=nums[i]; high=i; }
}
//找最小值位置之前的最大值
for(i=1;i<=low;i++){
if(l_max<nums[i]){ l_max=nums[i]; }
}
for(i=numsSize-1;i>=high;i--){
if(r_min>nums[i]){ r_min=nums[i]; }
}
//遍历
while(low!=(high-1)){
while(l_max<=r_min && low!=(high-1)){
high--;
if(r_min>nums[high]){ r_min=nums[high]; }
}
if(l_max>r_min){ r_min=nums[++high]; }
while(l_max<=r_min && low!=(high-1)){
low++;
if(l_max<nums[low]){ l_max=nums[low]; }
}
}
return low+1;
}
提交结果
用的方法比较笨,没有优化,有更好的方法欢迎补充。