OJ刷题:《剑指offer》之单身狗1、2 !(巧用位操作符,超详细讲解!)

2024-02-04 14:36

本文主要是介绍OJ刷题:《剑指offer》之单身狗1、2 !(巧用位操作符,超详细讲解!),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

1.单身狗1

1.1 题目描述

1.2排序寻找

1.3巧用位操作符

2.单身狗2

1.1 题目描述

1.2排序寻找

1.3巧用位操作符


                           不是每个人都能做自己想做的事,成为自己想成为的人。

                                                  克心守己,律己则安!

创作不易,宝子们!如果这篇文章对你们有帮助的话,别忘了给个免费的赞哟~ 

1.单身狗1

1.1 题目描述

在一个整型数组中,只有一个数字出现一次,其他数组都是成对出现的,请找出那个只出现一次的数字。

例如:

数组中有:1 2 3 4 5 1 2 3 4,只有5出现一次,其他数字都出现2次,出5

1.2排序寻找

1. 对于一个无序的数组,当我们将他们进行排序后,一切问题都会简单很多的~

冒泡排序的伪代码~

void sort(int arr[], int len)
{int i = 0;int j = 0;for (i = 0; i < len - 1; i++){int flag = 1;for (j = 0; j < len - 1; j++){if (arr[j] > arr[j + 1]){int tmp = arr[j];arr[j] = arr[j + 1];arr[j + 1] = tmp;flag = 0;}}if (flag == 1)break;}//冒泡排序-》升序数组
}

2. 那我们要如何找到那个“单身狗”呢~

我们可以很容易的注意到相邻的2个元素是相同的,那我们是不是可以俩俩比较呢,若不同,则前面的那个元素一定就是“单身狗”啦~

下面是这部分的伪代码~

for (i = 0; i < len; i+=2)
{if (arr[i] != arr[i + 1]){printf("单身狗数字是:%d\n", arr[i]);break;}
}

3. 不过,我们还要考虑边界情况呢~

当我们将前面的元素都比较完后,还没有找到单身狗,而按照上面的算法逻辑的话,最后那个元素是无法俩俩比较的,那我们该怎么办呢~

我们不妨立个flag=1;若在上面的逻辑中找到单身狗,flag=0,若没有找到,flag还是=1,

那单身狗就是最后那个元素啦~

int flag = 1;
for (i = 0; i < len; i+=2)
{if (arr[i] != arr[i + 1]){printf("单身狗数字是:%d\n", arr[i]);flag = 0;break;}
}
if (flag == 1)printf("单身狗数字是:%d\n", arr[len-1]);

1.3巧用位操作符

1. 这个题目其实还有更为巧妙的方法呢~

这里先给俩个结论1.相同的俩个元素^(抑或)结果为零~

                                 2.零与其他元素抑或结果为那个元素本身~

那是为什么呢~(其实在我之前的博客也提到过,这里再说明一下)http://【有趣的移位操作符和位操作符(由浅入深轻松搞定!) - CSDN App】http://t.csdnimg.cn/q2ubr

2. 好了,知道了这些那这个题目就显得异常简单了啦~

我们将所有元素抑或起来是不是就找到了那个单身狗呢~

下面是这部分的伪代码~

int find_single_dog(int arr[], int sz)
{int ret = 0;int i = 0;for (i = 0; i < sz; i++){ret ^= arr[i];}return ret;
}//sz是数组的长度

2.单身狗2

1.1 题目描述

一个数组中只有两个数字是出现一次,其他所有数字都出现了两次。

编写一个函数找出这两个只出现一次的数字。

例如:

有数组的元素是:1,2,3,4,5,1,2,3,4,6

只有5和6只出现1次,要找出5和6.

1.2排序寻找

1.这个题目如果用排序来做的话,主要的算法部分其实和前面的是差不多的~

唯一不同的是我们要找的俩个“单身狗”后才能结束寻找~

我们可以用count来计数,当count==2时,就结束寻找~

代码如下~

for (i = 0; i < len-1; i+=2)
{if (arr[i] != arr[i + 1]){printf("单身狗是%d\n", arr[i]);count++;i--;}if (count == 2)break;
}

2. 当然我们还要考虑边界情况的~

我们可以很容易的知道上面的代码逻辑一定可以至少找到一个单身狗5

当循环结束后i是等于len-1的,所以优化后的代码如下~

	for (i = 0; i < len-1; i+=2){if (arr[i] != arr[i + 1]){printf("单身狗是%d\n", arr[i]);count++;i--;}if (count == 2)break;}if(i==len-1)printf("单身狗是%d\n", arr[i]);//考虑边界情况
}

1.3巧用位操作符

1. 上面的代码还是不够牛逼,让我们看看牛逼的代码~

当单身狗只有一个时,我们可以用位操作的方法快速找到,这里有俩个不同的元素,这时我们就不可以简单的将他们全部抑或起来了,那怎么办呢~

2. 我们可不可以想办法将这俩个单身狗分开来后再进行抑或呢~(举个栗子,数据不一定正确分配)

3. 我们先将所有元素抑或起来(还是以上面的元素为例~)

然后我们将结果放到临时变量tmp中,那tmp到底有什么用呢~

我们仔细思考一下就会惊奇的发现(找到tmp二进制中第一个1(相异为1)可以区分俩个不同的单身狗!)即:找到有分歧的一位。在这一位上,两个数一定是一个1一个0

找tmp二进制中的第一个1的代码如下~

//找到tmp二进制中第一个1(相异为1)区分俩个不同的元素
int count = 0;//用count来记录tmp二进制中的第一个1
while ((tmp & (1<<count))==0)
{count++;
}

