使用异或查找数组中出现奇数次的唯一或唯二数字

2023-12-03 04:36

本文主要是介绍使用异或查找数组中出现奇数次的唯一或唯二数字,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

题目:
1.查找数组中的所有出现奇数次的数字,要求数组中不能有负数

2.现在有个数组,假设这个数组中出现奇数次的数字有且只有1个,请把它找出来

3.现在有个数组,假设这个数组中出现奇数次的数字有且只有2个,请把它找出来

先看题1的:
以下代码用c实现,由于c语言中没有字典,也不想上升到c++,所以实现起来较为复杂,可以不看,直接看下面的异或算法

#include<stdio.h>
#include <stdlib.h>struct MyStruct
{int* arr;int arr_size;
};int cmpfunc(const void* a, const void* b)
{return (*(int*)a - *(int*)b);
}
struct MyStruct find_odd_occurrence(int a[], int n) {//查找数组中的所有出现奇数次的数字,要求数组中不能有负数//先对数组a进行排序qsort(a, n, sizeof(int), cmpfunc);int last_num = - 1;int* res = (int*)malloc(n * sizeof(int));int res_index = 0;for (int i = 0; i < n; i++) {if (last_num == a[i]) {continue;}else {last_num = a[i];}int count = 1;for (int j = i + 1; j < n; j++) {if (a[j] == a[i]) {count += 1;}}if (count % 2 == 1) {res[res_index] = a[i];res_index += 1;}}//重新申请一个数组把多余的数字去掉int* res_arr = (int*)malloc(res_index * sizeof(int));for (int x = 0; x < res_index; x++) {res_arr[x] = res[x];}free(res);struct MyStruct real_res;real_res.arr = res_arr;real_res.arr_size = res_index;return real_res;
}int main() {int b[8] = { 1,2,2,9,4,4,5,5 };struct MyStruct res = find_odd_occurrence(b, 8);for (int k = 0; k < res.arr_size; k++) {printf("%d\n", res.arr[k]);}free(res.arr);return 0;
}

如上,经历了排序,2层for循环再遍历查找计数,再遍历计数为奇数项的数字,再处理结果,得到了一个通用的获取数组中所有出现奇数次的函数。

再看题2的

#include<stdio.h>int find1odd(int a[], int n) {//要求数组a中只有一个数字出现奇数次,则本函数能快速查找到数组中的这个数int res = 0;for (int i = 0; i < n; i++) {res ^=  a[i];}return res;
}int main() {int a[11] = { 1,1,2,2,2,3,2, 3,4,3,3 };printf("%d\n", find1odd(a, 11));return 0;
}

异或的规则:
(1)相同为0,相异为1
(2) 异或满足交换律,即 a ^ b ^ c = a ^ ( b ^ c) = a ^ c ^ b
(3) N ^ N = 0, N ^ 0 = N;

解读:
数组中出现偶数次的数字异或后通通为0,类似消消乐可以直接划掉,最后只剩下了出现奇数次的数字。

然后我们再看看第三题的

#include<stdio.h>int or2(int a[], int n) {//假设数组a中只有2个数字出现奇数次int res = 0;for (int i = 0; i < n; i++) {res ^=  a[i];}return res;
}int find_right1(int n) {//查找一个数最右边的1,如0b000001100,返回0b000000100return n & (~n + 1);
}int get1fromgroup(int a[], int n, int right1) {//原理是进行2分组,一组和right1中1的位置同样是1,一组是0int res = 0;for (int i = 0; i < n; i++) {if (a[i] & right1) {res ^= a[i];}}return res;
}int main() {int b[8] = { 1,2,2,9,4,4,5,5};int two_or = or2(b, 8);int right1 = find_right1(two_or);int one_odd = get1fromgroup(b, 8, right1);int other_odd = two_or ^ one_odd;printf("%d, %d", one_odd, other_odd);return 0;
}

