剑指offer 数组中出现次数超过一半的数字

题目如下:题目描述,数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。如果不存在则输出0。

在《剑指offer》一书中,提供了两种思路,第一种使用快速排序,第二种使用数组本身的特点做,具体方法分别讨论如下:

第一种解法,使用快速排序:

我们可以使用快速排序,每次求出一个数字在排序好的序列中的位置。从题目上来看,如果一个数字出现的次数比该数组的一半还多,就是说明,该数字应该出现在排序好的序列中的中间位上,因此,我们可以使用快速排序,找到在排序好的序列中在中间位置的数字,然后判断一下这个数字出现的次数是不是我们要找的。具体代码如下:
class Solution {
public:
	int Partition(vector<int> &numbers, int length, int start, int end) {
		// 使用剑指offer里的思路,在快速排序中,基数每次都使用序列的第一个元素
		swap(numbers[start], numbers[end]);
		int small = start - 1;
		for (int i = start; i < end; i++) {
			if (numbers[i] < numbers[end]) {
				small++;
				if (i != small) {
					swap(numbers[small], numbers[i]);
				}
			}
		}
		small++;
		swap(numbers[small], numbers[end]);
		return small;
	}

	int getResult(vector<int> &number, int length, int start, int end) {
		int middle = length >> 1;
		int index = Partition(number, length, start, end);
		// 下面的while循环每次都判断一下是不是中间位,如果不是,就继续寻找
		while (middle != index) {
			if (index < middle) {
				// 如果返回的下标比中间位小,说明中间位应该在该下标的右边
				start = index + 1;
				index = Partition(number, length, start, end);
			}
			else {
				// 如果返回的下标比中间位大,说明中间位应该在该下标的左边
				end = index - 1;
				index = Partition(number, length, start, end);
			}
		}
		int count = 0;
		// 判断一下出现的次数,两倍是不是比数组长度大
		for (auto x : number) {
			count += (x == number[index]);
		}
		if (count * 2 > length) return number[index];
		else return 0;
	}

	int MoreThanHalfNum_Solution(vector<int> numbers) {
		if (numbers.size() == 0) return 0;
		else return getResult(numbers, numbers.size(), 0, numbers.size() - 1);
	}
};

第二种解法:使用数组本身的特点,如果该数字出现的次数超过整体数组的长度,那么所有数字加起来,都没有那个数字出现的次数多。可以刚开始设置一个次数count,和一个初始化下标index。从前到后遍历这个数组,如果该数组的某一位和前一个为相同,则count加一,否则减一,某次循环中如果count为0,则将该位置的下标赋值给index,次数加一。

class Solution {
public:
	int MoreThanHalfNum_Solution(vector<int> numbers) {
		int index = 0;
		int count = 0;
		for (int i = 0; i < numbers.size(); i++) {

			if (numbers[i] == numbers[index]) {
				count++;
			}
			else if (count == 0) {
				// 这里是numbers[i] != numbers[index]的前提
				index = i;
			}
			else {
				count--;
			}
		}
		count = 0;
		for (int i = 0; i < numbers.size(); i++)
			count += (numbers[index] == numbers[i]);
		if (count <= numbers.size() >> 1) return 0;
		return numbers[index];
	}
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值