注:本文的代码实现使用的是 JS(JavaScript),为前端中想使用JS练习算法和数据结构的小伙伴提供解题思路。
描述
给一个长度为 n 的数组,数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。
例如输入一个长度为9的数组[1,2,3,2,2,2,5,4,2]。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。
保证数组输入非空,且保证有解
示例:
输入: [1,2,3,2,2,2,5,4,2]
返回值:2
输入:[3,3,3,3,2,2,2]
输出:3
输入:[1]
输出:1
提示:
- 数据范围: n < = 5000 n <= 5000 n<=5000,数组中元素的值 0 < = v a l < = 10000 0<= val <= 10000 0<=val<=10000
- 要求:空间复杂度: O ( 1 ) O(1) O(1),时间复杂度 O ( n ) O(n) O(n)
解题思路
排序法
先把数组排序,出现次数最多的元素一定会在排序后数组的最中间的位置。其复杂度为 O ( n l o g n ) O(nlogn) O(nlogn)
function MoreThanHalfNum_Solution(numbers)
{
// 排序
numbers = numbers.sort((a,b) => a-b)
// numbers.length >> 1 ,即向右以一位,相当于除2
return numbers[numbers.length >> 1]
}
哈希法
使用哈希表对数组中的每一个元素计数,找出个数大于numbers
长度的一半的那个元素即可。其时间和空间复杂度都为
O
(
n
)
O(n)
O(n)
function MoreThanHalfNum_Solution(numbers)
{
let obj = {}
// 其实在这里整除不整除无所谓,因为是比较元素个数和原数组长度的一半
let len = numbers.length / 2
// 统计每个元素出现的个数
for(const num of numbers){
if(obj.hasOwnProperty(num)) obj[num] ++
else obj[num] = 1
}
// 直接返回个数大于原数组长度的一半的那个元素
for(const item in obj){
if(obj[item] > len) return item
}
}
指针法
可以定义两个变量,一个num
用于存放某个元素,一个count
用于存放该元素的个数。遍历number
,若num
和当前元素相等,则count ++
,否则,count --
。每次遍历时,判断count
是否为0, 若为0,则将当前元素赋值给num
,且count =1
。这样,最后num
所指的元素一定是出现次数超过原数组长度的一半的那个元素。
理由很简单,如果有符合条件的数字,则它出现的次数比其他所有数字出现的次数和还要多。
function MoreThanHalfNum_Solution(numbers)
{
let num = numbers[0]
let count = 1
for(let i = 1, len = numbers.length; i < len; i++){
if(num !== numbers[i]) count --
else count ++
// 这个 if 判断可以放在上一个 if 语句的上面
if(count === 0) {
num = numbers[i]
count = 1
}
}
return num
}