颜色分类Ⅱ

题目
在这里插入图片描述
方法一:分治法

算法思路:
每次选定一个中间的颜色,这个中间的颜色用给出的k来决定,将小于等于中间的颜色的就放到左边,大于中间颜色的就放到右边,然后分别再递归左右两半。
代码思路:
递归函数设置四个参数,序列需要处理区间的左右端点和处理的颜色区间
根据给定的颜色区间决定中间的颜色
将小于等于中间的颜色的就放到左边,大于中间颜色的就放到右边
递归左右两半,直到颜色区间长度等于1

class Solution {
public:
    //分治法
    void sortColors2(vector<int> &colors, int k) {
    //如果colors数组为空或者只有1个数
    //直接返回原数组
        if(colors.size()<2){
            return ;
        }
        mysort1(colors,0,colors.size()-1,1,k);
    }
    //start和end分别是排序范围的开始和结束,colorstart,colorend分别是需要排序颜色的大小
    void mysort1(vector<int>&colors,int start,int end,int colorstart,int colorend){
        int left=start,right=end;
        if(left>=right||colorstart==colorend){
            return ;
        }
        //把小于colorkey的放在左边,大于colorkey的放在右边
        int colorkey=(colorend-colorstart)/2+colorstart;
        while(left<=right){
        //在左边区间找到一个大于colorkey的数
            while(left<=right&&colors[left]<=colorkey){
                left++;
            }
        //在右边区间找到一个小于colorkey的数
            while(left<=right&&colors[right]>colorkey){
                right--;
            }
            if(left<=right){
                swap(colors[left],colors[right]);
            }
        }
        //对左区间和右区间分别进行递归
        mysort1(colors,start,right,colorstart,colorkey);
        mysort1(colors,left,end,colorkey+1,colorend);
    }
};

方法二:在原数组进行的计数排序

算法思路
我们用负数代表数字出现的次数,例如colors[i]=-cnt表示数字i出现了cnt次
代码思路
我们从左往右遍历colors数组

  • 若colors[i] > 0且colors[colors[i]] < 0,那么colors[colors[i]] -= 1
  • 若colors[i] > 0且colors[colors[i]] > 0,那么先用临时变量temp存下colors[i],将colors[colors[i]]赋值给colors[i],再将colors[temp] = -1
  • 若colors[i] < 0,跳过
    倒着输出每种颜色
    另外注意数组下标是从0开始,为了避免n==k导致数组越界的情况,colors[i]对应的计数位为colors[colors[i] - 1]
class Solution {
public:
    //基于原数组的计数排序法
    void sortColors2(vector<int> &colors, int k) {
        if(colors.size()<2){
            return ;
        }
        mysort2(colors,k);
    }
    void mysort2(vector<int>&colors,int k){
        int index=0;
        while(index<colors.size()){
            //如果index已经是计数位,就直接跳过
            if(colors[index]<=0){
                index++;
            }
            //如果index不是计数位
            else{
                //因为数组的下标是0开始的,所以映射需要减1
                //比如数值为1的个数存放在colors[0]的位置
                //数值为2的个数存放在colors[1]的位置
                int tmp=colors[index]-1;
                //如果colors[tmp]是计数位
                if(colors[tmp]<=0){
                    colors[tmp]--;
                    //因为colors[index]被计数了,所以index这个位置被置为0
                    colors[index]=0;
                    index++;
                }
                //如果两个都不是计数位
                //由于是对index进行计数,所以需要保存colors[tmp]的数值
                //然后把colors[index]位置作为是计数位
                else{
                    swap(colors[tmp],colors[index]);
                    colors[tmp]=-1;
                }
            }
        }
        //倒着打印数组
        int num=colors.size()-1;
        //值为k的个数存放在数组下标为k-1的位置
        while(k>0){
            for(int j=0;j>colors[k-1];j--){
                colors[num--]=k;
            }
            k--;
        }
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

影中人lx

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值