持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第26天,点击查看活动详情
前言
题目来源
题目介绍
给定一个包含红色、白色和蓝色、共 n 个元素的数组 nums ,原地对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。
我们使用整数 0、 1 和 2 分别表示红色、白色和蓝色。
必须在不使用库的sort函数的情况下解决这个问题。
输入: nums = [2,0,2,1,1,0]
输出: [0,0,1,1,2,2]
题目分析
根据题目和示意,我们知道就是按顺序排放元素,按从小到大排序。因此可以知道应该循环数组,遍历元素,比较当前元素和后面元素的大小,如果碰到比自己大的就交换位置。
题目解答
class Solution {
public void sortColors(int[] nums) {
int numsSize=nums.length;
//遍历循环整个数组
for (int i = 0; i < numsSize - 1; i++) {
//每个数组元素和剩下的元素相比较
for (int j = i + 1; j < numsSize; j++) {
//如果当前元素比剩余元素大,那么交换2个的位置
if (nums[j] < nums[i]) {
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
}
}
}
}
这里进行了2次for循环,值的注意的是,第一层遍历只需要遍历到倒数第二个元素就行,因此numsSize - 1,内部在来一个for循环,遍历后面的元素(i+1),一直到最后一个,然后比较大小,大的就往后移动交换位置。,结果如下
用了2个for循环,还是比较耗性能,不是那么完美。
官方答案分析
class Solution {
public void sortColors(int[] nums) {
int n = nums.length;
int ptr = 0;
for (int i = 0; i < n; ++i) {
if (nums[i] == 0) {
int temp = nums[i];
nums[i] = nums[ptr];
nums[ptr] = temp;
++ptr;
}
}
for (int i = ptr; i < n; ++i) {
if (nums[i] == 1) {
int temp = nums[i];
nums[i] = nums[ptr];
nums[ptr] = temp;
++ptr;
}
}
}
}
官方的思路是在第一次遍历中,从左向右遍历整个数组,如果找到了 0,那么就需要将 0 与「头部」位置的元素进行交换,并将「头部」向后扩充一个位置。在遍历结束之后,所有的 0 都被交换到「头部」的范围,并且「头部」只包含 0。
在第二次遍历中,我们从「头部」开始,从左向右遍历整个数组,如果找到了 1,那么就需要将 1 与「头部」位置的元素进行交换,并将「头部」向后扩充一个位置。在遍历结束之后,所有的 1 都被交换到「头部」的范围,并且都在 0 之后,此时 2 只出现在「头部」之外的位置,因此排序完成。
可以看出这种方式执行效率高了很多。
总结
可以看出这题还是数组类问题,要理解遍历循环、交换位置、排序等概念。