题目来源:

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.

Credits:
Special thanks to @ts for adding this problem and creating all test cases.

这道题在剑指offer上见到过,使用一次遍历的方式就可以求解。做完以后看了下Discuss,发现还有好多种解法。主要有下面这么多种,图片来自于这里

我针对其中的5种进行了实现,第1种由于时间复杂度太高没有实现,第4种由于存在最差的情况所以也没有实现。


解法一:Hash table

这种解法是使用一个hash表,键用来存放数组的元素,键对应的值存放元素出现的次数。遍历整个数组,查找它在hash表中是否出现,如果出现将出现次数加1,如果没有出现,将它插入hash表中,并设置它的出现次数为1。每次遍历到一个元素,判断它的出现次数是否超过了数组长度的一半,要是超过了就返回该元素。时间复杂度是O(n),空间复杂度是O(n)。。 
runtime:48ms

     int majorityElement(vector<int>& nums) {
if(nums.size()==1)
return nums[0];
map<int,int> tables;
for(int i=0;i<nums.size();i++)
{
if(tables.count(nums[i]))
{
tables[nums[i]]++;
if(tables[nums[i]]>nums.size()/2)
return nums[i];
}
else
{
tables[nums[i]]=1;
}
} }

解法二:Sorting

这种解法其实应该一开始就想到的,因为这种解法可以说是最简单的。对数组进行排序,那么出现次数超过一半的元素必定是数组中的中间元素,返回这个元素即可。时间复杂度是O(nlogn),空间复杂度是O(1)。 
runtime:40ms

class Solution{
int majorityElement(vector<int>&num){
sort(num.begin(),num.end());
return num(nums.size()/);
}
};

解法三:Divide and conquer

这道题的提示是使用分治法或位操作来求解,最开始我思考时也是把数组分成分成两部分,但是在原始数组中出现次数超过一半的元素不一定在子数组中出现次数超过一半,到这里就不知道如果进行后续的操作了。看了上面的解释发现正确的思考方法应该是这样的: 
将数组分成两部分,寻找第一个部分中出现次数超过一半的元素为A,第二个部分出现次数超过一半的元素为B,如果A==B,那么A就是这个数组中出现次数超过一半的元素,如果A!=B,那么A和B都可能是这个数组中出现次数超过一半的元素,那么重新遍历这个数组,记录A和B出现的次数,返回出现次数多的元素,时间复杂度T(n)=2T(n/2)+2n=O(nlogn)。

runtime:20ms

int majorityElement(vector<int>& nums) {

         return helper(nums,,nums.size()-);
} int helper(vector<int> &nums,int begin,int end)
{
if(begin==end)
return nums[begin];
if(begin<end)
{
int mid=begin+(end-begin)/;
int left=helper(nums,begin,mid);
int right=helper(nums,mid+,end);
if(left==right)
return left;
else
{
int leftCount=;
int rightCount=;
for(int i=begin;i<=end;i++)
{
if(nums[i]==left)
leftCount++;
else if(nums[i]==right)
rightCount++;
} if(leftCount<rightCount)
return right;
else if(leftCount>rightCount)
return left;
}
}
}

解法四:Moore voting alogrithm

这种解法就是在《剑指offer》上看到的那种解法。它本质上也是一种分治法,只不过在编程时使用了一些技巧,结果没那么容易看出来了。 
算法的思想如下:每次从数组中找出一对不同的元素,将它们从数组中删除,直到遍历完整个数组。由于这道题已经说明一定存在一个出现次数超过一半的元素,所以遍历完数组后数组中一定会存在至少一个元素。 
上面就是这种算法的思想,删除操作可以在常数时间内完成,但是查找不同的元素无法在常数时间内完成,这里有一个技巧。 
在算法执行过程中,使用常量空间来记录一个候选元素c以及它的出现次数f(c),c即为当前阶段出现次数超过一半的元素。在遍历开始之前,该元素c为空,f(c)=0。然后开始遍历数组A时:

  1. 如果f(c)为0,表示当前并没有候选元素,也就是说之前的遍历过程中没有找到超过一半的元素。那么,如果超过一半的元素c存在,那么c在剩下的子数组中,出现的次数也一定超过一半。因次我们可以将原始问题转化成它的子问题。此时c赋值为当前元素,同时f(c)=1。
  2. 如果当前A[i]==c,那么f(c)+=1。(没有找到相同的元素,只需要把相同的元素累加起来)
  3. 如果当前元素A[i]!=c,那么f(c)-=1(相当于删除一个c),不对A[i]做任何处理(相当于删除A[i]) 
    如果遍历结束之后,f(c)不为0,那么再次遍历一遍数组,如果c真正出现的频率,上面算法的时间复杂度是O(n),空间复杂度为O(1)。这种方法的分析来自这里

runtime:20ms

   int majorityElement(vector<int>& nums) {
int count=;
int result=nums[];
for(int i=;i<nums.size();i++)
{
if(count==||nums[i]==result)
{
count++;
result=nums[i];
}
else
count--;
}
return result;
}

解法五:Bit manipulation

