【C进阶】找单身狗

news2024/9/27 12:13:38

⭐博客主页:️CS semi主页
⭐欢迎关注:点赞收藏+留言
⭐系列专栏:C语言进阶
⭐代码仓库:C Advanced
家人们更新不易,你们的点赞和关注对我而言十分重要,友友们麻烦多多点赞+关注,你们的支持是我创作最大的动力,欢迎友友们私信提问,家人们不要忘记点赞收藏+关注哦!!!

找单身狗

  • 前言
  • 一、题目描述
  • 一、先排序再找单身狗再排序
    • (一)解题思路
    • (二)解题代码
    • (三)出现的问题
  • 二、异或法(仅针对一个单身狗)
    • (一)解题思路
    • (二)解题代码
    • (三)出现的问题
  • 三、分组法(针对两个单身狗)
    • (一)解题思路
    • (二)解题代码
    • (三)展望
  • 总结


前言

找单身狗这个标题看起来那么地无厘头,可是当大家知道了本题的题目会感觉到原来这是真的单身狗呀!!这么多个数字就这一个数字是单着的,其他数字都是成双成对的,那肯定想法是很多的,我们直接往下看吧!!!


一、题目描述

寻找一组数组中只出现过一次的数,分为两种情况:
情况一、仅仅有一个单独出现的数,如下所示:
在这里插入图片描述
情况二、有两个单独出现的数,如下所示:
在这里插入图片描述

一、先排序再找单身狗再排序

(一)解题思路

是不是很拗口,但是,思路是很简单的,这种寻找方式是能找到多个单身狗,单身狗很多也没关系,我们利用排序的方法,先将这些杂乱的数进行排个序,相同的数肯定是紧紧挨着的,而且本题目是成双成对出现的,仅仅有单身狗,所以不存在有三个同样的数的可能,所以我们可以简单的想象成两个一样的数拉着手坐在一张椅子上,只有落单的那个数单独坐一个椅子,而我们不看双个人只看单个人就是需要跳过两个人,也就是一张板凳即可,这样就有思路了,我们就可以继续往下写代码了。

(二)解题代码

#include<stdio.h>
void bubble_sort(int* arr, int sz) {
	int i = 0;
	for (i = 0; i < sz - 1; i++) {
		int j = 0;
		for (j = 0; j < sz - 1 - i; j++) {
			if (*(arr + j) < *(arr + j + 1)) {
				int temp = *(arr + j);
				*(arr + j) = *(arr + j + 1);
				*(arr + j + 1) = temp;
			}
		}
	}

}
int main() {
	int arr[] = { 1,1,2,2,3,3,4 };
	int pos = 0;
	int sz = sizeof(arr) / sizeof(arr[0]);//算个数
	int arr2[10] = { 0 };//重新封装一个函数用来存放单的值
	bubble_sort(arr, sz);
	int i = 0;
	int j = 0;//arr2数组的计数器
	for (i = 0; i < sz;) {
		if (arr[i] == arr[i + 1]) {//前后两个是一样的就往后跳两个
			i = i + 2;
		}
		else {//前后两个不一样就存放并往后跳一个位置
			arr2[j] = arr[i];
			pos++;
			i++;
			j++;//计数器往后一位
		}
	}
	for (i = 0; i < pos; i++) {//打印
		printf("%d ", arr2[i]);
	}
	return 0;
}

(三)出现的问题

看似我们这个代码很完美了,思路很好,但是也是存在一定的问题的,第一个大问题就是这个代码的时空复杂度都会很高,因为这个代码是先遍历一次整个数组进行排序,再是遍历一次已经排好的数组进行找单身狗,这个数组需要遍历两次,是很麻烦的,万一有个1000个数的数组这么一遍历实在是太慢了;当然,第二个很大的问题是当我们找的那个单身狗在最后一个的话那就会导致越界访问,虽然能够打印出没有任何问题的数据,但是一旦越界访问是十分危险的,因为这个数组越界访问一个数发现那个数并不确定是个什么数,万一是和数组中最后一个单身狗一样的数怎么办,那不是会出现失误吗??那我们就需要用接下来介绍的方法解决了。


二、异或法(仅针对一个单身狗)

(一)解题思路

在之前的学习中我们学过一个操作符叫异或,因为我们知道,异或操作符是两个二进制数相同的为0,相异的为1。同理我们有以下定律:在这里插入图片描述

