NO40、数组中只出现一次的数字(再刷)

本文介绍了如何使用哈希表和异或操作高效地找出整型数组中仅出现一次的两个数字。两种方法对比,异或方法通过一次异或运算及位操作快速定位不同数,时间效率和内存消耗均为3ms和376k。
40、数组中只出现一次的数字 再刷

一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。

1、常规做法
    void FindNumsAppearOnce(vector<int> data,int* num1,int *num2) {
	unordered_map<int, int> unmp;
	for (int i = 0; i < data.size(); ++i) {
			unmp[data[i]] += 1;
	}


	auto it = unmp.begin();
	while (it != unmp.end()) {
		if (it->second == 1) {
			*num1 = it->first;
			++it;
			break;
		}
		++it;
	}

	while (it != unmp.end()) {
		if (it->second == 1) {
			*num2 = it->first;
			break;
		}
		++it;
	}
    }
二刷:
1、hash表的笨方法

运行时间:3ms 占用内存:376k

void FindNumsAppearOnce(vector<int> data,int* num1,int *num2) {

        unordered_map<int,int> unmp;
        
        for(auto a:data){
            unmp[a]++;
        }
        
        auto beg = unmp.begin();
        while(beg != unmp.end())
        {
            if(beg->second == 1)
            {
                *num1 = beg->first;
                beg++;
                break;
            }
            beg++;
            
        }
        
        while(beg != unmp.end())
        {
            if(beg->second == 1)
            {
                *num2 = beg->first;
                break;
            }
            beg++;
            
        }
    }
2、异或做法,很棒

只有一个数出现一次时,我们把数组中所有的数,依次异或运算,最后剩下的就是落单的数,因为成对儿出现的都抵消了。

依照这个思路,我们来看两个数(我们假设是AB)出现一次的数组。我们首先还是先异或,剩下的数字肯定是A、B异或的结果,这个结果的二进制中的1,表现的是A和B的不同的位。我们就取第一个1所在的位数,假设是第3位,接着把原数组分成两组,分组标准是第3位是否为1。如此,相同的数肯定在一个组,因为相同数字所有位都相同,而不同的数,肯定不在一组。然后把这两个组按照最开始的思路,依次异或,剩余的两个结果就是这两个只出现一次的数字。

运行时间:3ms 占用内存:376k

    void FindNumsAppearOnce(vector<int> data,int* num1,int *num2) {

       
       	if (data.size() < 2) return;

	int totalNum = 0;
	for (int i = 0; i < data.size(); i++) {
		totalNum ^= data[i];//所有数异或,结果为不同的两个数字的异或
	}

	int sign = 0;//标志位,记录totalNum中的第一个1出现的位置
	for (; sign < data.size(); sign++) {
		if ((totalNum & (1 << sign)) != 0) { //左移 sign 位,将所有数字进行左移sign位,而低位补上0
			break;
		}
	}
	cout << sign << endl;
	num1[0] = 0;
	num2[0] = 0;
	for (int i = 0; i < data.size(); i++) {
		if ((data[i] & (1 << sign)) == 0) {//标志位为0的为一组,异或后必得到一个数字(这里注意==的优先级高于&,需在前面加())
			num1[0] ^= data[i];
			cout << "0 "<<data[i] << " " << (1<<sign) << endl;
		}
		else {
			num2[0] ^= data[i];//标志位为1的为一组
			cout << "1 " << data[i] << " " << (1 << sign) << endl;
		}
	}

	cout << num1[0] << num2[0] << endl;
        
    }

美女帅哥们如果觉得写的还行,有点用的话麻烦点个赞或者留个言支持一下阿秀~
如果觉得狗屁不通,直接留言开喷就完事了。

需要该笔记PDF版本的去个人公众号【拓跋阿秀】下回复“阿秀剑指offer笔记”即可。

在C语言中,要在一个数组中找到只出现一次的数,可以使用哈希表(如标准库中的`std::unordered_map`)或者通过遍历数组并记录每个元素的出现次数来实现。这里我们提供一个简单的线性时间复杂度O(n)的解决方案,即使用一个计数数组: ```c #include <stdio.h> // 使用一个额外的数组来存储每个元素出现的次数 int* count_elements(int arr[], int size, int* result) { int count[size], temp; for (int i = 0; i < size; i++) { if (arr[i] != -1) { // 如果元素未被标记,则更新计数 count[arr[i]]++; } else { // 如果元素已经被标记(值为-1),则它是唯一出现一次的数 temp = arr[i]; while (temp != -1) { arr[temp] = -1; // 标记这个元素以便后续查找 temp = count[temp]; // 跟随计数值移动 } *result = temp; return arr; } } // 如果所有元素都出现了两次,返回NULL return NULL; } int main() { int arr[] = {1, 2, 3, 4, 5, 6, 7, 2, 1}; int size = sizeof(arr) / sizeof(arr[0]); int unique_num; arr = count_elements(arr, size, &unique_num); if (arr == NULL) { printf("No unique element found.\n"); } else { printf("The unique element is: %d\n", unique_num); } return 0; } ``` 在这个例子中,数组中的初始值为`-1`表示该位置未处理过。程序会遍历数组,对于每个未标记的元素,将其计数加一;当遇到已标记的元素时(值为`-1`),它就是唯一出现一次的数。当遍历结束后,如果没有找到唯一元素,函数会返回`NULL`。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

拓跋阿秀

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值