还可以使用位操作来求解这道题。因为一个整数在32为机器上只有32位,那么可以使用一个长度为32的数组来记录输入数组中每1位中1的个数和0的个数,由于存在一个出现次数超过一半的元素,那么取第i位中出现次数多的(0或者1)即可以构成超过数组一半元素。 
runtime:40ms

int majorityElement(vector<int>& nums) {
int **table=new int*[];
int result=;
for(int i=;i<;i++)
{
table[i]=new int[]();
}
for(int i=;i<nums.size();i++)
{
for(int j=;j<;j++)
{
int pos=<<j&nums[i]?:;
table[j][pos]++;
}
}
for(int i=;i<;i++)
{
if(table[i][]>table[i][])
result+=<<i;
}
return result;
}

LeetCode169:Majority Element(Hash表\位操作未懂)的更多相关文章

  1. LeetCode169 Majority Element, LintCode47 Majority Number II, LeetCode229 Majority Element II, LintCode48 Majority Number III

    LeetCode169. Majority Element Given an array of size n, find the majority element. The majority elem ...

  2. leetcode169——Majority Element (C++)

    Given an array of size n, find the majority element. The majority element is the element that appear ...

  3. [LeetCode169]Majority Element求一个数组中出现次数大于n/2的数

    题目: Given an array of size n, find the majority element. The majority element is the element that ap ...

  4. [LeetCode169]Majority Element

    Majority Element Total Accepted: 58500 Total Submissions: 163658My Submissions Question Solution  Gi ...

  5. [Swift]LeetCode169. 求众数 | Majority Element

    Given an array of size n, find the majority element. The majority element is the element that appear ...

  6. [LeetCode] Majority Element 求众数

    Given an array of size n, find the majority element. The majority element is the element that appear ...

  7. [LeetCode] Majority Element 求大多数

    Given an array of size n, find the majority element. The majority element is the element that appear ...

  8. PHP数组/Hash表的实现/操作、PHP变量内核实现、PHP常量内核实现 - [ PHP内核学习 ]

    catalogue . PHP Hash表 . PHP数组定义 . PHP变量实现 . PHP常量实现 1. PHP Hash表 0x1: 基本概念 哈希表在实践中使用的非常广泛,例如编译器通常会维护 ...

  9. Hash表的扩容(转载)

    Hash表(Hash Table)   hash表实际上由size个的桶组成一个桶数组table[0...size-1] . 当一个对象经过哈希之后.得到一个对应的value , 于是我们把这个对象放 ...

随机推荐

  1. WCF跨域解决方法及一些零碎的东西。

    之前发过一篇随笔,说的WCF配置文件配置问题.里面也配了跨域支持,但是jsoncollback只支持Get请求,Post请求是解决不了,所以这里把真正的WCF跨域问题贴出来. 话不多说,直接帖配置文件 ...

  2. C语言作业第二次总结

    1.作业亮点 1.1作业整体概况 本次作业全体同学能够按时完成作业,且大部分同学的作业体现了自己的思路和方法,具备了一定变成能力. 1.2推荐博客 林岳-代码注释清晰,详细.->博文 王艺斌-算 ...

  3. OVS常用命令

    添加brideg: sudo ovs-vsctl add-br br0 删除brideg: sudo ovs-vsctl del-br br0 显示bridge: sudo ovs-vsctl sho ...

  4. Markdown文本测试

    一级标题 二级标题 三级标题 四级标题 五级标题 六级标题 1. 这是一 2. 这是二 这是无序符号 My Github 这是着重表示 这是斜体 一级粗体 二级斜体 cin >> a; c ...

  5. PYTHON 词云

    #!/usr/bin/env python # -*- coding:utf-8 -*- import matplotlib.pyplot as plt from wordcloud import W ...

  6. JFinal项目发送邮件——jfinal-mail-plugin

    JFianl框架: JFinal 是基于 Java 语言的极速 WEB + ORM 框架,其核心设计目标是开发迅速.代码量少.学习简单.功能强大.轻量级.易扩展.Restful.在拥有Java语言所有 ...

  7. 14-TypeScript简单工厂模式

    在TypeScript中,要调用功能,通常在调用方通过实例化被调用方对象来调用相关方法,但这种实现在调用方和被调用方形成了强耦合的关系. 另外如果被调用方有种实现,在调用方需要根据场景去实例化不同的类 ...

  8. CDH:5.14.0 中 Hive BUG记录

    CDH5.14.0使用的HIVE版本: 自建表log: +----------------------------------------------------+--+ | createtab_st ...

  9. ll的命令后面的字段详解

    linux学习 命令ll后字段的解释 分类:linux | 标签: 命令ll后字段的解释  2010-10-25 15:47阅读(4513)评论(0) ls -l 列表信息详解 我们平时用ls -l ...

  10. @SpringBootApplication 组合注解包含哪些注解及作用

    序:在学习springboot,教程一般对一些注解语焉不详,发现@SpringBootApplication 这个注解包含了很多注解,也就是说使用这个注解可以少写几个注解,这里看源码粘出来一些,仅用于 ...