待字闺中:找数字续

原题

一个数组A,数字出现的情况,只有以下三种:

1. 一些数字只出现一次

2. 一些数字出现两次

3. 只有一个数字出现三次

请给出方法,找到出现三次的数字。

分析

这个题目和“找数字”的题目比较相似,但是解法上类似么?之前的解法是检查某一位上的1的和,是否能够被3整除,因为整数是32位的,可以开辟一个 32位大小的数组,这也是常数空间的。那么这个题目可以用这个方法来解决么?因为有不确定个数的数字出现了一次,这样可以产生的余数的种类也就比较多了。 那该怎么处理呢?

hashmap的方法被称为万金油,在牺牲了空间的条件下,很好的达到了O(n)的时间复杂度。

//hash: t.O(n);s.O(n)
bool isfound = false;
int findThreeTimeNum(int* arr, int length)
{
	assert(NULL != arr && length>0);
	if(length < 3)return -1;
	unordered_map<int, int> mp;
	unordered_map<int, int>::iterator it = mp.end();
	for(int i = 0; i < length; i++)//O(n)
	{
		it = mp.find(arr[i]);
		if(it == mp.end())
			mp[arr[i]] = 1;
		else
			mp[arr[i]]++;
	}
	for(it = mp.begin(); it != mp.end(); it++)//O(n)
		if(it->second == 3){
			isfound = true;
			return it->first;
		}
	return -1;
}

如果要求常数空间的解法呢?之前的文章也有讨论,快排的时间复杂度是O(nlogn),然后遍历一遍,找到连续三个相同的数字。后面这一遍遍历,可以省去,因为出现三次的数字只有一个。但总的时间复杂度仍是O(nlogn)。

//sort: O(nlogn)
bool isfound = false;
int findThreeTimeNum(vector<int> arr)
{
	sort(arr.begin(),arr.end());
	int times = 1;
	int curnum = arr[0];
	vector<int>::iterator it = arr.begin();
	for(it++; it != arr.end(); it++)
	{
		if(curnum == *it)
			times++;
		else{
			curnum = *it;
			times=1;
		}
		if(times == 3)
		{
			if((it+1) == arr.end() || *(it+1) != curnum){
				isfound = true;
				return *it;
			}
		}
	}
	return -1;
}

是否还有其他的方法呢?有的同学给出了如下的方法:可以取得A中所有数字的乘积p,我们假设p没有溢出。这是遍历数组中的每一个元素A[i],查看 是否p % (A[i] * A[i] * A[i]) == 0,但此时,A[i]并不一定是最终要找到的数字,还需要遍历数组A,查看A[i]是否出现了三次。但这个方法整体的时间复杂度为O(n^2)。如果数组中的数都是素数的话,这个方法可行,复杂度为O(n).

这个题目,能够在时间复杂度O(n),空间复杂度O(1)的条件下完成么?



From:http://www.ituring.com.cn/article/56182

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值