Majority Element && Majority Element II

Majority Element

https://leetcode.com/problems/majority-element/

Difficulty: Easy

查找数组的多数元素(majority element)

多数元素为数组中出现次数多于?n/2?的元素。假设数组非空且多数元素一定存在

LeetCode的解答中给出了七种思路

第一种是Brute force solution,时间复杂度为O(n2),顾名思义,遍历数组,依次判断每个元素是否为多数元素

第二种是Hash table,时间复杂度为O(n),空间复杂度也为(n),对数组中的每个元素计数,大于?n/2?时即为所求结果

第三种是Sorting,时间复杂度为O(nlogn),找到第n/2个元素即可

第四种是Randomization,平均时间复杂度为O(n),最坏情况为无穷大。随机选一个元素,判断其是否为多数元素。由于选中多数元素的概率大于1/2,尝试次数的期望<2

// Runtime: 20 ms
#include <cstdlib>
class Solution {
public:
    int majorityElement(vector<int>& nums) {
        int size = nums.size();
        while (true) {
            int r = nums[rand() % size];
            int count = 0;
            for (int i = 0; i < size; i++) {
                if (r == nums[i]) {
                    count++;
                }
            }
            if (count > size >> 1) {
                return r;
            }
        }
    }
};

第五种是Divide and conquer,时间复杂度为O(nlogn),将数组分成两半,分别递归查找这两部分的多数元素,若两者相同,则为多数元素,若不同,则其中之一必为多数元素,判断其一即可

第六种是Moore voting algorithm,时间复杂度为O(n),这个算法可能是最为巧妙的一种方法了吧。维护一个candidate和一个counter,counter初始化为0,之后遍历整个数组,如果counter为0,则 candidate 设置为当前元素,并且 counter 设置为 1,如果 counter 不为 0,根据当前元素是否为 candidate 来递增或递减 counter。若数组非空,实际中,也可以直接把 candidate 赋值为数组的第一个元素。参考Majority Element II,把 candidate 设置为任意值,并且 counter 设为 0 是最自然的一种思路了。可能这个算法的全称是这个吧。Boyer-Moore Majority Vote Algorithm

// Runtime: 16 ms
class Solution {
public:
    int majorityElement(vector<int>& nums) {
        int maj = nums[0], count = 1;
        for (int i = 1; i < nums.size(); i++) {
            if (count == 0) {
                maj = nums[i];
                count++;
            }
            else if (maj == nums[i]) {
                count++;
            }
            else {
                count--;
            }
        }
        return maj;
    }
};

第七种是Bit manipulation,时间复杂度为O(n),需要32个计数器,每个计数器记录所有数组某一位的 1 的数目,由于多数元素一定存在,那么 1 的数目和 0 的数目必然不同,多者即为多数元素那一位的取值

Majority Element II

https://leetcode.com/problems/majority-element-ii/

Difficulty: Medium

查找数组中出现次数多于?n/3?的元素

类似于 Majority Element 中的第六种算法Boyer-Moore Majority Vote Algorithm,由于最多有两个可能的元素,所以我们使用两个 candidate,每个 candidate 对应一个 counter。Majority Element 中若两个元素不同,则去除这两个元素并不影响剩余数组的多数元素。类似的,在本题中,如果去除三个不同的元素,并不影响剩余数组的出现次数多于?n/3?的元素。先判断当前元素是否与 candidate 相匹配,若不匹配,则判断是否要更新 candidate,若也不需要更新,则已经获取了三个不同的元素,即当前元素和两个 candidate,去除的方式是两个 counter 同时减一。

需要注意的是,循环中判断的顺序很重要,需要先判断当前元素是否与两个 candidate 之一相匹配,若均不匹配,再判断 counter。这就需要考虑,最初的 candidate 需要如何确定。即便数组的长度大于等于2,依旧不能类似 Majority Element 那样,使用数组的前两个元素作为两个 candidate,因为数组的前两个元素可能是相同的。其实解决办法也很简单,只要给两个 candidate 赋予不同的初值,并且两个 counter 的初值均为 0 即可。

如果先判断 counter,则有可能出现两个 candidate 相同的情况。如测试用例[2,2],[?1,1,1,1,2,1]

class Solution {
public:
    vector<int> majorityElement(vector<int>& nums) {
        vector<int> ret;
        int n1 = 0, n2 = 1, count1 = 0, count2 = 0;
        for (auto n: nums) {
            if (n == n1) {
                count1++;
            } else if (n == n2) {
                count2++;
            } else if (count1 == 0) {
                n1 = n;
                count1 = 1;
            } else if (count2 == 0) {
                n2 = n;
                count2 = 1;
            } else {
                count1--;
                count2--;
            }
        }
        if (count1 != 0 && validateME(nums, n1)) {
            ret.push_back(n1);
        }
        if (count2 != 0 && validateME(nums, n2)) {
            ret.push_back(n2);
        }
        return ret;
    }
    bool validateME(vector<int>& nums, int val) {
        int count = 0;
        for (auto n: nums) {
            if (n == val) {
                count++;
            }
        }
        if (count > nums.size() / 3) {
            return true;
        } else {
            return false;
        }
    }
};

扩展

Boyer-Moore Majority Vote Algorithm 中给出了两个扩展,一是使用更少的比较次数,一是如何并行执行这个算法

Fewer Comparisons

在不确定多数元素是否存在的情况下,使用 Boyer-Moore 算法找到的 candidate 还需要遍历一次数组对其出现次数进行计数。在最坏情况下需要比较2N次(出现n/2+1次时停止即可,所以是最坏情况)。这部分的算法只需要3N/2?2次比较,但是需要额外的空间(N)。

