数组分块问题 【刷题反思】
1. 数组分两块
1.1 题目
题目描述:给一个数组 nums ,写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序
请注意,必须在不复制数组的情况下原地对数组进行操作
示例:
输入:
nums = [0,1,0,3,12]
输出:
nums = [1,3,12,0,0]
class Solution
{
public:
void moveZeroes(vector<int>& nums)
{
}
};
1.2 思想
无非是将数组分为三部分,第一部分为非0元素,第二部分为全0元素,第三部分为待扫描元素
我们可以定义一个下标 cur 来作为分界线,定义 i 来遍历数组,[ 0,cur ]为非0元素,[ cur+1,i ]为0元素,[ i,n-1 ]为待扫描元素
1.3 模拟实现
#include<vector>
class Solution
{
public:
void moveZeroes(vector<int>& nums)
{
//定义cur表示非0和0两块的分界线,i来遍历数组
//因为,cur标记[ 0,cur ],所以cur初始为0
int cur = -1, i = 0;
while (i != nums.size())
{
//如果nums[i]==0,直接i++,将这个数纳入[cur+1,i]这个范围
if (nums[i] == 0) i++;
//如果nums[i]!=0,已知[0,cur],[cur+1,i],[i,n-1]这3个范围,将nums[cur+1]和nums[i]交
//换,再将cur++,把这个数纳入[0,cur]的范围
else
{
swap(nums[cur + 1], nums[i]);
cur++;
i++;
}
}
}
};
2. 数组分三块
2.1 题目
题目描述:给一个包含红色、白色和蓝色、共 n 个元素的数组 nums1,原地对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列
我们使用整数0、1和2分别表示红色、白色和蓝色
必须在不使用库内置的 sort 函数的情况下解决这个问题
示例:
输入: nums = [ 2,0,2,1,1,0 ]
输出: nums = [ 0,0,1,1,2,2 ]
class Solution {
public:
void sortColors(vector<int>& nums) {
}
};
2.2 思想
和荷兰国旗问题一样,这类问题就是将数组分为三块,我们可以再填加一个指针(数组下标)
这里数组大小设为 n,定义三个指针:left,i,right
[ 0,left ] 为0,[ left+1,i-1 ]为1,[ i,right-1]为未扫描,[ right,n-1 ]为2
2.3 模拟实现
#include<vector>
class Solution {
public:
void sortColors(vector<int>& nums) {
//[0,left],要包含0,left初始化为-1
//[right,n-1],要包含下标n-1,right初始化为数组大小
int left = -1, i = 0, right = nums.size();
while (i < right)
{
//[0,left],[left+1,i-1],[i,right-1],[right,n-1]
//nums[i]和nums[left+1]交换,left++就可以将0放入[0,left]中
if (nums[i] == 0)
{
swap(nums[i], nums[left + 1]);
left++;
i++;
}
else if (nums[i] == 1)
{
i++;
}
//nums[i]和nums[right-1]交换,right--,将2放入[right,n-1]中
//注意:nums[right-1]还没有判断,交换后也没有判断,所以i不能++
else
{
swap(nums[i], nums[right - 1]);
right--;
}
}
}
};