LeetCode 169.多数元素

134 阅读2分钟

Offer 驾到,掘友接招!我正在参与2022春招系列活动-刷题打卡任务,点击查看活动详情

题目:给定一个长度为n的数组,找到其中的多数元素。多数元素指的是在数组中出现次数大于数组长度/2的那些数字。要求时间复杂度为O(n)O(n), 空间复杂度为O(1)O(1)

例如:

​ 输入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];
    }

上述算法的时间复杂度为O(n)O(n),空间复杂度为O(n)O(n)

题目要求时间复杂度为O(1)O(1),且看另一种思路:

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;
 }

该算法的时间复杂度为O(n)O(n), 空间复杂度为O(1)O(1)