【每日易题】七夕限定——单身狗问题以及进阶问题位运算法的深入探讨

这篇具有很好参考价值的文章主要介绍了【每日易题】七夕限定——单身狗问题以及进阶问题位运算法的深入探讨。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

【每日易题】七夕限定——单身狗问题以及进阶问题位运算法的深入探讨,每日易题,算法,开发语言,c语言,c++

君兮_的个人主页

勤时当勉励 岁月不待人

C/C++ 游戏开发

Hello,米娜桑们,这里是君兮_,在写这篇博客的前一天是七夕,也是中国传统的“情人节”,不知道各位脱单了吗?碰巧最近刷题时遇到了经典的单身狗问题想带大家深入探讨一下,如果没脱单的话不如继续学习吧,记住,如果你喜欢的人不喜欢你,就变得足够优秀让她/他喜欢上你吧!!

一.什么是单身狗问题?

  • 单身狗往往是这样的,在别人都成双成对的时候,只有你一个人孤独寂寞冷(比如博主)。而单身狗问题往往是找出一系列数中落单的那个
  • 对于这种问题往往可以暴力求解,但这样显得不够“优雅”,毕竟我们是“单身贵族”嘛!所以我们这里就介绍一种时间复杂度和空间复杂度都比较低的方法——位运算法

找出一个单身狗

  • 先举出最简单的例子
  • 问题如下
