zoukankan      html  css  js  c++  java
  • 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
    ", 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;
        }
  • 相关阅读:
    「题解」:毛一琛/$cow$ $subsets$
    「题解」:$e$
    「题解」:$d$
    「题解」:$Simple$
    「题解」:$Game$
    「题解」:砖块
    「题解」:天才绅士少女助手克里斯蒂娜
    约瑟夫问题小结
    「题解」:[loj2763][JOI2013]现代豪宅
    20190812
  • 原文地址:https://www.cnblogs.com/kingxiaozi/p/10546804.html
Copyright © 2011-2022 走看看