Week1

这周刚开始讲了一点Divide-and-Conquer的算法,于是这周的作业就选择在LeetCode上找分治法相关的题目来做。

169.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.

这道题是难度为Easy的题目。看到这个题目我首先想到的(除去暴力算法)就是通过排序将相同的元素放在一起。由于这个题目的主元素出现次数一定大于n/2次,所以我想到的办法是排序后取最中间的元素(这个元素一定是主元素)。

想到这一点,程序就相当简单。复杂度为O(nlogn)。

//排序取中间数
#include<vector>
#include<algorithm>
using namespace std;

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

当然,这周学的是分治法。我用上面的方法通过了这道题之后再尝试着用分治法的思路去做这道题。长时间思考后无果,看了LeetCode里面的Solution,解法如下。注释是我自己加的。

//Didive-and-Conquer Solution
class Solution {
public:
    int majorityElement(vector<int>& nums) {
        return majority(nums, 0, nums.size() - 1);
    }
private:
	// left为最左端元素,right为最右端元素,mid为中间元素
	// 返回条件为最左端元素等于最右端元素
	// 将问题分为两半递归下去
	// 
    int majority(vector<int>& nums, int left, int right) { 
        if (left == right) return nums[left];
        int mid = left + ((right - left) >> 1);
        int lm = majority(nums, left, mid);
        int rm = majority(nums, mid + 1, right);
        if (lm == rm) return lm;
		// 关键 —— 合并结果
        return count(nums.begin() + left, nums.begin() + right + 1, lm) > count(nums.begin() + left, nums.begin() + right + 1, rm) ? lm : rm;
    }
};

那除了分治法以外,我还看到了一些十分有意思的解法——

一个是随机算法,随机生成一个index,然后遍历这个数组,统计这个index下的元素在数组里的出现次数,如果超过n/2就确认是主元素。这是一个不稳定的O(n)的算法。

class Solution {
public:
    int majorityElement(vector<int>& nums) {
        int n = nums.size();
        srand(unsigned(time(NULL)));
        while (true) {
            int idx = rand() % n;
            int candidate = nums[idx];
            int counts = 0; 
            for (int i = 0; i < n; i++)
                if (nums[i] == candidate)
                    counts++; 
            if (counts > n / 2) return candidate;
        }
    }
};

我看到的另一个有趣的解法是用栈的方法来遍历数组:当栈为空时,压入一个元素;当栈不为空时,当前元素跟栈内元素进行比较,如果相同则压入栈内,如果不同则将栈内元素弹出(当前元素不压栈)。当遍历完整个数组后,栈内剩下的元素一定会是主元素。

public class Solution {
    public int majorityElement(int[] num) {

        int major=num[0], count = 1;
        for(int i=1; i<num.length;i++){
            if(count==0){
                count++;
                major=num[i];
            }else if(major==num[i]){
                count++;
            }else count--;
            
        }
        return major;
    }
}
原文地址:https://www.cnblogs.com/JerryChan31/p/7502628.html