#剑指offer45扑克牌顺子

扑克牌顺子

https://www.nowcoder.com/practice/762836f4d43d43ca9deb273b3de8e1f4?tpId=13&&tqId=11198&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking

剑指offer45扑克牌顺子

剑指offer45
图片说明
图片说明
图片说明
1、排序+遍历
满足以下2条规则即可:(1)判断是否有除0以外的重复 (2)最大最小之间相差是否大于4
无需计较0的数量,满足以上,少的0都会补上
因为排序原因,时间复杂度O(nlogn) 空间复杂度O(1)
个人代码

//只要保证11、范围长度在5个数以内,2、除0外不能重复,就可以保证连续,
//无论0几个缺啥补啥,只要没重复,就不可能不够补
//时间复杂度O(n+nlogn) 即O(nlogn)  空间复杂度O(1)
    bool IsContinuous( vector<int> numbers ) {
        sort(numbers.begin(),numbers.end()); //排序
        int max=numbers[4]; //最大值
        int index=0; //0数量
        while(numbers[index]==0)
        {
            ++index; 
        }
        int min=numbers[index]; //除0外最小值
        if((max-min)>4) return false; //最大最小之间顶多差4个数
        for(int i=index;i<4;i++) //除0外的数不能有重复
        {
            if(numbers[i]==numbers[i+1])
                return false;
        }
        return true;
    }

2、优化,萝卜插坑排序
上述时间复杂度高时因为排序原因,而我们实际想做的是计算最大最小值,以及判断是否除0以外的重复
观察发现,在知道大小之后,我们的数组类似于0-n-1分别不同的数字排序,萝卜插坑排序可以优化时间复杂度到O(n),对于坑被占的情况排序中止,直接返回不连续。
第一次遍历,0调整到最前面,顺便找min max 并初步判断
第二次,0之后的位置间插坑排序,判断是否有重复值
时间复杂度:O(n) 空间复杂度:O(1)
个人代码

  bool IsContinuous( vector<int> numbers ) {
        int index=0; //0的待入位置
        int min=-1;
        int max=-1;
        //第一次遍历,0移动到最前面,找出min max
        for(int i=0;i<numbers.size();i++)
        {
            if(numbers[i]==0) //发现0,0与非0数字交换位置,
            {
                int temp=numbers[index];
                numbers[index++]=numbers[i];
                numbers[i]=temp;
            }
            else //找0以外ia最大最小值
            {
                if(min==-1&&max==-1)  //min max初始化
                {
                    min=numbers[i];
                    max=numbers[i];
                }
                else
                {
                    if(numbers[i]<min)
                        min=numbers[i];
                    if(numbers[i]>max)
                        max=numbers[i];
                }
            }
        }
        if((max-min)>(numbers.size()-1)) //数字范围超了
            return false;
        //插坑排序,找重复值
        //第一次遍历后,index位置及以后都是非0数字,最小值min应放在0位置
        //任意数X应放在X-min位置,比如X=min+1,放在1位置
        for(int i=index;i<numbers.size();i++)
        {
            if(numbers[i]!=(i+min))
            {
                int pos=numbers[i]-min;//numbers[i]应该放入的位置
                if(numbers[pos]==numbers[i]) //若应该放入的位置已经有相同值,即也放正确的值,则重复
                    return false;
                //否则交换与numbers[i]交换
                if(numbers[pos]!=0)
                {
                    int temp=numbers[pos];
                    numbers[pos]=numbers[i];
                    numbers[i]=temp;
                    i--;//i位置显然需要重新判断
                }
                else //合适位置是0视作空,直接放入,原有位置视为空
                {
                    numbers[pos]=numbers[i];
                    numbers[i]=0; //
                }
            }
        }
        return true;
    }
全部评论

相关推荐

点赞 评论 收藏
分享
11-27 12:43
已编辑
门头沟学院 C++
点赞 评论 收藏
分享
评论
点赞
收藏
分享
牛客网
牛客企业服务