Offer 驾到,掘友接招!我正在参与2022春招系列活动-刷题打卡任务,点击查看活动详情。
题目:给定一个长度为n的数组,找到其中的多数元素。多数元素指的是在数组中出现次数大于数组长度/2的那些数字。要求时间复杂度为, 空间复杂度为。
例如:
输入nums=[3,2,3],输出为3。
输入nums=[2,2,1,1,1,2,2],输出为2。
解题思路
如果一个数在数组中出现的次数超过数组长度/2,那么如果对数组进行排序,此时数组的第数组长度/2个元素必然是那个多数元素,可得代码如下:
public int majorityElement(int[] nums) {
Arrays.sort(nums);
return nums[nums.length/2];
}
此时算法的时间复杂度就取决于排序的方式。
换个思路,对于数组中的每个元素,我们可以计算每个元素出现的次数,因为题目保证总会有符合条件的数,因此我们可以对每个元素的次数进行判断,如果某个元素的次数大于数组长度/2,则此元素就是符合条件的元素,此时直接返回即可。
计算每个元素的次数我们可以使用HashMap,如果map中包含此元素,则先将元素对应的值加一,之后直接判断元素的长度是否大于数组的长度/2。上面的思路还可以进一步优化,我们可以在第一次循环中先判断map的键,如果键存在则直接判断当前键对应的值是否大于数组的长度/2,如果大于则可以直接返回改键,代码结束。
根据上述思路,可得代码如下:
public int majorityElement(int[] nums) {
HashMap<Integer, Integer> map = new HashMap<>();
for(int i=0;i<nums.length;i++){
if(map.containsKey(nums[i])){
map.put(nums[i], map.get(nums[i]) + 1);
if(map.get(nums[i])>nums.length/2){
return nums[i];
}
}else {
map.put(nums[i], 1);
}
}
return nums[0];
}
上述算法的时间复杂度为,空间复杂度为。
题目要求时间复杂度为,且看另一种思路:
Boyer-Moore 投票算法
另一种思路是投票法,用一个元素temp记录当前较多的元素,元素个数为count,如果当前元素和temp一致,则count自增,否则自减。如果当前count为0,则重置temp。可得如下代码:
public int majorityElement(int[] nums) {
int count = 0;
int temp = Integer.MAX_VALUE;
for(int i=0;i<nums.length;i++){
if(count==0){
temp = nums[i];
count++;
continue;
}
if(nums[i]!=temp){
count--;
}else{
count++;
}
}
return temp;
}
该算法的时间复杂度为, 空间复杂度为。