这道题虽然简单,但适合用来练习各种解法。《剑指offer》5.2节 面试题29与此题一样,并且给出了leetcode官方题解未给出的快速选择的解法。
方法一、用哈希表解决
cpp
class Solution {
public:
int majorityElement(vector<int>& nums) {
unordered_map<int,int> count;
int majority = 0;
int cnt = 0;
for(auto num:nums){
count[num]++;
if(count[num] > cnt){
cnt = count[num];
majority = num;
}
}
return majority;
}
};
方法二、先排序再取nums[n/2]
cpp
class Solution {
public:
int majorityElement(vector<int>& nums) {
int len = nums.size();
srand(time(0));
quick_sort(nums,0,len-1);
return nums[len/2];
}
int partition(vector<int>& nums,int left,int right){
if(left >= right)
return left;
int random = rand()%(right - left +1);
swap(nums[left],nums[left + random]);
int pivot = nums[left];
while(left < right){
while(left<right && pivot < nums[right]) right--;
nums[left] = nums[right];
while(left<right && nums[left]<=pivot) left++;
nums[right] = nums[left];
}
nums[left] = pivot;
return left;
}
void quick_sort(vector<int>& nums,int left,int right){
if(left>=right) return;
int pivot_pos = partition(nums,left,right);
quick_sort(nums,left,pivot_pos-1);
quick_sort(nums,pivot_pos+1,right);
}
};
方法三、快速选择
由于方法二可知,问题等价于求数组排好序后的第n/2个元素。那么由快速排序算法的思想,其实不用把整个数组排序结束,就可以找到排好序后的第n/2个元素,也就是快速选择算法。
这种解法,leetcode官方没有给出。
cpp
class Solution {
public:
int majorityElement(vector<int>& nums) {
srand(time(0));
return quick_select(nums,0,nums.size()-1,nums.size()/2);
}
int partition(vector<int>& nums,int left,int right){
if(left >= right) return left;
int random_pos = left + rand()%(right - left +1);
swap(nums[left],nums[random_pos]);
int pivot = nums[left];
while(left<right){
while(left<right && pivot <= nums[right]) right--;
nums[left] = nums[right];
while(left<right && nums[left] < pivot) left++;
nums[right] = nums[left];
}
nums[left] = pivot;
return left;
}
int quick_select(vector<int>& nums,int left,int right,int k){
if(left>=right) return nums[left];
int pivot_pos = partition(nums,left,right);
if(pivot_pos == k)
return nums[pivot_pos];
else if(pivot_pos > k)
return quick_select(nums,left,pivot_pos-1,k);
else
return quick_select(nums,pivot_pos+1,right,k);
}
};
方法四、随机化方法
cpp
class Solution {
public:
int majorityElement(vector<int>& nums) {
srand(0);
int len = nums.size();
int random = 0;
int cnt = 0;
while(true){
random = rand()%len;
cnt = 0;
for(auto num:nums){
if(num == nums[random]){
cnt++;
if(cnt >len/2)
return num;
}
}
}
}
};
方法五、分治法
cpp
class Solution {
public:
int majorityElement(vector<int>& nums) {
return divide_conquer(nums,0,nums.size()-1);
}
int divide_conquer(vector<int>& nums,int left,int right){
if(left>=right)
return nums[left];
int mid = left + (right - left)/2;
int majorityLeft = divide_conquer(nums,left,mid);
int majorityRight = divide_conquer(nums,mid+1,right);
if(majorityLeft == majorityRight)
return majorityLeft;
int cnt = 0;
for(int i = left;i <= right;i++){
if(nums[i] == majorityLeft){
cnt++;
if(cnt > (right - left +1)/2)
return majorityLeft;
}
}
return majorityRight;
}
};
方法六、Boyer-Moore投票法
《剑指offer》5.2节也给出了这种解法
cpp
class Solution {
public:
int majorityElement(vector<int>& nums) {
int candidate = nums[0];
int count = 1;
for(int i = 1;i < nums.size();i++){
if(nums[i] == candidate){
count++;
}else{
count--;
if(count == 0)
{
candidate = nums[i];
count = 1;
}
}
}
return candidate;
}
};