题目
leetcode 169 求众数
给定一个大小为 n 的数组,找到其中的众数。众数是指在数组中出现次数大于 ⌊ n/2 ⌋ 的元素。
你可以假设数组是非空的,并且给定的数组总是存在众数。
总结
方法一:排序后取中位数
按照数组的特点,若一个数在数组中出现次数大于一半,则当给该数组排序后,该数字一定会出现在中间位置。
到了JDK7的时候JDK内置的排序算法已经由经典快排变成了Dual-Pivot排序算法。快速排序的时间复杂度为O(nlogn)。经典快排递归的时候把输入数组分两段,而Dual-Pivot则分三段。
class Solution {
public int majorityElement(int[] nums) {
Arrays.sort(nums);
// 当为奇数时,返回最中间数字;当为偶数时,返回偏右侧数字。
return nums[nums.length / 2];
}
}
方法二:基于数组特点的摩尔投票法
我们可以考虑在遍历数组的时候保存两个值:一个是数组中的一个数字;另一个是次数。当我们遍历到下一个数字的时候,如果count=0,说明从此个数字重新开始算,result需要更新为当前数字。如果count!=0,说明下一个数字如果相同,则count++,如果不同,则抵消一个,count–。
该方法只需要遍历一遍数组,故时间复杂度为O(n)。
class Solution {
public int majorityElement(int[] nums) {
int len = nums.length;
int result;
int count;
// 要考虑数组为空的情况
if (len == 0) {
return 0;
} else {
result = nums[0];
count = 1;
}
// 从第二个元素开始遍历
for(int i = 1; i<nums.length; i++){
if(count == 0){
result = nums[i];
count = 1;
}else if(nums[i] == result)
count++;
else
count--;
}
// 要考虑数组中不存在众数的情况
if (count > 0) {
return result;
}else {
return 0;
}
}
}
方法三:基于Partition函数的分治法
如果把这个数组排序,那么排序之后位于数组中间的数字一定就是那个出现次数超过数组长度一般的数字。即,我们只用找出长度为n的数组中第n/2大的数字。于是可以用快速排序的思想,找到第n/2大的数字。
该方法时间复杂度为O(n),空间复杂度为O(1),但是需要在原数组上进行改动。注:如果代码中加System.out
可能会在leetcode上超出时间限制。
class Solution {
public int majorityElement(int[] nums) {
// 我们的目的是找出排序在第mid的数
int len = nums.length;
int mid = len / 2;
if(len == 1) {
return nums[0];
}
int start = 0;
int end = len - 1;
int index = partition(nums, start, end);
while (index != mid) {
if (index > mid) {
end = index - 1;
index = partition(nums, start, end);
} else {
start = index + 1;
index = partition(nums, start, end);
}
}
return nums[mid];
}
// partition函数是为了找出nums[0]在排序中的第几个位置
public int partition(int[] nums, int start, int end) {
int i = start;
int j = end;
int pivot = nums[start];
if (i >= j) {
return i;
}
while (i < j) {
while (pivot <= nums[j] && i < j) {
j--;
}
while (pivot >= nums[i] && i < j) {
i++;
}
//如果满足条件则交换
if (i < j) {
int temp = nums[j];
nums[j] = nums[i];
nums[i] = temp;
}
}
nums[start] = nums[i];
nums[i] = pivot;
return i;
}
}
方法四:基于HashMap的统计
可以利用HashMap保存每对键值出现的次数。
这种方式的时间复杂度是O(n),空间复杂度也是O(n)。
class Solution {
public int majorityElement(int[] nums) {
int len = nums.length;
HashMap<Integer, Integer> map = new HashMap<>();
if (len == 1) {
return nums[0];
}
for(int i = 0; i < len; i++) {
if (!map.containsKey(nums[i])) {
map.put(nums[i], 1);
} else {
int count = map.get(nums[i]);
count++;
if (count > len/2) {
return nums[i];
} else {
map.put(nums[i], count);
}
}
}
return 0;
}
}