1 题目
题目:数组划分(Partition Array)
描述:给出一个整数数组 nums 和一个整数 k。划分数组(即移动数组 nums 中的元素),使得:所有小于k的元素移到左边、所有大于等于k的元素移到右边,返回数组划分的位置,即数组中第一个位置 i,满足 nums[i] 大于等于 k。
- 你应该真正的划分数组 nums,而不仅仅只是计算比 k 小的整数数,如果数组 nums 中的所有元素都比 k 小,则返回 nums.length。
lintcode题号——31,难度——medium
样例1:
输入:
nums = []
k = 9
输出:0
解释:空数组,输出0
样例2:
输入:
nums = [3,2,2,1]
k = 2
输出:1
解释:真实的数组为[1,2,2,3].所以返回 1
2 解决方案
2.1 思路
使用对向双指针的方式,两个指针分别从头尾开始向中间走,两个指针配合,左指针寻找左区间中不符合条件的元素,右指针寻找右区间中符合条件的元素,交换两者,不断将符合条件的元素交换入左区间,直到所有符合条件的元素都到左边即可。
2.2 时间复杂度
时间复杂度为O(n)。
2.3 空间复杂度
空间复杂度为O(1)。
3 源码
细节:
- 使用对向双指针的方式。
- 边界判断需要单独对left指向的值进行判断,结果可能在right,也可能在right右边,所以不能在nums.at(left)<k时直接返回right。
C++版本:
/**
* @param nums: The integer array you should partition
* @param k: An integer
* @return: The index after partition
*/
int partitionArray(vector<int> &nums, int k) {
// write your code here
int result = 0;
if (nums.empty())
{
return result;
}
int left = 0;
int right = nums.size() - 1;
while (left < right) // 与快排不同,快排为left<=right
{
if (nums.at(left) < k)
{
left++;
continue;
}
if (nums.at(right) >= k)
{
right--;
continue;
}
if (left < right)
{
swap(nums.at(left++), nums.at(right--));
}
}
if (nums.at(left) < k)
{
return left + 1; // 使用right的话,无法处理k大于所有数组元素的情况
}
return left;
}