//找出单身狗-版本1
//有一个数组只有一个数组出现一次,其余数字都是成对出现的
//请找出只出现一次的数字
//1 2 3 4 5 1 2 3 4
  • 5就是这里的单身狗`
  • 那我们怎样用位运算法求解呢?
  • 我们知道对于异或来说相同为0,相异为1
  • 而异或又有这样的特性
//a^a=0;
//a^0=a;
  • 同时,异或也满足交换律和结合律,我们就能写出以下代码
int find_single_dog1(int arr[], int sz)
{
	int i = 0;
	int ret = 0;
	for (i = 0; i < sz; i++)
	{
		ret ^= arr[i];
	}
	return ret;
}

int main()
{
	int arr[] = { 1,2,3,4,5,1,2,3,4 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	int dog = find_single_dog1(arr, sz);
	printf("%d\n", dog);

	return 0;
}
  • 什么意思呢?
  • 我们通过一个函数把所有的元素都给异或在一起,我们知道相同元素异或在一起为0,而一个元素异或0等于它本身,这样,就可以得到这个“单身狗”了。
    【每日易题】七夕限定——单身狗问题以及进阶问题位运算法的深入探讨,每日易题,算法,开发语言,c语言,c++

找两条单身狗

  • 从上面这题我们又可以深入一点,如果此时有两个人,但是他们是同性或者是异性但是不适合呢?也就是说有两条单身狗我们又该如何解决呢?
//找出单身狗版本2
//一个数组中只有两个数字是出现一次,其他所有数字都出现了两次。、
//编写一个函数找出这两个只出现一次的数字。
//例如:
//有数组的元素是:1,2,3,4,5,1,2,3,4,6
//只有5和6只出现1次,要找出5和6.
  • 此时的难点在于,我们也可以通过把所有的元素都异或起来的方法找到这两条单身狗异或的值,但是我们怎样通过他俩异或的值找到相应的两个元素呢?
  • 我们可以这样考虑,我们如果能把两条单身狗分到不同的组里,再找出每一个组中的单身狗不就和第一种情况一样了吗?
  • 此时我们分组的条件就应该是两者一定存在差异的地方,哪里能凸显两者的差异呢?
  • 先把代码放这,让大家自己想一下,下面会有详细的解释的
void find_single_dog2(int arr[], int sz, int* pd1, int* pd2)
{
	//1. 所有数字异或在一起
	int ret = 0;//5 ^ 6
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		ret ^= arr[i];
	}
	//2. 计算ret的第几位是1,从而找出不同进行分组
	int pos = 0;
	for (i = 0; i < 32; i++)
	{
		if (((ret >> i) & 1) == 1)
		{
			pos = i;
			break;
		}
	}
 	//分组
	//计算数组中元素的第pos为1的异或 
	for (i = 0; i < sz; i++)
	{
		if (((arr[i] >> pos) & 1) == 1)
		{
			*pd1 ^= arr[i];
		}
	}
	//计算数组中元素的第pos为0的异或
	*pd2 = ret ^ *pd1;
}

int main()
{
	int arr[] = { 1,2,3,4,5,1,2,3,4,6 };
	int dog1 = 0;
	int dog2 = 0;
	int sz = sizeof(arr) / sizeof(arr[0]);
	find_single_dog2(arr, sz, &dog1, &dog2);

	printf("%d %d", dog1, dog2);

	return 0;
}


  • 看懂了吗?我来解释一下
  • 我们这个ret是把所有数异或进来的,此时只剩下了两条单身狗异或的值,异或相异为1
    也就是说找到ret二进制位是1的位置是不是就找到两条单身狗的不同之处啦?接下来通过分组就可找出单身狗
  • 注意:相同的元素相应的二进制位一定相同,也就是非单身狗们一定会被分到同一组中,从而保证这组中异或后有且仅有一条单身狗。
  • 这里还有一个能偷懒的地方,我们知道了两条单身狗异或的值,又找出了一条单身狗,通过异或法是不是就能快速找出另一条单身狗了?
a^b^a=b

【每日易题】七夕限定——单身狗问题以及进阶问题位运算法的深入探讨,每日易题,算法,开发语言,c语言,c++


二.LeetCode单身狗进阶题

  • 题目的链接放在这里
    错误集合
    【每日易题】七夕限定——单身狗问题以及进阶问题位运算法的深入探讨,每日易题,算法,开发语言,c语言,c++
  • 说到底,这个题就是单身狗题目的变种,我们同样是通过异或先找出重复出现的值和丢失的值,然后再对它们进行分组,依次找出即可
int* findErrorNums(int* nums, int numsSize, int* returnSize){
   
    int ret=0;
    int*returnNums=(int*)malloc(sizeof(int)*2);
    *returnSize=2;
    int i=0;
    //通过把数组中元素和1到n中元素异或起来,找到多余元素以及缺少的元素 (找两条单身狗)
    for(i=0;i<numsSize;i++)
    {
        ret^=(i+1);
        ret^=nums[i];
    }
    int pos=0;
    i=0;
    
    //异或后不同位二进制为1,找1分组
    while(i<32)
    {
        if(((ret>>i)&1)==1)
        {
            pos=i;
            break;
        }
        i++;

    }
    //找出不同位后分组,只用找一个就行
    int nums1=0;
    int nums2=0;
    for(i=1;i<=numsSize;i++)
    {
        if(((i>>pos)&1)==1)
        {
            nums2^=i;
        }
    }
    for(i=0;i<numsSize;i++)
    {
        if(((nums[i]>>pos)&1)==1)
        {
            nums1^=nums[i];
            
        }
    }
        nums1^=nums2;//分组后的元素异或1-n找相同元素消掉
        //多的或者少的那个元素,不确定,我们需要判断一下
        int flag=0;//标记
        for(i=0;i<numsSize;i++)
        {
            if(nums[i]==nums1)
            {
                flag=1;
                returnNums[0]=nums1;
                break;
            }
        }
        if(flag==1)//数组中找到了这个元素,为重复元素,另一个为缺少元素
        returnNums[1]=ret^nums1;
        else
        {
            returnNums[1]=nums1;
            returnNums[0]=nums1^ret;

        }
        return returnNums;
    

}
  • 除了注释中提到的,我这里还想提两点需要注意的地方
  • 与找单身狗不同,这里我们没有成对的元素,因此我们在分组前后都通过异或1到n的数找相同元素从而消掉,剩下的就是我们的单身狗了(有些人可能不理解重复的元素咋消掉啊,重复的元素在ret里就因为相同而消掉了,因此照样能找到这条单身狗哦)
  • 与普通题不同的地方在于,我们这里找出两条单身狗后还有辨别一下哪个是重复元素,哪个是缺少元素,在区分时我们通过flag做了一个标记,flag的值被修改也就是数组存在这个数,说明它就是重复元素啦,另一个自然是缺少元素,反之未被修改就与这种情况相反。

总结

  • 今天的内容到这里就结束了,有关位运算的地方如果不太清楚最后自己画画逻辑图就能弄懂,而有关题目博主建议如果看懂了的话不妨自己动手试试哦!!

  • 好了,如果你有任何疑问欢迎在评论区或者私信我提出,大家下次再见啦!

新人博主创作不易,如果感觉文章内容对你有所帮助的话不妨三连一下这个新人博主再走呗。你们的支持就是我更新的动力!!!

**(可莉请求你们三连支持一下博主!!!点击下方评论点赞收藏帮帮可莉吧)**

【每日易题】七夕限定——单身狗问题以及进阶问题位运算法的深入探讨,每日易题,算法,开发语言,c语言,c++文章来源地址https://www.toymoban.com/news/detail-674410.html

到了这里,关于【每日易题】七夕限定——单身狗问题以及进阶问题位运算法的深入探讨的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【C刷题笔记】找单身狗问题

    目录 版本1:在数组内只有一个元素没有成对出现 版本2:在数组内有两个元素没有成对出现 第一步:异或所有元素,异或就是相同为0,相异为1 第二步:计算ret的二进制中哪一位元素是1 第三步:开始分组异或 1.分组: 2.异或 单身狗 只有一个数字出现一次,其他数数字都是成对出现的

    2024年02月07日
    浏览(30)
  • php限定能执行的php目录以及路径

    server {     listen 80;     server_name www.sdph.org.cn sdph.org.cn;     index index.php index.html index.htm default.php default.htm default.html;     root /www/wwwroot/yixuehui1/public;     location ~* ^/(static|uploads|upload|images|cache|tmp|css|js)/.*.(php|php5)$ {         deny all;      }          location = /index.php {        

    2024年02月06日
    浏览(32)
  • (MACOS限定!)关于npm install 报错问题的解决

    很多使用MacOS的朋友在设置npm install会遇到报错的情况,如图:  接下来就让我们一起解决下这个问题吧! 输入代码: 然后输入密码,如图: 此时尝试输入 npm install iquery,结果 报错,进行步骤二,如图: 图片中也显示了要输入: 根据步骤一图,输入代码: 输入密码,如图

    2024年02月14日
    浏览(50)
  • ( 位运算 ) 338. 比特位计数 ——【Leetcode每日一题】

    难度:简单 给你一个整数 n ,对于 0 = i = n 中的每个 i ,计算其二进制表示中 1 的个数 ,返回一个长度为 n + 1 的数组 ans 作为答案。 示例 1: 输入:n = 2 输出:[0,1,1] 解释: 0 -- 0 1 -- 1 2 -- 10 示例 2: 输入:n = 5 输出:[0,1,1,2,1,2] 解释: 0 -- 0 1 -- 1 2 -- 10 3 -- 11 4 -- 100 5 -- 101 提

    2024年02月05日
    浏览(27)
  • C语言每日一练 —— 第20天:位运算

      今天主要内容是聊一聊二进制和位运算。   对应视频教程如下:位运算视频教程。   我们在学习 光天化日学C语言(06)- 进制转换入门 的时候,曾经提到过二进制。   二进制就是逢二进一,计算机中的存储采用的就是二进制。在计算机中,非零即一。   例如

    2024年02月07日
    浏览(38)
  • ( 位运算 ) 190. 颠倒二进制位 ——【Leetcode每日一题】

    难度:简单 颠倒给定的 32 位无符号整数的二进制位。 提示: 请注意,在某些语言(如 Java )中,没有无符号整数类型。在这种情况下,输入和输出都将被指定为有符号整数类型,并且不应影响您的实现,因为无论整数是有符号的还是无符号的,其内部的二进制表示形式都是

    2024年02月03日
    浏览(49)
  • 深度学习进阶篇[9]:对抗生成网络GANs综述、代表变体模型、训练策略、GAN在计算机视觉应用和常见数据集介绍,以及前沿问题解决

    【深度学习入门到进阶】必看系列,含激活函数、优化策略、损失函数、模型调优、归一化算法、卷积模型、序列模型、预训练模型、对抗神经网络等 专栏详细介绍:【深度学习入门到进阶】必看系列,含激活函数、优化策略、损失函数、模型调优、归一化算法、卷积模型、

    2024年02月08日
    浏览(102)
  • 武忠祥老师每日一题|109题有理函数积分|反常积分的运算(一)

    ∫ 5 + ∞ d x x 2 − 4 x + 3 int_{5}^{+infty}frac{dx}{x^2-4x+3} ∫ 5 + ∞ ​ x 2 − 4 x + 3 d x ​ 无论是不定积分、定积分、反常积分,分母为二次时,如果可以在实数范围内可以分解,就把分母拆项做。如果不能分解,就用配方法做。 对于这个题目,分母是可以拆成(x-1)(x-3)的。 然后根

    2024年02月05日
    浏览(36)
  • (位运算) 1356. 根据数字二进制下 1 的数目排序 ——【Leetcode每日一题】

    难度:简单 给你一个整数数组 arr 。请你将数组中的元素按照其二进制表示中数字 1 的数目升序排序。 如果存在多个数字二进制中 1 的数目相同,则必须将它们按照数值大小升序排列。 请你返回排序后的数组。 示例 1: 输入 :arr = [0,1,2,3,4,5,6,7,8] 输出 :[0,1,2,4,8,3,5,6,7] 解释

    2024年02月12日
    浏览(54)
  • Cadence+硬件每日学习十个知识点(46)23.8.26 (运算放大器)

    答:Vin在放大器的负端输入,所以这个是反相比较器,当输入0的时候,输出1。 这里在放大器的正端输入电压5V,用两个100K的电阻分压,当没有加Rh电阻时,放大器没有迟滞,当Vin为2.5V以下时,输出5V,当Vin为2.5V以上时,输出0V,但是因为存在噪声,所以如下图的左方所示,

    2024年02月10日
    浏览(55)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包