leetcode-求众数

题目:给定一个大小为 的数组,找到其中的众数。众数是指在数组中出现次数大于 ⌊ n/2 ⌋ 的元素。

    你可以假设数组是非空的,并且给定的数组总是存在众数。

示例 1:

输入: [3,2,3]
输出: 3

示例 2:

输入: [2,2,1,1,1,2,2]
输出: 2

首先了解一下什么是分治

维基百科

计算机科学中,分治法是建基于多项分支递归的一种很重要的算法范式。字面上的解释是“分而治之”,就是把一个复杂的问题分成两个或更多的相同或相似的子问题,直到最后子问题可以简单的直接求解,原问题的解即子问题的解的合并。

这个技巧是很多高效算法的基础,如排序算法快速排序归并排序)、傅立叶变换快速傅立叶变换)。

另一方面,理解及设计分治法算法的能力需要一定时间去掌握。正如以归纳法去证明一个理论,为了使递归能够推行,很多时候需要用一个较为概括或复杂的问题去取代原有问题。而且并没有一个系统性的方法去适当地概括问题。

分治法这个名称有时亦会用于将问题简化为只有一个细问题的算法,例如用于在已排序的列中查找其中一项的折半搜索算法(或是在数值分析中类似的勘根算法)。这些算法比一般的分治算法更能有效地运行。其中,假如算法使用尾部递归的话,便能转换成简单的循环。但在这广义之下,所有使用递归或循环的算法均被视作“分治算法”。因此,有些作者考虑“分治法”这个名称应只用于每个有最少两个子问题的算法。而只有一个子问题的曾被建议使用减治法这个名称。

分治算法通常以数学归纳法来验证。而它的计算成本则多数以解递归关系式来判定。

  • 第一种

集合(Map),实现。执行用时:46 ms

    public int majorityElement(int[] nums) {
        //  [n/2] 元素
        int majorityElement = nums.length / 2;
        // 创建一个集合
        Map<Integer, Integer> map = new HashMap();
        for (int num : nums) {
            // 思路:数组元素为key,出现次数为value。如果存在key,value+1,如果不存在key,第一次设置value 为1
            map.put(num, map.get(num) != null ? map.get(num).intValue() + 1 : 1);
        }
        for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
            // 出现次数和[n/2] 进行比较,大于,则返回(其实应该用一个集合来保存所有满足条件的众数,然后再返回)
            if (entry.getValue() > majorityElement) {
                return entry.getKey();
            }
        }
        return 0;
    }
  • 第二种

分治法 实现

// 用分治法求众数

#include <iostream>
#include <cstdio>

using namespace std;

// 本程序的关键。 以中间的数字为界限。 确定左右起始和终止界限
void split(int s[], int n, int &l, int &r)
{
    int mid = n/2;
    for(l=0; l<n; ++l)
    {
        if (s[l] == s[mid])
            break;
    }
    for(r=l+1; r<n; ++r)
    {
        if (s[r] != s[mid])
            break;
    }

}

// num 众数。 maxCnt 重数
void getMaxCnt(int &mid, int &maxCnt, int s[], int n)
{
    int l, r;
    split(s, n, l, r);  // 进行分割。这个函数是本程序的关键
    int num = n/2;
    int cnt = r-l;

    // update
    if (cnt > maxCnt)
    {
        maxCnt = cnt;
        mid = s[num];
    }

    // l 表示左边的个数。左边的个数必须大于 maxCnt 才有必要搜寻
    if (l+1 > maxCnt)
    {
        getMaxCnt(mid, maxCnt, s, l+1);
    }

    // 右边搜寻, 右边数组的起始地址要变更
    if (n-r > maxCnt)
    {
        getMaxCnt(mid, maxCnt, s+r, n-r);
    }
}

int main(void)
{
    int s[] = {1, 2, 2, 2, 3, 3, 5, 6, 6, 6, 6};
    int n = sizeof(s)/sizeof(s[0]);

    int maxCnt = 0;
    int num = 0;
    getMaxCnt(num, maxCnt, s, n);
    printf("%d %d\n", num, maxCnt);

    return 0;
}
  • 第三种

时间最快的  执行用时:7 ms

    public int majorityElement2(int[] nums) {
        int result = nums[0], count = 0;
        for (int i = 0; i < nums.length; i++) {
            if (count == 0) {
                result = nums[i];
                count++;
            } else if (result == nums[i]) {
                count++;
            } else {
                count--;
            }
        }
        return result;
    }

猜你喜欢

转载自www.cnblogs.com/kingxiaozi/p/10546804.html