背景:找出一组数字序列中出线次数大于总数 1/2 的数字(并假设一定存在这个数字)。显然这个数字只存在一个。
每次从序列出选择两个不相同的数字删掉(或者是“抵消”),最后剩下的一个数字或几个相同的数字,就是出现次数大于总数一半的那个。
中心思想就是:删除,删除,删除,直到不能删除为止。
维护两个变量,分别是最后的结果 res
和计数值 count
,其实这俩变量表达的是一个隐形的数组,数组中存储的是 当前暂时无法删除的数字 也就是 res
, count
表示数组的长度
伪代码
- 初始化元素m并给计数器i赋初值i = 0
- 对于输入队列中每一个元素x:
- 若i = 0, 那么 m = x and i = 1
- 否则若m = x, 那么 i = i + 1
- 否则 i = i − 1
- 返回 m
举个栗子
输入 {1,2,1,3,1,1,2,1,5}
res = 0 count = 0
第1步:没有元素可以跟当前的结果抵消
当前值 curr 为 1,,count == 0 ,所以 res = curr(1),count++(1)
第2步:当前值 curr 为 2,当前值不等于 res,所以抵消掉当前结果,可以暂时不修改res 的结果
count != 0 && res != curr,所以 res 保持不变(1), count--(0)
第3步:当前值 curr 为 1,count == 0, 当前值不等于 res,所以抵消掉当前结果,可以暂时不修改res 的结果
count == 0,所以 res = curr(1), count++(1)
第4步:当前值 curr 为 3, count != 0 && res != curr, 所以 res 保持不变(1), count--(0)
第5步:当前值 curr 为 1, count == 0, 所以 res = 1, count++(1)
第6步:当前值 curr 为 1, count == 0 ,所以 res = curr(1),count++(2)
第7步:当前值 curr 为 2, count != 0 && res != curr, 所以 res 保持不变(1),count--(1)
第8步:当前值 curr 为 1, count == 0, 所以 res = curr(1),count++(2)
第9步:当前值 curr 为 5, count != 0 && res != curr, 所以 res 保持不变(1),count--(1)
超过 1/3 的 众数
package main
// @lc code=start
func majorityElement(nums []int) []int {
target := len(nums) / 3
cur1, cur2 := 0, 0
count1, count2 := 0, 0
for _, val := range nums {
if cur1 == val && count1 > 0 {
count1++
} else if cur2 == val && count2 > 0 {
count2++
} else if count1 == 0 {
cur1 = val
count1++
} else if count2 == 0 {
cur2 = val
count2++
} else {
count1--
count2--
}
}
count1, count2 = 0, 0
for _, val := range nums {
if val == cur1 {
count1++
} else if val == cur2 {
count2++
}
}
res := make([]int, 0)
if count1 > target {
res = append(res, cur1)
}
if count2 > target {
res = append(res, cur2)
}
return res
}