力扣链接:75. 颜色分类,难度等级:中等。
给定一个包含红色、白色和蓝色、共 n 个元素的数组 nums,原地对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。
我们使用整数 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]
约束:
n == nums.length1 <= n <= 300nums[i]为0、1或2- 进阶:你能想出一个仅使用常数空间的一趟扫描算法吗?
提示 1
A rather straight forward solution is a two-pass algorithm using counting sort.
提示 2
Iterate the array counting number of 0's, 1's, and 2's.
提示 3
Overwrite array with the total number of 0's, then 1's and followed by 2's.
思路
题目要求我们原地对只包含 0、1、2 的数组进行排序。进阶挑战是仅使用常数额外空间,在单次遍历(一趟扫描)中完成。
这正是由 Edsger W. Dijkstra 提出的著名的“荷兰国旗问题”(Dutch National Flag problem)。我们可以使用三个指针来解决它,将数组划分为三个主要区域:开头的 0 区域,结尾的 2 区域,以及当前正在处理的元素区域(这会自然而然地把 1 留在中间)。
👋 站长寄语:我还为你开发了 coder.id - 打造程序员个人IP, 包含作品集、简历和博客等,助您顺利拿到 Offer!
步骤
- 初始化三个指针:
low = 0(0 的边界),high = nums.length - 1(2 的边界),以及i = 0(当前正在遍历的元素索引)。 - 当
i <= high时,进行循环:- 如果
nums[i] == 0:交换nums[i]和nums[low]。我们知道从low交换过来的元素必定是0或1(因为i已经扫描过那里或者和low重合),所以可以安全地将low和i都加 1。 - 如果
nums[i] == 1:元素已经处于中间的正确位置,只需将i加 1 即可。 - 如果
nums[i] == 2:交换nums[i]和nums[high]。我们将high减 1。但是,我们不要在这里将i加 1,因为从high换到i位置的新元素还没有被检查过(它可能是0、1或2)。
- 如果
- 当
i越过high时,数组就已经排序完成了。
复杂度
时间复杂度
O(N)
空间复杂度
O(1)
解释
- 时间复杂度:
O(N),其中N是数组nums的长度。我们最多处理每个元素两次(被i遍历到,或者从high交换过来再被检查),这意味着我们只对数组进行了一趟扫描。 - 空间复杂度:
O(1)。排序完全是原地进行的,仅使用了三个整型变量作为指针,只需要常数级别的额外空间。
Python #
class Solution:
def sortColors(self, nums: List[int]) -> None:
"""
Do not return anything, modify nums in-place instead.
"""
# low points to the next position for 0
# high points to the next position for 2
low, i, high = 0, 0, len(nums) - 1
while i <= high:
if nums[i] == 0:
# Swap and advance both low and i
nums[low], nums[i] = nums[i], nums[low]
low += 1
i += 1
elif nums[i] == 2:
# Swap and decrement high. Do NOT advance i yet
# because the swapped element needs to be checked
nums[high], nums[i] = nums[i], nums[high]
high -= 1
else:
# nums[i] == 1, already in place
i += 1
Java #
class Solution {
public void sortColors(int[] nums) {
int low = 0;
int i = 0;
int high = nums.length - 1;
while (i <= high) {
if (nums[i] == 0) {
swap(nums, low, i);
low++;
i++;
} else if (nums[i] == 2) {
swap(nums, i, high);
high--;
// Don't increment 'i' here, the new nums[i] needs to be evaluated
} else {
// nums[i] == 1
i++;
}
}
}
private void swap(int[] nums, int a, int b) {
int temp = nums[a];
nums[a] = nums[b];
nums[b] = temp;
}
}
JavaScript #
/**
* @param {number[]} nums
* @return {void} Do not return anything, modify nums in-place instead.
*/
var sortColors = function(nums) {
let low = 0;
let i = 0;
let high = nums.length - 1;
while (i <= high) {
if (nums[i] === 0) {
// Swap nums[low] and nums[i]
[nums[low], nums[i]] = [nums[i], nums[low]];
low++;
i++;
} else if (nums[i] === 2) {
// Swap nums[i] and nums[high]
[nums[high], nums[i]] = [nums[i], nums[high]];
high--;
// Do not increment i, evaluate the newly swapped element
} else {
// If it is 1, just move forward
i++;
}
}
};
Cpp #
class Solution {
public:
void sortColors(vector<int>& nums) {
int low = 0;
int i = 0;
int high = nums.size() - 1;
while (i <= high) {
if (nums[i] == 0) {
swap(nums[low], nums[i]);
low++;
i++;
} else if (nums[i] == 2) {
swap(nums[i], nums[high]);
high--;
// Note: i is not incremented
} else {
// nums[i] == 1
i++;
}
}
}
};
Csharp #
public class Solution {
public void SortColors(int[] nums) {
int low = 0;
int i = 0;
int high = nums.Length - 1;
while (i <= high) {
if (nums[i] == 0) {
// Swap
int temp = nums[low];
nums[low] = nums[i];
nums[i] = temp;
low++;
i++;
} else if (nums[i] == 2) {
// Swap
int temp = nums[high];
nums[high] = nums[i];
nums[i] = temp;
high--;
} else {
i++;
}
}
}
}
Go #
func sortColors(nums []int) {
low := 0
i := 0
high := len(nums) - 1
for i <= high {
if nums[i] == 0 {
nums[low], nums[i] = nums[i], nums[low]
low++
i++
} else if nums[i] == 2 {
nums[high], nums[i] = nums[i], nums[high]
high--
} else {
// nums[i] == 1
i++
}
}
}
Ruby #
# @param {Integer[]} nums
# @return {Void} Do not return anything, modify nums in-place instead.
def sort_colors(nums)
low = 0
i = 0
high = nums.length - 1
while i <= high
if nums[i] == 0
nums[low], nums[i] = nums[i], nums[low]
low += 1
i += 1
elsif nums[i] == 2
nums[high], nums[i] = nums[i], nums[high]
high -= 1
else
i += 1
end
end
end
Rust #
impl Solution {
pub fn sort_colors(nums: &mut Vec<i32>) {
let mut low = 0;
let mut i = 0;
let mut high = nums.len() as i32 - 1;
while (i as i32) <= high {
match nums[i] {
0 => {
nums.swap(low, i);
low += 1;
i += 1;
}
2 => {
nums.swap(i, high as usize);
high -= 1;
}
_ => {
// It's 1
i += 1;
}
}
}
}
}
Kotlin #
class Solution {
fun sortColors(nums: IntArray): Unit {
var low = 0
var i = 0
var high = nums.size - 1
while (i <= high) {
when (nums[i]) {
0 -> {
val temp = nums[low]
nums[low] = nums[i]
nums[i] = temp
low++
i++
}
2 -> {
val temp = nums[high]
nums[high] = nums[i]
nums[i] = temp
high--
}
else -> {
i++
}
}
}
}
}
Swift #
class Solution {
func sortColors(_ nums: inout [Int]) {
var low = 0
var i = 0
var high = nums.count - 1
while i <= high {
if nums[i] == 0 {
nums.swapAt(low, i)
low += 1
i += 1
} else if nums[i] == 2 {
nums.swapAt(i, high)
high -= 1
} else {
i += 1
}
}
}
}
其它语言
欢迎贡献代码到 GitHub repo -> 75. 颜色分类。感谢!打造你的开发者个人IP
- 📄 简历 + 作品集 + 博客
- 🌐 支持绑定自定义域名
- ✨ 顶级子域名:
https://yourname.coder.id