229. Majority Element II (M)

Given an integer array of size n, find all elements that appear more than ⌊ n/3 ⌋ times.

Follow-up: Could you solve the problem in linear time and in O(1) space?

Example 1:

Input: nums = [3,2,3]
Output: [3]
Example 2:

Input: nums = [1]
Output: [1]
Example 3:

Input: nums = [1,2]
Output: [1,2]

Constraints:

1 <= nums.length <= 5 * 104
-109 <= nums[i] <= 109


我的答案:时间、空间复杂度O(n)

class Solution {
public:
    vector<int> majorityElement(vector<int>& nums) {
        int length = nums.size();
        
        unordered_map<int, int> count;
        unordered_set<int> screen_out;
        
        for (const auto& n:nums) {
            if (screen_out.find(n) == screen_out.end()) {
                if (count.find(n) == count.end()) {
                    count[n] = 1;
                }
                else {
                    ++count[n];
                }
                if (count[n] > length/3) {
                    screen_out.insert(n);
                }
            }
        }
        
        vector<int> ans(screen_out.begin(), screen_out.end());
        return ans;
    }
};

Runtime: 40 ms, faster than 26.49% of C++ online submissions for Majority Element II.
Memory Usage: 16.5 MB, less than 7.86% of C++ online submissions for Majority Element II.

有点慢

看答案:
https://zxi.mytechroad.com/blog/algorithms/array/leetcode-229-majority-element-ii/

Solution: Boyer–Moore Voting Algorithm
Time complexity: O(n)
Space complexity: O(1)

class Solution {
public:
    vector<int> majorityElement(vector<int>& nums) {
        int length = nums.size();
        
        unordered_map<int, int> count;
        vector<int> ans;
        // ans.reserve(2);
        
        for (const auto& n:nums) {
            if (find(ans.begin(), ans.end(), n) == ans.end()) {
                if (count.find(n) == count.end()) {
                    count[n] = 1;
                }
                else {
                    ++count[n];
                }
                if (count[n] > length/3) {
                    ans.push_back(n);
                    if (ans.size() == 2) break;
                }
            }
        }
        
        return ans;
    }
};

Runtime: 32 ms, faster than 51.59% of C++ online submissions for Majority Element II.
Memory Usage: 16.3 MB, less than 7.86% of C++ online submissions for Majority Element II.

看了答案之后发现,最多有2个元素输出
做了点优化


答案Boyer-Moore算法:

// Author: Huahua
class Solution {
public:
  vector<int> majorityElement(vector<int>& nums) {
    int n1 = 0;
    int c1 = 0;
    int n2 = 1;
    int c2 = 0;
    for (int num : nums) {
      if (num == n1) {
        ++c1;
      } else if (num == n2) {
        ++c2;
      } else if (c1 == 0) {
        n1 = num;
        c1 = 1;
      } else if (c2 == 0) {
        n2 = num;
        c2 = 1;
      } else {
        --c1;
        --c2;
      }
    }
    
    c1 = c2 = 0;
    for (int num : nums) {
      if (num == n1) ++c1;
      else if (num == n2) ++c2;
    }
    
    const int c = nums.size() / 3;
    vector<int> ans;
    if (c1 > c) ans.push_back(n1);
    if (c2 > c) ans.push_back(n2);
    return ans;
  }
};

Runtime: 28 ms, faster than 76.28% of C++ online submissions for Majority Element II.
Memory Usage: 16.1 MB, less than 23.62% of C++ online submissions for Majority Element II.

问题:
为什么要重新计数?
https://www.youtube.com/watch?v=FGwCv6JAZQ8


实验了一下,果然出错了!主要是count可能会降到0,这时候有可能整个需要,有可能不需要

然后上面的代码其实有点tricky,n1和n2需要初始化,但是要初始化成两个不一样的数字,类似前面都搜索过一段了,但是刚好两个counter都清零的结果。否则如果n1=n2=0,然后输入都是0,那么第二个for循环的第二个if就得是else if,这样也行。

最后是,第一个for loop里面if和else if的顺序,必须把n1和n2的判断放到最前面,否则

        for (const auto& n:nums){
            if (c1 == 0) {
                n1 = n;
                ++c1;
            }
            else if (c2 == 0) {
                n2 = n;
                ++c2;
            }
            else if (n == n1) ++c1;
            else if (n == n2) ++c2;
            else {
                --c1;
                --c2;
            }
        }

比如连续两个1输入,[1,1,...],那么第二个1就会把c2也占了,而且本身的计数也会少加了1


cout << n << ", " << n1 << ", " << c1 << ", " << n2 << ", " << c2 << endl;
错误结果:
1, 1, 1, 2147483647, 0
1, 1, 1, 1, 1
2, 1, 0, 1, 0 <~ “那么第二个1就会把c2也占了,而且本身的计数也会少加了1”
3, 3, 1, 1, 0
4, 3, 1, 4, 1
1, 3, 0, 4, 0
1, 1, 1, 4, 0
5, 1, 1, 5, 1
6, 1, 0, 5, 0
7, 7, 1, 5, 0
1, 7, 1, 1, 1
1, 7, 1, 1, 2
8, 7, 0, 1, 1
9, 9, 1, 1, 1
10, 9, 0, 1, 0
1, 1, 1, 1, 0
11, 1, 1, 11, 1
12, 1, 0, 11, 0
13, 13, 1, 11, 0
14, 13, 1, 14, 1
正确结果
1, 1, 1, 2147483647, 0
1, 1, 2, 2147483647, 0
2, 1, 2, 2, 1
3, 1, 1, 2, 0
4, 1, 1, 4, 1
1, 1, 2, 4, 1
1, 1, 3, 4, 1
5, 1, 2, 4, 0
6, 1, 2, 6, 1
7, 1, 1, 6, 0
1, 1, 2, 6, 0
1, 1, 3, 6, 0
8, 1, 3, 8, 1
9, 1, 2, 8, 0
10, 1, 2, 10, 1
1, 1, 3, 10, 1
11, 1, 2, 10, 0
12, 1, 2, 12, 1
13, 1, 1, 12, 0
14, 1, 1, 14, 1


回顾169. Majority Element

Boyer moore的写法是:

// https://zxi.mytechroad.com/blog/divide-and-conquer/leetcode-169-majority-element/
class Solution {
public:
    int majorityElement(vector<int>& nums) {
        int majority = nums.front();
        int count = 0;
        
        for (const int num : nums) {
            if (num == majority) ++count;
            else if (--count == 0) {
                count = 1;
                majority = num;
            }
        }
        
        return majority;
    }
};

这里的count判断和num不需要注意前后顺序,因为只有一个count

我自己的写的版本,过了测试

class Solution {
public:
    int majorityElement(vector<int>& nums) {
        int majority = nums.front();
        int count = 0;
        
        for (const int num : nums) {
            if (count == 0) {
                ++count;
                majority = num;
            }
            else if (num == majority) ++count;
            else --count;
        }
        
        return majority;
    }
};
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,732评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,496评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,264评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,807评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,806评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,675评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,029评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,683评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,704评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,666评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,773评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,413评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,016评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,204评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,083评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,503评论 2 343

推荐阅读更多精彩内容