只出现一次的数(LeetCode题解C++)

只出现一次的数(三种类型题)

1. 给一个非空数组,其中只有一个元素出现一次,其余元素出现两次,找出那个出现一次的数:

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

1.1 思路

要判断这个只出现一次的数和出现两次的数,我们可以用按位异或来解决,首先复习一下这个运算符:
在C++中,按位异或运算符用于对两个操作数的每个对应位进行按位异或运算。在C++中,按位异或运算符表示为^

具体规则如下:

  • 0 ^ 0 = 0
  • 0 ^ 1 = 1
  • 1 ^ 0 = 1
  • 1 ^ 1 = 0

例如,考虑两个二进制数a = 1010b = 1100,进行按位异或运算时,对应位上的操作如下:

a = 1 0 1 0
b = 1 1 0 0
---------
    0 1 1 0

所以,a ^ b的结果为0110,即十进制数6。

此外,按位异或运算还有一些特性,例如对两个相同的值进行按位异或操作结果为0,对任何值与0进行按位异或操作结果不变等。

就比如;
5^5=0
0^3=3
看到这里我们发现只要让给的那组数按位与一遍,最终的结果就是只出现一次的数

1.2 程序代码

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

    }
};

2. 一次变形题

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

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

2.1 解题思路

这个问题我们仍然用运算符解决,我们发现第一题的思路在这里行不通,因为三次异或不能消除元素,那我们怎么解决呢,3和1总是有差别的,我们还是把数变为二进制来考虑,标准的C++中,一个整数类型通常占据特定的位数。其中,int类型通常是一个32位的整数类型。
我们先来考虑两个数 2和3
2:0000 0000 0000 0000 0000 0000 0000 0010
3:0000 0000 0000 0000 0000 0000 0000 0101
我们就不如把数组中每个位数上的1统计一下,假如数组里都是出现3次,那是不是我们记录的1的个数肯定是3的倍数,相反如果不是3的倍数,那就是我们要找的目标了。
首先我们要记录,得有一个记录的工具吧,我们定义一个含有32个元素的数组,把对应位置1的个数记录一下,然后那些不是3的倍数的位,就是要找的目标了。
怎么记录呢,我们这样:

   for(auto e:nums)
         {
            for(size_t i=0;i<32;++i)
            {
             if(e & (1<<i))
               {
                 bitArray[i]++;
               }
            }
         }

看代码。我们遍历第一个数的时候,还得遍历他32位上的1吧 ,对应代码:for(size_t i=0;i<32;++i),然后看怎么找1,就用到按位与& 了,这个运算符是:两个都为1则为1,否则为0,所以我们用1给他按位与(1<<i 表示左移i位),当我们检查第i位上是否为1是,就把1左移i位与之相对应,这样就行了。如果e & (1<<i)为1了,我们就是数组里的第i个元素加上1。

好,现在我们已经得到1个数的数组了,现在我们要把里面不为3的倍数的位挑出来。 if(bitArray[i]%3==1)或者 if(bitArray[i]%3!=0),可是我们还要记录他所在的位数,比如负责记录的数组:
0000 0000 0000 0000 0000 0000 0000 7667
这个说明我们要找的数是:
0000 0000 0000 0000 0000 0000 0000 1001
怎么实现这个过程呢,我们这样:

  if(bitArray[i]%3==1)
             val |=(1<<i);

这里面 I 是或运算符(有1则为1),val为0,比如我们看到第0位为7符合条件可以运行吧,val32个位上都为0,1左移0位,说明第0位上是0,两相或运算,则val第0位为1吧。好,第二次循环,第1位是6,不符合条件吧,也就没法去和1 或 了,就是0,以此类推。

2.2 程序代码

class Solution {
public:
    int singleNumber(vector<int>& nums)
     {
         int bitArray[32]={0};
         //统计出了32个位合计1的个数
         for(auto e:nums)
         {
            for(size_t i=0;i<32;++i)
            {
             if(e & (1<<i))
               {
                 bitArray[i]++;
               }
            }
         }
         int val=0;
         //找出3n+1的位,这些位就是只出现一次的数为1的位
         for(size_t i=0;i<32;++i)
         {
            if(bitArray[i]%3==1)
             val|=(1<<i);
         }
         return val;
    }

};

