复习算法 寻找数组中重复元素这种类型题目(原地标记法)

如果题目已知的arr[i]的取值范围没有要求

题目:只出现一次的数字链接
ti
思路:
x^0=x
x^x=0

代码:

class Solution {
public:
    int singleNumber(vector<int>& nums) 
    {
        int ret=0;
        for(int value:nums)
        {
            ret=ret^value;
        }

        return ret;

    }
};

如果题目已知的arr[i]的取值范围有取值范围,并且明显有数组中数字与下标有一一对应的性质

题目:剑指 Offer 03. 数组中重复的数字链接
在这里插入图片描述
思路:
很明显, nums.size()=n 并且里面的每个数字在 0~n-1 之间,将每个没有归位的元素归位,如果发现待归位元素的待交换的位置是存的相同的值,也就是重复了

if(nums[i]==nums[nums[i]])
{
    return nums[i];
}

每次将元素归位,时间复杂度是o(n) (for中虽有while循环,但是代码运行时,while并不是每次都执行,最多执行的总次数是o(n).)
代码:

class Solution {
public:
    int findRepeatNumber(vector<int>& nums) 
    {
        //这题并没有要求求出所有重复的数字

        for(int i=0;i<nums.size();i++)
        {
            while(nums[i]!=i)
            {
              
                if(nums[i]==nums[nums[i]])
                {
                    return nums[i];
                }
                swap(nums[i],nums[nums[i]]);
            }

            
            cout<<"i="<<i<<endl;

        }

        return 0;
    }
};

题目:442. 数组中重复的数据链接
在这里插入图片描述

思路:
这题和上一题基本一样,这题将所有的重复元素算出,
需要注意的是,由于需要求出所有重复的元素,并且重复的元素只能加入一次,
因此我们需要

 if (nums[i]==-1) break;

 if(nums[i]==nums[nums[i]-1]) 
   {
       ret_v.push_back(nums[i]);
       nums[i]=-1;
       break;
   }

下面我们来分析下面代码的时间复杂度
将元素归位时间复杂度是o(n)(for中虽有while循环,但是代码运行时,while并不是每次都执行,最多执行的总次数是o(n).)
题目中说不需要额外空间,也就是o(1)空间,但是返回值又是vector 并且在代码中我们会发现申请了空间,题目的意思其实是 我们申请的空间只能用来存结果,这样就算做没有使用额外的空间

代码:

class Solution 
{
    //首先我们需要知道  1 ≤ a[i] ≤ n   就一直在暗示我们 元素和下标一一对应的关系,因此。我们需要将元素放在正确的位置上面就可以了
public:
    vector<int> findDuplicates(vector<int>& nums) 
    {
        vector<int> ret_v;
        for(int i=0;i<nums.size();i++)
        {
            
            
            while((nums[i]-1)!=i)//这种题对应的的标记一定不能弄混
            {
                if (nums[i]==-1) break;

                if(nums[i]==nums[nums[i]-1]) 
                {
                    
                    //cout<<"nums[i]="<<nums[i]<<endl;
                    ret_v.push_back(nums[i]);

                    nums[i]=-1;
                    break;

                }else
                {
                    swap(nums[i],nums[nums[i]-1]);
                }
            }
           
           
        }

        return ret_v;
    }
};

题目:448. 找到所有数组中消失的数字链接
在这里插入图片描述

思路:
这题就是将上一题变了一点,将元素归位后将 然后将numbers进行遍历,元素值是-1(代表重复,或者没有这个位置本该对应的元素)的index+1 存入vector 中。

代码:

class Solution {
public:
    vector<int> findDisappearedNumbers(vector<int>& nums) 
    {
         vector<int> ret_v;
        for(int i=0;i<nums.size();i++)
        {
            
            
            while((nums[i]-1)!=i)//这种题对应的的标记一定不能弄混
            {
                if (nums[i]==-1) break;

                if(nums[i]==nums[nums[i]-1]) 
                {
                    

                    nums[i]=-1;
                    break;

                }else
                {
                    swap(nums[i],nums[nums[i]-1]);
                }
            }
           
           
        }
        for(int i=0;i<nums.size();i++)
        {
            if(nums[i]==-1) ret_v.push_back(i+1);
        }
        return ret_v;

    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值