🤗C++菜鸡刷leetcode之每日两道题🤗
不甘心算法菜成这个样子,从0开始写题,理论[算法第4版]+实践[leetcode]再扑棱扑棱尝试一下。
题目1:75. 颜色分类
75. 颜色分类
题目要求在不使用库内置的 sort 函数 并且 原地 解决这个问题。可以自己写原地排序算法函数解决,比如冒泡排序 快排等。除了使用排序方法,首先想到的就是利用单指针或者双指针,通过swap把0元素都交换至数组的前面,把2都交换至数组末尾。
方法1:单指针 ptr
。 第一个循环遍历数组,从第0个元素开始。当遇到元素为 0 时,将该元素与指针 ptr
指向元素交换并更新ptr
。确保所有的0元素在数组前部分。第二个循环从指针 ptr
开始继续遍历数组。当遇到元素为 1 时,同样将该元素与指针 ptr
指向的元素交换,并更新ptr
。确保所有的 1 都被交换到数组的中间位置。该方法时间复杂度O(n)
,空间复杂度O(1)
。代码如下:
class Solution {
public:
void sortColors(vector<int>& nums) {
int ptr = 0;
for (int i = 0; i < nums.size(); i++) {
if (nums[i] == 0) swap(nums[i], nums[ptr]), ptr++;
}
for (int i = ptr; i < nums.size(); i++) {
if (nums[i] == 1) swap(nums[i], nums[ptr]), ptr++;
}
}
};
方法2:双指针l
和r
。一个指针指向0部分的最右侧 l
指针,一个指针指向2部分的最左侧 r
指针。for循环遍历整个数组元素,若当前元素是0,则交换至l处,并更新 l
指针 与 i
。若当前元素是2,则交换至r
指针处, 并更新r
指针。若当前元素不是0也不是2,则忽略并让i
继续向前。该方法时间复杂度O(n)
,空间复杂度O(1)
。代码如下:
class Solution {
public:
void sortColors(vector<int>& nums) {
int l = 0, r = nums.size() - 1;
for(int i = 0; i <= r;){
if(nums[i] == 0){
swap(nums[i], nums[l]);
l++,i++;
}else if(nums[i] == 2){
swap(nums[i], nums[r]);
r--;
}else{
i++;
}
}
}
};
题目2:31. 下一个排列
31. 下一个排列
题目要求必须 原地 修改,只允许使用额外常数空间。
字典序排列的下一个顺序
比如数组[1, 2, 3] 的所有字典序排列是:[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]
方法1:使用C++的内置函数 next_permutation
,时间复杂度O(n)
,空间复杂度O(1)
。代码如下:
class Solution {
public:
void nextPermutation(vector<int>& nums) {
next_permutation(nums.begin(), nums.end());
}
};
方法2:
若把数组的每一次排列看成一整个数字:
需求:且希望下一个数字比当前的数字大,下一个数增加的幅度尽可能的小。因此选择尽可能从 右边 开始找大数,把右边的尽可能小的大数与前面的小数进行交换。把大数换到前面后,需要将大数后面的数字重置为升序,升序排列就是最小的排列。因此设计算法为:
① 先从右边开始找到第一个a[k] < a[k+1]
的升序数组,a[k+1]
到 a[n-1]
一定是降序
② 在a[k+1]到a[n-1]
之间,从右向左,查找第一个元素a[k] < a[t]
,a[k]
是小数,a[t]
是大数
③ 交换a[k]
与 a[t]
,并让a[k+1]
到a[n-1]
之间逆置,让降序变成升序,保持大数在前面后的最小数字排列
时间复杂度O(n)
,空间复杂度O(1)
。代码如下:
class Solution {
public:
void nextPermutation(vector<int>& nums) {
if(nums.size() <= 1) return;
int n = nums.size();
int k = n - 2;
// 先从右向左 找到a[k] < a[k+1]的数对儿,此时a[k+1]~a[n-1]是降序
while(k >= 0 && nums[k] >= nums[k+1]) k--;
// 再从又向左找到比a[k]大的最小数
if(k >= 0){
int t = n - 1;
while(nums[t] <= nums[k]) t--;
// 交换大数和小数
swap(nums[t], nums[k]);
}
// 交换后保持大数后面是最小的排序即全部升序
reverse(nums.begin() + k + 1, nums.end());
}
};