C++菜鸡刷leetcode之每日两道题

🤗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:双指针lr。一个指针指向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());
    }
};

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值