2. 第二次变形题

给你一个整数数组 nums,其中恰好有两个元素只出现一次,其余所有元素均出现两次。 找出只出现一次的那两个元素。你可以按 任意顺序 返回答案。
输入:nums = [1,2,1,3,2,5]
输出:[3,5]
解释:[5, 3] 也是有效的答案。

2.1 解题思路

这个题里有两个一次出现的数,其余出现两次,按照前面的方法,我们很容易把出现两次的数排除,可结果却是两个出现一次的数异或。以上面的案例说:
出现一次的数是3和5,两个异或一下:
3:0000 0000 0000 0000 0000 0000 0000 0011
5:0000 0000 0000 0000 0000 0000 0000 0101
…^ 0000 0000 0000 0000 0000 0000 0000 0110
异或是相同为0不同为1,这我们得到的结果可以看出这两个数在哪个位上是不同的,而这正是他们之间的茶差别。3和5在第1位和第2位上不同(第0位相同),我们就在这第1位上做文章(第2位也可以)。
首先我们把整个数组的里数,分成两组。怎么分呢,就是把第1位是1的分到第一组,为0的分到第二组。这样是不是就把3和5分到不同的组了,其他的数也按照这个方法,
结果就是这样了:
第一组:2 2 3
第二组:1 1 5

这不就回到第一个问题了嘛,直接异或,就妥了。

2.2 程序代码

class Solution {
public:
    vector<int> singleNumber(vector<int>& nums)
     {
         //异或完成之后,val就是那两个数据异或的结果
        int val = 0;
        for(auto e : nums)
        {
            val^=e;
        }
        size_t i=0;
       // 转化成问题1
        for(i=0;i<32;++i)
        {
            if(val & (1<<i))
            break;
        }
        int num1=0,num2=0;
        for(auto e:nums)
        {
            if(e & (1<<i))
            num1^=e;
            else
            num2^=e;
        }
        vector<int> v;
        v.push_back(num1);
        v.push_back(num2);

        return v;
    }
};
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
引用\[1\]:这段代码是一个解决LeetCode上某个题目的C++实现,具体是一个双指针的解法。该题目是计算一个组中的积水量。代码中使用了两个指针分别指向组的左右边界,然后通过比较左右指针所指向的元素的大小,来确定当前位置的积水量。具体的计算方法是,如果左指针所指向的元素小于右指针所指向的元素,则对左指针的左边进行操作,如果左指针所指向的元素大于等于右指针所指向的元素,则对右指针的右边进行操作。在每一次操作中,都会更新左边的最大值和右边的最大值,并计算当前位置的积水量。最后返回总的积水量。\[1\] 引用\[2\]:这段代码是另一个解决LeetCode上某个题目的C++实现,具体是一个深度优先搜索的解法。该题目是计算一个二维网格中从起点到终点的可行路径量。代码中使用了递归的方式进行深度优先搜索,从起点开始,每次向下或向右移动一步,直到到达终点。在每一步移动中,会判断当前位置是否有障碍物,如果有障碍物则返回0,如果到达终点则返回1,否则继续递归搜索下一步的位置。最后返回总的可行路径量。\[2\] 引用\[3\]:这段代码是另一个解决LeetCode上某个题目的C++实现,具体是一个动态规划的解法。该题目是计算一个组中的积水量。代码中使用了动态规划的思想,通过遍历组中的每个元素,分别计算该元素左边和右边的最大值,并计算当前位置的积水量。最后返回总的积水量。\[3\] 综上所述,这三段代码分别是解决LeetCode上不同题目的C++实现,分别使用了双指针、深度优先搜索和动态规划的方法来解决问题。 #### 引用[.reference_title] - *1* *3* [Leetcode 热题100 42.接雨水(C++ 多种解法,错过可惜)](https://blog.csdn.net/qq_51933234/article/details/124637883)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down28v1,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [[C++]Leetcode 不同路径 || 解题思路及详解](https://blog.csdn.net/weixin_62712365/article/details/123951736)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down28v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值