核心思想是重新排列元素确保相邻元素不同。

第一遍,维护一个空的 rearranged list 和一个空的 bucket。遍历数组,并与 list 的最后一个元素相比,若相同,则把该元素放入 bucket 中,若不同,则放入 list 中,然后取 bucket 的一个元素也放入 list 中。遍历完成后,list 的最后一个元素即为备选的 candidate

第二遍,一次用 list 的最后一个元素与 candidate 比较,若相同,则删除 list 的最后两个元素,若不同,则删除 list 的最后一个元素和 bucket 中的一个元素。如果移除了 list 的所有元素并且 bucket 不空,则 candidate 是多数元素。(很多边界条件需要考虑,但大体思想如此。举一个实际的例子基本就理解了这个算法。比如 5 5 0 0 5,最后 list 剩余 5,而 bucket 为空,这也算是 candidate 为多数元素的一种情况)

举个例子,5(1) 5 (2) 0(1) 0(2) 0(3) 5(3) 0(4) 0(5) 5(4),这里只给出第一遍遍历的情况,第二遍按照思想,很容易走通

iterator list bucket
1 5(1)
2 5(1) 5(2)
3 5(1) 0(1) 5(2)
4 5(1) 0(1) 5(2) 0(2)
5 5(1) 0(1) 5(2) 0(2) 0(3)
6 5(1) 0(1) 5(2) 0(2) 5(3) 0(3)
7 5(1) 0(1) 5(2) 0(2) 5(3) 0(3) 0(4)
8 5(1) 0(1) 5(2) 0(2) 5(3) 0(3) 0(4) 0(5)
9 5(1) 0(1) 5(2) 0(2) 5(3) 0(3) 5(4) 0(4) 0(5)

Distributed Boyer-Moore

保留每个处理结果的 candidate 和 counter,对所有的结果再执行一次 Boyer-Moore 算法。需要注意的是,这次不是单纯的增减一了,而是根据需要比较元素的 counter 来进行处理。这里的代码引自原文,虽然是用 Python 写的,但是一目了然。

candidate = 0
count = 0
for candidate_i, count_i in parallel_output:
  if candidate_i = candidate
    count += count_i
  else if count_i > count:
    count = count_i - count
    candidate = candidate_i
  else
    count = count - count_i

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-06 17:14:26

Majority Element && Majority Element II的相关文章

Eclipse运行自动化脚本报错: invalid element state: Element is not currently interactable and may not be manipulated

Exception in thread "main" org.openqa.selenium.InvalidElementStateException: invalid element state: Element is not currently interactable and may not be manipulated 这是在异步取数据的时候取不到,只需要加一个延时就好了 Thread.sleep(2000);

stale element reference: element is not attached to the page document 异常

在执行脚本时,有时候引用一些元素对象会抛出如下异常 org.openqa.selenium.StaleElementReferenceException: stale element reference: element is not attached to the page document 按字面表达的意思大概是,所引用的元素已过时,不再依附于当前页面.通常情况下,这是因为页面进行了刷新或跳转,解决方法是,重新使用 findElement 或 findElements 方法进行元素定位即可.

Raphael.js API 之Element.remove(),Element.removeData(),paper.text(),Element.node(),Element.onDragOver

/*API-38*/ Element.remove() 删除某个元素对象,无返回值 /*API-39*/ Element.removeData([key]); 删除某个key的value值,如果没有特殊说明则删除所有的元素数据 参数列表: key 可选参数 字符串类型 key 返回值:元素对象 /*API-105*/ 在画布上添加一个字符串,如果需要换行,使用'\n' 参数列表: x number类型 x轴坐标位置 y number类型 y轴坐标 text 字符串类型 文本内容 返回值:type

关于报错stale element reference: element is not attached to the page document处理

1.现象 在执行脚本时,有时候引用一些元素对象会抛出如下异常 org.openqa.selenium.StaleElementReferenceException: stale element reference: element is not attached to the page document 2.报错原因 官方给出解释如下: The element has been deleted entirely.The element is no longer attached to the D

关于报错stale element reference: element is not attach

1.现象 在执行脚本时,有时候引用一些元素对象会抛出如下异常 org.openqa.selenium.StaleElementReferenceException: stale element reference: element is not attached to the page document 2.报错原因 官方给出解释如下: The element has been deleted entirely.The element is no longer attached to the D

Leetcode # 169, 229 Majority Element I and II

Given an array of size n, find the majority element. The majority element is the element that appears more than ? n/2 ? times. You may assume that the array is non-empty and the majority element always exist in the array. 这一题可以用排序之后查看序列正中间那个元素的方法来解.但

stale element reference: element is not attached to the page document

//should set firefox path //FirefoxBinary binary=new FirefoxBinary(new File("C:\\Program Files (x86)\\Mozilla Firefox\\firefox.exe")); //FirefoxProfile profile = null; System.setProperty("webdriver.chrome.driver", "e:\\chromedrive

LeetCode(7): Majority Element

Majority Element: Given an array of size n, find the majority element. The majority element is the element that appears more than ⌊ n/2 ⌋ times.You may assume that the array is non-empty and the majority element always exist in the array. 题意:找出给定数组中的

Majority Element:主元素

Given an array of size n, find the majority element. The majority element is the element that appears more than ? n/2 ? times. You may assume that the array is non-empty and the majority element always exist in the array. 求主元素:包含n个元素的数组中,如果一个元素的出现次数大