1.题目描述
数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。如果不存在则输出0。
2.题目分析
思路一:暴力枚举
先排序,然后找出中间的值,复杂的O(nlogn)
思路二:利用O(n)的空间,换取时间复杂度O(n)
基于快排思想中的partition函数来做,因为根据题目,那么排序后的数组中间的数就是那个出现次数超过一半的数,那么我只需要利用快排中的partition,找到长度为n的数组中间n/2大的那个数就行。
我们有成熟的时间复杂度为的算法得到数组中任意第k大的数字。只不过现在的K值为数组长度的一半。
思路三:利用这个数组的特性,保存两个值,一个是数组中的数字,另一个是次数。
根据数组特点来做,数组中有一个数字出现的次数超过数组长度的一半,也就是说它出现的次数比其他所有数字出现的次数的和还要多。因此,我们可以考虑在遍历数组的时候保存两个值:一个是数组中的一个数字;一个是次数。当我们便利到下一个数字的时候,如果下一个数字和我们之前保存的数字相同,则次数加1;如果下一个数字和我们之前保存的数字不同,则次数减1.如果次数为零,那我们需要保存下一个数字,并把次数设为1.由于我们要找的数字出现的次数比其他所有数字出现次数之和还要多,那么要找的数字肯定是最后一次把次数设为1对应的数字。
3.代码
思路二:
// 第一种 function MoreThanHalfNumSolution(numbers) { const left = 0, right = numbers.length - 1; let key = partition(numbers, left, right); const mid = numbers.length >> 1; while (key !== mid) { if (key > mid) { key = partition(numbers, left, key - 1); } else { key = partition(numbers, key + 1, right); } } let res = numbers[mid]; if (!checkMoreThanHalf(numbers, res)) { res = 0; } return res; } function partition(a, left, right) { const key = a[left]; // 一开始让key为第一个数 while (left < right) { // 扫描一遍 while (key <= a[right] && left < right) { // 如果key小于a[right],则right递减,继续比较 right--; } [a[left], a[right]] = [a[right], a[left]]; // 交换 while (key >= a[left] && left < right) { // 如果key大于a[left],则left递增,继续比较 left++; } [a[left], a[right]] = [a[right], a[left]]; // 交换 } return left; // 把key现在所在的下标返回 } function checkMoreThanHalf(numbers, num) { let times = 0; for (let i = 0; i < numbers.length; i++) { if (num === numbers[i]) { times++; } } if (times * 2 <= numbers.length) { return false; } return true; }
思路三:
// 第二种 function MoreThanHalfNumSolution2(numbers) { let res = numbers[0], times = 1; for (let i = 0; i < numbers.length; i++) { if (times === 0) { res = numbers[i]; times = 1; } else if (numbers[i] === res) { times++; } else { times--; } } if (!checkMoreThanHalf(numbers, res)) { res = 0; } return res; } function checkMoreThanHalf2(numbers, num) { let times = 0; for (let i = 0; i < numbers.length; i++) { if (num === numbers[i]) { times++; } } if (times * 2 <= numbers.length) { return false; } return true; }
参考文章:
https://www.cnblogs.com/echovic/p/6541681.html
https://www.cnblogs.com/wuguanglin/p/MoreThanHalfNum_Solution.html
https://github.com/DavidChen93/-offer-JS-/blob/master/39.1 数组中出现次数超过一半的数字.js