解读:
数组中出现偶数次的数字异或后直接消失,只剩下2个奇数异或的值,表示为 two_or = x ^ y
假设这个two_or = b00001101,根据相异为1,我们分析1出现的位置x和y只能有一个贡献了1,那么我们可以根据其中任意一位的1对所有数组中的数字进行分组,即此位是1还是0进行分组,那么x和y必然分别出现两个分组里, 然后其它数字不管此位是0还是1,全部是出现了偶数次,所以不管分在那个分组,经过异或后全部抵消掉了。
这里我们选择的是出现在最右侧的1,这里有个小技巧
即 查找一个数最右边的1,可以通过 n & (~n + 1)得到,如获取整数6的最右侧的1
0b0000 0110
取反得到0b1111 1001
再+1得到0b1111 1010
&后 得到 0b0000 0010
(&的规则是两个都为1(真)则1(真),其它全部为0(假))

这篇关于使用异或查找数组中出现奇数次的唯一或唯二数字的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

使用Python构建一个Hexo博客发布工具

《使用Python构建一个Hexo博客发布工具》虽然Hexo的命令行工具非常强大,但对于日常的博客撰写和发布过程,我总觉得缺少一个直观的图形界面来简化操作,下面我们就来看看如何使用Python构建一个... 目录引言Hexo博客系统简介设计需求技术选择代码实现主框架界面设计核心功能实现1. 发布文章2. 加

C++中初始化二维数组的几种常见方法

《C++中初始化二维数组的几种常见方法》本文详细介绍了在C++中初始化二维数组的不同方式,包括静态初始化、循环、全部为零、部分初始化、std::array和std::vector,以及std::vec... 目录1. 静态初始化2. 使用循环初始化3. 全部初始化为零4. 部分初始化5. 使用 std::a

shell编程之函数与数组的使用详解

《shell编程之函数与数组的使用详解》:本文主要介绍shell编程之函数与数组的使用,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录shell函数函数的用法俩个数求和系统资源监控并报警函数函数变量的作用范围函数的参数递归函数shell数组获取数组的长度读取某下的

使用Python开发一个带EPUB转换功能的Markdown编辑器

《使用Python开发一个带EPUB转换功能的Markdown编辑器》Markdown因其简单易用和强大的格式支持,成为了写作者、开发者及内容创作者的首选格式,本文将通过Python开发一个Markd... 目录应用概览代码结构与核心组件1. 初始化与布局 (__init__)2. 工具栏 (setup_t

Python虚拟环境终极(含PyCharm的使用教程)

《Python虚拟环境终极(含PyCharm的使用教程)》:本文主要介绍Python虚拟环境终极(含PyCharm的使用教程),具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,... 目录一、为什么需要虚拟环境?二、虚拟环境创建方式对比三、命令行创建虚拟环境(venv)3.1 基础命令3

Python Transformer 库安装配置及使用方法

《PythonTransformer库安装配置及使用方法》HuggingFaceTransformers是自然语言处理(NLP)领域最流行的开源库之一,支持基于Transformer架构的预训练模... 目录python 中的 Transformer 库及使用方法一、库的概述二、安装与配置三、基础使用:Pi

关于pandas的read_csv方法使用解读

《关于pandas的read_csv方法使用解读》:本文主要介绍关于pandas的read_csv方法使用,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录pandas的read_csv方法解读read_csv中的参数基本参数通用解析参数空值处理相关参数时间处理相关

使用Node.js制作图片上传服务的详细教程

《使用Node.js制作图片上传服务的详细教程》在现代Web应用开发中,图片上传是一项常见且重要的功能,借助Node.js强大的生态系统,我们可以轻松搭建高效的图片上传服务,本文将深入探讨如何使用No... 目录准备工作搭建 Express 服务器配置 multer 进行图片上传处理图片上传请求完整代码示例

SpringBoot条件注解核心作用与使用场景详解

《SpringBoot条件注解核心作用与使用场景详解》SpringBoot的条件注解为开发者提供了强大的动态配置能力,理解其原理和适用场景是构建灵活、可扩展应用的关键,本文将系统梳理所有常用的条件注... 目录引言一、条件注解的核心机制二、SpringBoot内置条件注解详解1、@ConditionalOn

Python中使用正则表达式精准匹配IP地址的案例

《Python中使用正则表达式精准匹配IP地址的案例》Python的正则表达式(re模块)是完成这个任务的利器,但你知道怎么写才能准确匹配各种合法的IP地址吗,今天我们就来详细探讨这个问题,感兴趣的朋... 目录为什么需要IP正则表达式?IP地址的基本结构基础正则表达式写法精确匹配0-255的数字验证IP地