Given an array nums of integers and an int k, partition the array (i.e move the elements in "nums") such that:
* All elements < k are moved to the left
* All elements >= k are moved to the right
Return the partitioning index, i.e the first index i nums[i] >= k.
Example
If nums = [3,2,2,1] and k=2, a valid answer is 1.
Challenge
Can you partition the array in-place and in O(n)?
Notice
You should do really partition in array nums instead of just counting the numbers of integers smaller than k.
If all elements in nums are smaller than k, then return nums.length
双指针,类似quickSort中找左右不合格元素互换,直到左右交汇。
细节:
1.基本直接返回left即可,多加一个额外check。因为left左边都是<k的元素,而且left指着的又是>=k的元素(除了全小的corner case),当然就是第一个>=k的了。
2.具体穷举解释一下为什么L或者检查一下后L+1就肯定是第一个>=k的元素了。退出一定是发生在 a)刚换完相邻的两个LR,两指针交叉了,L指着>=k的元素。b)刚换完隔一元素的两个LXR,两指针指着同一个未检查的元素,所以要检查(但下一个也就是原来R那个位置的肯定是刚换过的合格的>=k的元素了)c)换完两个隔很远的元素,L一直扫到R,L指着一个未检查的元素,但下一个肯定是刚换过的合格>=k元素。d)换完两个隔很远的元素,L动到了第一个>=k的元素,R一直扫到L,L还是指着合格元素。
我的实现
public class Solution { /** * @param nums: The integer array you should partition * @param k: An integer * @return: The index after partition */ public int partitionArray(int[] nums, int k) { // write your code here if (nums == null || nums.length == 0) { return 0; } int left = 0, right = nums.length - 1; while (left < right) { while (left < right && nums[left] < k) { left++; } while (left < right && nums[right] >= k) { right--; } if (left < right) { int temp = nums[left]; nums[left] = nums[right]; nums[right] = temp; left++; right--; } } // IMPORTANT. if (nums[left] < k) { left++; } return left; } }