4. 最后,我们要将数组中的所有元素右移count位后再与一按位与(此时一定可以将不同的单身狗区分开来,至于其他相同的元素不管他们那一位上是1还是0都会被分配到相同的部分

//数组中的元素右移count后&1
for (int i = 0; i < len; i++)
{if (((arr[i] >>= count) & 1) == 1)*tmp1^= arr[i];else*tmp2^= arr[i];
}

注:tmp1和tmp2一定要初始化为零呢~,还要注意运算符的优先级(一定要加括号按照我们的思路计算!)

附:完整的代码~

void Fun(int arr[], int*tmp1, int*tmp2, int len)
{int tmp = 0;//将所有元素抑或起来结果放到tmp中for (int i = 0; i < len; i++)tmp ^= arr[i];//找到tmp二进制中第一个1(相异为1)区分俩个不同的元素int count = 0;//用count来记录tmp二进制中的第一个1while ((tmp & (1<<count))==0){count++;}//数组中的元素右移count后&1for (int i = 0; i < len; i++){if (((arr[i] >>= count) & 1) == 1)*tmp1^= arr[i];else*tmp2^= arr[i];}
}

5.完结散花

好了,这期的分享到这里就结束了~

如果这篇博客对你有帮助的话,可以用你们的小手指点一个免费的赞并收藏起来哟~

如果期待博主下期内容的话,可以点点关注,避免找不到我了呢~

我们下期不见不散~~

 

这篇关于OJ刷题:《剑指offer》之单身狗1、2 !(巧用位操作符,超详细讲解!)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/677832

相关文章

电脑密码怎么设置? 一文读懂电脑密码的详细指南

《电脑密码怎么设置?一文读懂电脑密码的详细指南》为了保护个人隐私和数据安全,设置电脑密码显得尤为重要,那么,如何在电脑上设置密码呢?详细请看下文介绍... 设置电脑密码是保护个人隐私、数据安全以及系统安全的重要措施,下面以Windows 11系统为例,跟大家分享一下设置电脑密码的具体办php法。Windo

JSON字符串转成java的Map对象详细步骤

《JSON字符串转成java的Map对象详细步骤》:本文主要介绍如何将JSON字符串转换为Java对象的步骤,包括定义Element类、使用Jackson库解析JSON和添加依赖,文中通过代码介绍... 目录步骤 1: 定义 Element 类步骤 2: 使用 Jackson 库解析 jsON步骤 3: 添

将sqlserver数据迁移到mysql的详细步骤记录

《将sqlserver数据迁移到mysql的详细步骤记录》:本文主要介绍将SQLServer数据迁移到MySQL的步骤,包括导出数据、转换数据格式和导入数据,通过示例和工具说明,帮助大家顺利完成... 目录前言一、导出SQL Server 数据二、转换数据格式为mysql兼容格式三、导入数据到MySQL数据

Redis的Zset类型及相关命令详细讲解

《Redis的Zset类型及相关命令详细讲解》:本文主要介绍Redis的Zset类型及相关命令的相关资料,有序集合Zset是一种Redis数据结构,它类似于集合Set,但每个元素都有一个关联的分数... 目录Zset简介ZADDZCARDZCOUNTZRANGEZREVRANGEZRANGEBYSCOREZ

Go中sync.Once源码的深度讲解

《Go中sync.Once源码的深度讲解》sync.Once是Go语言标准库中的一个同步原语,用于确保某个操作只执行一次,本文将从源码出发为大家详细介绍一下sync.Once的具体使用,x希望对大家有... 目录概念简单示例源码解读总结概念sync.Once是Go语言标准库中的一个同步原语,用于确保某个操

Java操作PDF文件实现签订电子合同详细教程

《Java操作PDF文件实现签订电子合同详细教程》:本文主要介绍如何在PDF中加入电子签章与电子签名的过程,包括编写Word文件、生成PDF、为PDF格式做表单、为表单赋值、生成文档以及上传到OB... 目录前言:先看效果:1.编写word文件1.2然后生成PDF格式进行保存1.3我这里是将文件保存到本地后

windows系统下shutdown重启关机命令超详细教程

《windows系统下shutdown重启关机命令超详细教程》shutdown命令是一个强大的工具,允许你通过命令行快速完成关机、重启或注销操作,本文将为你详细解析shutdown命令的使用方法,并提... 目录一、shutdown 命令简介二、shutdown 命令的基本用法三、远程关机与重启四、实际应用

使用SpringBoot创建一个RESTful API的详细步骤

《使用SpringBoot创建一个RESTfulAPI的详细步骤》使用Java的SpringBoot创建RESTfulAPI可以满足多种开发场景,它提供了快速开发、易于配置、可扩展、可维护的优点,尤... 目录一、创建 Spring Boot 项目二、创建控制器类(Controller Class)三、运行

springboot整合gateway的详细过程

《springboot整合gateway的详细过程》本文介绍了如何配置和使用SpringCloudGateway构建一个API网关,通过实例代码介绍了springboot整合gateway的过程,需要... 目录1. 添加依赖2. 配置网关路由3. 启用Eureka客户端(可选)4. 创建主应用类5. 自定

最新版IDEA配置 Tomcat的详细过程

《最新版IDEA配置Tomcat的详细过程》本文介绍如何在IDEA中配置Tomcat服务器,并创建Web项目,首先检查Tomcat是否安装完成,然后在IDEA中创建Web项目并添加Web结构,接着,... 目录配置tomcat第一步,先给项目添加Web结构查看端口号配置tomcat    先检查自己的to