(二)解题代码

#include<stdio.h>
int main() {
	int dog = 0;
	int arr[] = { 1,2,2,3,3,4,1 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	int i = 0;
	for (i = 0; i < sz; i++) {
		dog = dog ^ arr[i];
	}
	printf("这个单身狗是:%d", dog);
	return 0;
}

(三)出现的问题

这个代码看似没问题,但是我们看标题,它是只能针对一个单身狗的,而我们的最终目的是找两个单身狗,那我们仅仅全部再异或一次那完蛋了,出来的数甚至跟里面所有的值都不一样,所以我们该怎么做呢?我们接下来仔细认真看吧!!!


三、分组法(针对两个单身狗)

(一)解题思路

我们此时先假设一组数为:1 1 2 2 3 3 4 4 5 6。我们发现,如果有两个单独的数,那我们异或一下发现是5^6,那我们其实就能想到,既然5和6异或出不来两个单身狗,那就分组吧!把这两个单身狗分开分成两组,不能让他俩成了,所以我们就简单分为以下思路:
**第一步:**先全部异或,得到一个异或结果的数。在这里插入图片描述

**第二步:**从右往左依次看位,如果与1异或为1,那说明前面的两个单身狗数是在此位是不一样的值,既然值不一样,那就说明可以以这个位进行分割。
**第三步:**我们先把所有的值进行换算成二进制以后,发现是肯定在这个数组中是有情侣数是和单身狗数在某一位是一样的,那有同学问了,这到底什么意思???其实啊,很简单,就是单纯把这两个单身狗数分开,其他情侣数是怎么样都没事,因为必然会分到某一组去的,如果都分到同一组了,那也是没关系的,只要最后再来个异或拿出这个单身狗数即可。
在这里插入图片描述

(二)解题代码

//代码块1:
#include<stdio.h>
void find_digit(int* arr, int sz) {
	//1.要把所有数字异或
	int i = 0;
	int ret = 0;
	int pos = 0;
	for (i = 0; i < sz; i++) {
		ret ^= *(arr + i);
	}
	//2.计算ret哪一位为1
	for (i = 0; i < 32; i++) {
		if ((ret >> i) & 1 == 1) {//算术右移
			pos = i;
			break;
		}
	}
	//3.把从低位向高的第pos位为1的放在一个组,为0的放在另外一个组
	int num1 = 0;
	int num2 = 0;
	for (i = 0; i < sz; i++) {
		if (((*(arr + i) >> pos) & 1) == 1) {
			num1 ^= arr[i];
		}
		else {
			num2 ^= arr[i];
		}
	}
	printf("%d %d", num1, num2);
}
int main() {
	int arr[] = { 1,2,3,4,5,6,1,2,3,4 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	//进行分组
	//要点:5和6必须在不同的组
	//找出这两个只出现一次的数字
	find_digit(arr, sz);

	return 0;
}
//改进:
#include<stdio.h>
void find_digit(int* arr, int sz, int* px, int* py) {
	//1.要把所有数字异或
	int i = 0;
	int ret = 0;
	int pos = 0;
	for (i = 0; i < sz; i++) {
		ret ^= *(arr + i);
	}
	//2.计算ret哪一位为1
	for (i = 0; i < 32; i++) {
		if ((ret >> i) & 1 == 1) {//算术右移
			pos = i;
			break;
		}
	}
	//把从低位向高的第pos位为1的放在一个组,为0的放在另外一个组
	int num1 = 0;
	int num2 = 0;
	for (i = 0; i < sz; i++) {
		if (((*(arr + i) >> pos) & 1) == 1) {
			num1 ^= arr[i];
		}
		else {
			num2 ^= arr[i];
		}
	}
	*px = num1;
	*py = num2;
}
int main() {
	int arr[] = { 1,2,3,4,5,6,1,2,3,4 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	int x = 0;
	int y = 0;
	//进行分组
	//要点:5和6必须在不同的组
	//找出这两个只出现一次的数字
	find_digit(arr, sz, &x, &y);
	printf("%d %d\n", x, y);

	return 0;
}

(三)展望

这个代码其实已经挺完善的了,但肯定存在不足之处,就是这个单身狗数不确定个数,万一有三个、四个……单身狗数呢!?这个很不确定,但当然肯定有解法的,对于三个我们就是需要先一个再两个,就是做的是第二个解法加上第三个解法,依次类推,但也有一种很难很难的题目,万一这个单身狗数不确定呢!?那我们不知道怎么做了,就需要我们进行先判断有几个再相应思路进行解题,也可以用第一种解法,只不过会比较复杂,如果实在担心数组越界的问题,那就先多加一个值,再将这个值不打印即可。


总结

本题的想法和思路有很多,这边总结了两种思路,但当然了,还有更多的解法和更完善的解法等待我们去探索,当我们拥有了这些知识以后,就会知道这些知识的用法和不断巩固!!!


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/175436.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Spring事务(事务的实现、隔离级别、传播机制)

目录 一、事务的定义和意义 二、事务的实现 1、MySQL事务的回顾 2、Spring声明式事务&#xff08;利⽤注解⾃动开启和提交事务&#xff09; 前置知识及概念 实例分析&#xff1a;事务的回滚 &#x1f514;特殊情况&#xff08;无自动回滚&#xff09; &#x1f514;事务…

VueJs中如何使用provide与inject

前言在vue2.0里面provide与inject是以选项式(配置)API的方式在组件中进行使用的,解决的是跨组件(祖孙)间通信的一种方式也就是父子组件间的通信,父组件上通过自定义属性,而子组件间通过props这种方式接收,如果想要一层一层的传递,这种方式就会比较麻烦,不灵活provide与inject就…

Linux下的进程信号

目录 信号背景&#xff1a; 信号产生前 Core Dump 信号产生中 信号产生后 其他概念 不可重入函数 volatile关键字 SIGCHLD 17号信号 信号背景&#xff1a; 在生活中处处都存在的信号&#xff0c;比如信号灯&#xff0c;要想处理信号&#xff0c;我们就必须具备两种…

day26-XML/枚举/注解

1.xml 1.1概述【理解】 万维网联盟(W3C) 万维网联盟(W3C)创建于1994年&#xff0c;又称W3C理事会。1994年10月在麻省理工学院计算机科学实验室成立。 建立者&#xff1a; Tim Berners-Lee (蒂姆伯纳斯李)。 是Web技术领域最具权威和影响力的国际中立性技术标准机构。 到目前为…

AWS - IAM

AWS IAM 自用笔记。 Terms IAM - Identity and Access Management, a global service it gives: Centralized control of AWS accountShared access to AWS accountGranular permissionsIdentity Federation, i.e., Facebook, LinkedIn etc. it allows: Multi-Factor Authe…

20230121解决AIO-3568J开发板无法刷机以及串口异常的问题

20230121解决AIO-3568J开发板无法刷机以及串口异常的问题 2023/1/21 22:31 一片比较旧的AIO-3568J开发板&#xff0c;症状&#xff1a; 1、无法刷机&启动。【Loader模式 & MASKROM模式】 2、串口输出乱码&#xff01; &#xff08;一&#xff09;刷机问题的解决&#x…

一起自学SLAM算法:7.3 估计理论

连载文章&#xff0c;长期更新&#xff0c;欢迎关注&#xff1a; 不管是用贝叶斯网络还是因子图&#xff0c;一旦SLAM问题用概率图模型得到表示后&#xff0c;接下来就是利用可观测量&#xff08;和&#xff09;推理不可观测量&#xff08;和&#xff09;&#xff0c;也就是说S…

初识C语言(上)

写在前面 我们正式开始接触到C语言,这是我在学习过C语言后重新写的博客,我把之前的稍微优化了一下,希望能用更加朴素的语言和大家分享,我希望给大家带来一个可以看的懂,理论和实践并行的内容.当然里面也会存在一些错误和不恰当的地方,还请诸位指正. 为何学习C语言 我想从两个…

mac 疑难问题汇总

macos 更改zsh到bash查看当前系统有哪些bash命令行&#xff1a;cat /etc/shells切换成bash命令行&#xff1a;chsh -s /bin/bashmac触摸屏轻点设置Mac通过crontab设置定时任务报错Operation not permitted1、系统偏好设置->安全性和隐私->完全磁盘访问权限2、解除锁定允许…

【双向链表】java代码实现

前言&#xff1a; 大家好&#xff0c;我是良辰丫&#x1f353;&#x1f353;&#x1f353;&#xff0c;上一篇文章我和大家一起去探索了单链表的知识世界&#xff0c;今天我们去接触双向链表&#xff0c;什么&#xff1f;没听错&#xff0c;就是双向链表&#xff0c;比单链表更…

UE INI文件操作 INI File Operation [ Read / Write ] 插件说明

在 Windows 平台上的 INI 文件读写操作 1. Write INI String 输入&#xff1a; Directory&#xff1a; 选择保存目录 Project Directory &#xff1a; 当前项目目录Project Content Directory&#xff1a;当前项目 Content 目录Project Config Directory&#xff1a;当前项目…

JVM内存区域的划分

根据 JVM 规范&#xff0c;JVM 内存共分为虚拟机栈、堆、方法区、程序计数器、本地方法栈五个部分。 程序计数器&#xff08;线程私有&#xff09;&#xff1a; 是当前线程所执行的字节码的行号指示器&#xff0c;每条线程都要有一个独立的程序计数器&#xff0c;这类内存也称为…

Java基础08:面向对象进阶(上)

Java基础08&#xff1a;面向对象进阶&#xff08;上&#xff09;一、static1. 静态变量2. 静态方法3. 工具类4. static注意事项5. 重新认识main方法二、继承1. 继承的概念2. 继承的特点3. 继承中访问成员变量4. 继承中访问成员方法&#xff08;方法重写&#xff09;5. 继承中访…

给大家准备了程序员专属红包封面,审核通过后我哭了,太心酸了(┬_┬)

大家好&#xff0c;我是小悟 今天就是除夕了&#xff0c;也就是大年三十&#xff0c;小伙伴们应该都回家了吧&#xff0c;小悟祝大家新年快乐&#xff0c;身体健康&#xff0c;万事如意&#xff0c;兔飞猛进哦。 春节临近&#xff0c;收到微信定制红包封面并送了四千个名额的…

【深度学习】详解 MoCo

目录 摘要 一、引言 二、相关工作 三、方法 3.1 Contrastive Learning as Dictionary Look-up 3.2 Momentum Contrast 3.3 Pretext Task 四、实验 4.1 Linear Classification Protocol 总结 ☆ 实现 参考资料 Title&#xff1a;Momentum Contrast for Unsupervised…

AlmaLinux 9 安装Kasm Workspaces

今天尝试一下AlmaLinux 9 安装Kasm Workspaces。 前提条件 安装了Docker和Docker Compose&#xff0c;已经最新版本要求&#xff0c; docker 18.06 docker compose 2.1.1 创建一个Swap分区 下面的步骤将创建一个2千兆字节&#xff08;2048MB&#xff09;的交换分区。请根据…

我的创作纪念日——“永远相信美好的事情即将发生”

作者&#xff1a;非妃是公主 专栏&#xff1a;《程序人生》 个性签&#xff1a;顺境不惰&#xff0c;逆境不馁&#xff0c;以心制境&#xff0c;万事可成。——曾国藩 文章目录序与CSDN的往事机缘收获憧憬碎碎念序 第一次写创作纪念日的文章&#xff01;哈哈哈哈&#xff0c;今…

一起自学SLAM算法:7.5 基于因子图的状态估计

连载文章&#xff0c;长期更新&#xff0c;欢迎关注&#xff1a; 虽然式&#xff08;7-90&#xff09;所示的完全SLAM系统可以用滤波方法求解&#xff0c;比如著名的Fast-SLAM实现框架。但是&#xff0c;贝叶斯网络表示下的完全SLAM系统能很方面地转换成因子图表示&#xff0c;…

字符串匹配: BF与KMP算法

文章目录一. BF算法1. 算法思想2. 代码实现二. KMP算法1. 算法思想概述2. 理解基于最长相等前后缀进行匹配3. 代码中如何实现next数组5. 代码实现6. next数组的优化一. BF算法 1. 算法思想 BF 算法, 即暴力(Brute Force)算法, 是普通的模式匹配算法, 假设现在我们面临这样一个…

24/365 java 观测线程状态 线程优先级

1.观测线程 JDK中定义的线程的六个状态 &#xff1a; 可以用getState()来观测线程 public static void main(String[] args) throws InterruptedException {Thread thread new Thread(()->{for (int i 0; i < 10; i) {try {Thread.sleep(100);} catch (InterruptedExc…