Leetcode--只出现一次的数字(三道题目)

文章介绍了如何利用异或运算和位操作解决一系列问题,找出整数数组中只出现一次的元素,要求线性时间复杂度和常量额外空间。方法包括对数组进行异或操作,然后通过位运算定位只出现一次的数字。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

136.只出现一次的数字(简单)

题目

给你一个 非空 整数数组 nums ,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。

你必须设计并实现线性时间复杂度的算法来解决此问题,且该算法只使用常量额外空间。

示例 1 :

输入:nums = [2,2,1]
输出:1

示例 2 :

输入:nums = [4,1,2,1,2]
输出:4

示例 3 :

输入:nums = [1]
输出:1

提示:

  • 1 <= nums.length <= 3 * 104
  • -3 * 104 <= nums[i] <= 3 * 104
  • 除了某个元素只出现一次以外,其余每个元素均出现两次。

分析

        由于题目中明确表明,除了一个数字只出现了一次之外,其他数字都出现了两次,可以使用异或运算,每两个相同的数字异或后都变为零,只剩最后只出现一次的数字,与0异或后仍然为自己。

源代码

class Solution {
public:
    int singleNumber(vector<int>& nums) {
        int val=0;
        for(auto e:nums)
        {
            val ^=e;
        }
        return val;

    }
};

 137.只出现一次的数字II(中等)

题目

给你一个整数数组 nums ,除某个元素仅出现 一次 外,其余每个元素都恰出现 三次 。请你找出并返回那个只出现了一次的元素。

你必须设计并实现线性时间复杂度的算法且使用常数级空间来解决此问题。

示例 1:

输入:nums = [2,2,3,2]
输出:3

示例 2:

输入:nums = [0,1,0,1,0,1,99]
输出:99

提示:

  • 1 <= nums.length <= 3 * 104
  • -231 <= nums[i] <= 231 - 1
  • nums 中,除某个元素仅出现 一次 外,其余每个元素都恰出现 三次

分析

以第一组为例:nums = [2,2,3,2],首先判断每一位是0还是1,采取与移位1进行与运算,将每一个数字的每一位出现了多少个1,加在一次,这时可能出现两种情况

只有三个相同的数字出现该位,则该位和为3N,该位也出现了那个特别的数字,则该位和为3N+1

0010

0010

0011

0010

---------------------

0041

然后对每一位进行余三操作,如果余数为1,则单独一个的数该位为1,否则该为为0,这个地方困扰我的问题是如何将这些余数变为一个数字,即如何在对应位置1,采取与1进行移位或运算

源代码

class Solution {
public:
    int singleNumber(vector<int>& nums) {
        int BitsArray[32]={0};
        for(auto e:nums)
        {
            for(size_t i=0;i<32;i++)
            {
                if(e&(1<<i))
                {
                    BitsArray[i]++;
                }

            }

        }
        int val=0;
        for(size_t j=0;j<32;j++)
        {
            if(BitsArray[j]%3==1)
            {
                val|=(1<<j);
            }
           
        }
        return val;

    }
};

260.只出现一次的数字III(中等)

题目

给你一个整数数组 nums,其中恰好有两个元素只出现一次,其余所有元素均出现两次。 找出只出现一次的那两个元素。你可以按 任意顺序 返回答案。

你必须设计并实现线性时间复杂度的算法且仅使用常量额外空间来解决此问题。

示例 1:

输入:nums = [1,2,1,3,2,5]
输出:[3,5]
解释:[5, 3] 也是有效的答案。

示例 2:

输入:nums = [-1,0]
输出:[-1,0]

示例 3:

输入:nums = [0,1]
输出:[1,0]

提示:

  • 2 <= nums.length <= 3 * 104
  • -231 <= nums[i] <= 231 - 1
  • 除两个只出现一次的整数外,nums 中的其他数字都出现两次

分析

        可以先将他们全部异或,那么结果就是只出现一次的那两个数字的异或的结果,然后想办法将它们分开。

        以这个举例:nums = [1,2,1,3,2,5],那么结果应该是3和5的异或

0011

0101

-------------

0110

        由结果可知,哪一位为1,则说明该为这两个数字不一样,可用这个来区分它们,将这些数分为两组,例如,红色这位为1,则该位两个数字一个为1,一个为0,分为两组之后,就成了136的问题了,除了该数其他数都出现两次

例如该位为1的有:2 3 2

       该位为0的有:1 5 1

源代码 

class Solution {
public:
    vector<int> singleNumber(vector<int>& nums) {
        int val=0,j=0;
        for(auto e:nums)
        {
            val^=e;
        }
        for(auto e:nums)
        {
            for(j=0;j<32;j++)
            {
                if(val&(1<<j))
                {
                    break;
                }
            }
        }
        int num1=0,num2=0;
        for(auto e:nums)
        {
            if(e&(1<<j))
            {
                 num1^=e;
            }
            else
            {
                num2^=e;
            }
           
        }
        vector<int> v;
        v.push_back(num1);
        v.push_back(num2);
        return v;

    }
};

小结

这次练习加深了我对位运算符的认识,当要从两两相同的数中找不同的那个可以用异或运算,如何定位某一位是0还是1也可以采用与1移位与的运算,将某一位置1或0可以采用与1移位或的运算。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值