给定一个大小为 n 的数组 nums ,返回其中的多数元素。多数元素是指在数组中出现次数 大于 ⌊ n/2 ⌋ 的元素。
你可以假设数组是非空的,并且给定的数组总是存在多数元素。
进阶:尝试设计时间复杂度为 O(n)、空间复杂度为 O(1) 的算法解决此问题。
解法一:排序
多数元素在数组中至少占一半,因此将数组生序或者降序排列,中间位置的元素一定是多数元素。
ini
function majorityElement(nums: number[]): number {
const sortedNums:number[] = []
const len = nums.length
for (let i = 0; i < len; i++) {
let insertIndex = 0;
while(insertIndex <= sortNums.length) {
if (insertIndex === sortedNums.length || sortedNums[insertIndex] > nums[i] ) {
sortedNums.splice(insertIndex,0, nums[i])
break
}
insertIndex++
}
}
const m = Math.floor(sortedNums.length / 2)
return sortedNums[m]
};
有嵌套循环因此时间复杂度为 O(n * n),有额外的中间量存储空间,空间复杂度为 O(n)
解法二:hash 表
用一个 map 统计数组中元素出现的次数,key 为 数组中的元素,value 为元素出现的次数,统计结束,判断哪个元素出现的次数大于 ⌊ n/2 ⌋,满足要求的元素是多数元素。
typescript
function majorityElement(nums: number[]): number {
const countMap = new Map<number,number>()
nums.forEach(num => {
const curCount = countMap.get(num) || 0
countMap.set(num,curCount + 1)
})
const maxCount = Math.round(nums.length / 2)
for (const [number, count] of countMap) {
if (count >= maxCount) {
return number
}
}
}
countMap.size 的最大值为 n/2,两次遍历的时间复杂度为 O (n + n/2) => O ( 2 * n), 有额外的中间量存储空间,空间复杂度为 O(n)
解法三:摩尔投票法
假设,数组中的元素是人,相同元素属于相同的团,元素的数量是团的人数,让不同团的两两决战,每人只能决战一次,决战之后离开团,这些团剩下的人就是多数元素.
ini
function majorityElement(nums: number[]):number {
let majority
let count = 0
nums.forEach(num => {
if (count === 0) {
majority = num
}
if (num === majority) {
count ++
}
if (num !== majority) {
count --
}
})
return majority
}
时间复杂度O(n),空间复杂度 O(1)