分治算法--众数问题

Problem Description

给定含有n个元素的多重集合S,每个元素在S中出现的次数称为该元素的重数。多重集S中重数最大的元素称为众数。例如,S={1,2,2,2,3,5}。多重集S的众数是2,其重数为3。对于给定的由n 个自然数组成的多重集S,计算S的众数及其重数。如果出现多个众数,请输出最小的那个。

Input

输入数据的第1行是多重集S中元素个数n(n<1300000);接下来的n行中,每行有一个最多含有5位数字的自然数,。

Output

输出数据的第1行给出众数,第2行是重数。

Sample Input

6
1
2
2
2
3
5

Sample Output

2
3
思路:
首先需要排序。
每次先求中位数的重数,然后将数组从中位数(0-最左边的中位数和最右边的中位数到n)分开在左边和右边各求中位数的重数然后比较,然后再分开在比较。这样一直分最后就成了一个数字的重数(分成的最小问题)。
其实这样做已经能够在OJ AC。但是还可以进一步优化,当中位数的个数大于左侧或者右侧的时候可以不再向下求中位数的大小。换句话数就是当左侧或者右侧某一侧或者两侧的数字个数小于中位数的重数的时候就可以不必向下接着进行分析。
#include 
#include 
#include 

using namespace std;
int a[1300000+5];
void split(int &l, int &r, int a[], int n)
{
    int mid = n / 2;
    for(l = 0; l < n; l++)
    {
        if(a[mid] == a[l])
            break;
    }
    for(r = l + 1; r < n; r++)
    {
        if(a[mid] != a[r])
        {
            break;
        }
    }
}

void getmaxcnt(int &maxcnt, int &num, int a[], int n)
{
    int mid = n / 2;
    int l, r;
    int sum;
    split(l, r, a, n);
    sum = r - l;
    if(maxcnt < sum)
    {
        maxcnt = sum;
        num = a[mid];
    }
    if(maxcnt == sum)
    {
        if(num > a[mid])
        {
            num = a[mid];
        }
    }
    if(l + 1> maxcnt)
    {
        getmaxcnt(maxcnt, num, a, l);
    }
    if(n - r > maxcnt)
    {
        getmaxcnt(maxcnt, num, a + r, n - r);
    }
}

int main()
{
    int n, i;
    scanf("%d", &n);
    for(i = 0; i < n; i++)
        scanf("%d", &a[i]);
    sort(a, a+n);
    int maxcnt, num;
    maxcnt = 0;
    num = 0;
    getmaxcnt(maxcnt, num, a, n);
    printf("%d\n%d\n", num, maxcnt);
    return 0;
}

 

你可能感兴趣的:(分治算法,OJ)