【位运算问题】Leetcode 136、137、260问题详解及代码实现

简介: 此外,任意一个数异或0都为他本身 (这从二进制编码来理解也很好理解,0的二进制编码全为0,任意一个数与其异或不同的就是若干位的1)

Halo,这里是Ppeua。平时主要更新C语言,C++,数据结构算法......感兴趣就关注我吧!你定不会失望。


🌈个人主页:主页链接


🌈算法专栏:专栏链接


    我会一直往里填充内容哒!


🌈LeetCode专栏:专栏链接


目前在刷初级算法的LeetBook 。若每日一题当中有力所能及的题目,也会当天做完发出


🌈代码仓库:Gitee链接


🌈点击关注=收获更多优质内容🌈



这三个问题都为位运算中异或^的特性,所以放在一起. 可以看看之前的这篇文章有对接下俩涉及的概念lowbitx的具体讲解:位运算专题


先来了解一下异或^:


相同为0,不同则为1,这是在二进制编码中


101111^10111=00000
1010^0101=1111


放到一个整形数据来看,相同的数字就被消去了


此外,任意一个数异或0都为他本身 (这从二进制编码来理解也很好理解,0的二进制编码全为0,任意一个数与其异或不同的就是若干位的1)


x^x=0
x^0=x


此外 ,异或满足结合律与交换律


a ^ b = c  => a ^ c = b  => b ^ c = a (交换律)
a ^ b ^ c = a ^ (b ^ c) = (a ^ b)^ c (结合律)


异或的特性就这么多,现在开始解题吧.


136. 只出现一次的数字


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


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


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


这题很简单,利用异或里同项相消,异项保留的特点,直接遍历^每一个数字返回遍历后的结果就可以了


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


137. 只出现一次的数字 II


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


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


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


数组中有且仅有1个数字出现1次 其余均出现了3次。


在32位环境下一个数的二进制位由32个0/1构成。取数组中的每一个数的某一二进制位相加,得到的一定是三的倍数,或者三的倍数加一(当那唯一出现一次的数该二进制位也是1的时候)。

知道这个规律后,我们定义一个初始循环表示ans的第i位数。之后内嵌一个循环遍历数组中的每一个数。


若总数不为3的倍数,则说明该位上有唯一出现一次的数的1,将其拼到ans上。


878194caf4f14450921fc1a8a3882b71.jpg


class Solution {
public:
    int singleNumber(vector<int>& nums) {
        int ans=0;
        for(int i=0;i<32;i++)
        {
            int total=0;
            for(auto num:nums)
            {
                total+=(num>>i)&1;
            }
            if(total%3)
            {
                ans|=1<<i;
            }
        }
        return ans;
    }
};


260. 只出现一次的数字 III


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


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


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


这题是第一题的升级版,有两个元素恰好出现一次,参照第一题的做法,若将这一个数组分为两个组,将这唯一出现的两个元素分别放入这两个组中,执行第一题的异或操作,最后剩下来的就是唯一出现的数字.


那么如何将两个数字分开放呢?


观察二进制位出现的规律,一个位就两种可能,要么是1,要么是0,所以我们只要找到这两个数不相同的那一个位,以此来区分就可


0e3662140c1249b3bb9ce481ded3978b.jpg


先将所有数据^,因为除这两个数字外,其余都是两两出现,^后的结果为这两个数字的结果.


再用lowbit思想 返回其第一个出现1的数字(异或完lowbit返回的是这两个数字第一个不相同的位)


在进行一个循环将每一个数与这个数,无非就两种结果,将这两种结果分组,即可


#include<iostream>
#include<vector>
using namespace std;
class Solution {
public:
    vector<int> singleNumber(vector<int>& nums) {
        vector<int>ans1;
        vector<int>ans2;
        vector<int>ans3(2);
        long tag=0;
        for(auto n:nums)tag^=n;
        long ans=0;
        ans=tag&(-tag);//lowbit
        for(auto n:nums)
        {
            if(n&ans)
            {
                ans3[0]^=n;
            }
            else ans3[1]^=n;
        }
        return ans3;
    }
};


完结撒花:


🌈本篇博客的内容【Leetcode 136、137、260问题详解及代码实现】已经结束。

🌈若对你有些许帮助,可以点赞、关注、评论支持下博主,你的支持将是我前进路上最大的动力。


🌈若以上内容有任何问题,欢迎在评论区指出。若对以上内容有任何不解,都可私信评论询问。


🌈诸君,山顶见!

目录
相关文章
|
5月前
力扣-2029-石子游戏-‘屎山’代码
力扣-2029-石子游戏-‘屎山’代码
40 3
|
5月前
|
算法 索引
力扣随机一题 位运算/滑动窗口/数组
力扣随机一题 位运算/滑动窗口/数组
42 0
|
6月前
|
算法
leetcode代码记录(全排列 II
leetcode代码记录(全排列 II
47 4
|
6月前
leetcode代码记录(最长回文子串
leetcode代码记录(最长回文子串
46 2
|
6月前
|
算法
leetcode代码记录(寻找两个正序数组的中位数
leetcode代码记录(寻找两个正序数组的中位数
44 2
|
6月前
leetcode代码记录(最长连续递增序列
leetcode代码记录(最长连续递增序列
38 2
|
6月前
leetcode代码记录(第一个出现两次的字母
leetcode代码记录(第一个出现两次的字母
34 2
|
6月前
|
算法
leetcode代码记录(全排列
leetcode代码记录(全排列
49 1
|
6月前
|
索引
leetcode代码记录(Z 字形变换
leetcode代码记录(Z 字形变换
44 1
|
6月前
leetcode代码记录(回文数
leetcode代码记录(回文数
40 1