这是我参与更文挑战的第 10 天,活动详情查看: 更文挑战
调整数组顺序使得奇数位于偶数前面(剑指 Offer 21)
题目描述
输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有奇数位于数组的前半部分,所有偶数位于数组的后半部分。
示例 1:
输入:nums = [1,2,3,4]
输出:[1,3,2,4]
注:[3,1,2,4] 也是正确的答案之一。
提示
0 <= nums.length <= 500001 <= nums[i] <= 10000
思路分析
我们可以使用双指针解法,左侧从 0 开始,右侧从数组尾部开始,不断将左侧的偶数值和右侧的奇数值进行交换,直到左侧指针等于右指针时,停止遍历。返回的数组就是我们想要的奇数在前,偶数在后的数组。
代码展示
解法一:时间复杂度是,空间复杂度是。
//剑指offer 21 调整数组顺序使得奇数位于偶数前面
public int[] exchange(int[] nums) { //1,2,4,3,6,5 //1,3,5,2,4,6
int length = nums.length;
int left = 0;
int right = length - 1;
while (left < right){
if (nums[left] % 2 == 0){ //偶数
if (nums[right] % 2 == 0){ //right 也是偶数
right--;
} else { //right奇数
int temp = nums[right];
nums[right] = nums[left];
nums[left] = temp;
left++;
right--;
}
} else { //奇数
left++;
}
}
return nums;
}
颜色分类(75)
题目描述
给定一个包含红色、白色和蓝色,一共 n 个元素的数组,原地对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。
此题中,我们使用整数 0、 1 和 2 分别表示红色、白色和蓝色。
示例 1:
输入:nums = [2,0,2,1,1,0]
输出:[0,0,1,1,2,2]
示例 2:
输入:nums = [2,0,1]
输出:[0,1,2]
示例 3:
输入:nums = [0]
输出:[0]
示例 4:
输入:nums = [1]
输出:[1]
提示
n == nums.length1 <= n <= 300nums[i]为0、1或2
进阶
- 你可以不使用代码库中的排序函数来解决这道题吗?
- 你能想出一个仅使用常数空间的一趟扫描算法吗?
思路分析
不推荐使用官方的排序函数,而且仅仅使用常数空间,也就是说空间复杂度是,因为有三个颜色,所以我们可以先把前面两个颜色先归为一种,然后也是利用双指针解法,统一把 2 移到后面,在将 2 排序好之后在区分 0 和 1,也是利用双指针解法进行解答。
不过颜色问题还有一个注意点,在第二次判断时,也要过滤 nums[right] = 2 的情况,因为存在第一次遍历判断时不变的情况,所以这里还需要注意一下。我们可以用一些简单的案例,比如 {0,1},{1,2}等情况进行简单的代入。
代码展示
解法一:时间复杂度是,空间复杂度是。
public void sortColors(int[] nums) { //1,2
int left = 0;
int right = nums.length - 1;
//先将0,1移到左侧,2移到右侧
while (left < right){
if (nums[left] == 2){
if (nums[right] != 2){
nums[left++] = nums[right];
nums[right--] = 2;
} else {
right--;
}
} else {
left++;
}
}
//0移到左侧,1移到右侧,2已经在最右侧了
left = 0;
while (left < right){
if (nums[left] == 1){
if (nums[right] != 1 && nums[right] != 2){ //需要特殊注意,这里也要判断不能为2,因为第一个while 可能被直接跳过比如: [1,2]
nums[left++] = nums[right];
nums[right--] = 1;
} else {
right--;
}
} else {
left++;
}
}
}
总结
对于这类问题,我们可以将问题分解,然后利用双指针解法,直接在原地处理。