1057. Stack (30)

来源:互联网 发布:matlab简单编程实例pdf 编辑:程序博客网 时间:2024/05/22 10:50

Stack is one of the most fundamental data structures, which is based on the principle of Last In First Out (LIFO).  The basic operations include Push (inserting an element onto the top position) and Pop (deleting the top element).  Now you are supposed to implement a stack with an extra operation: PeekMedian -- return the median value of all the elements in the stack.  With N elements, the median value is defined to be the (N/2)-th smallest element if N is even, or ((N+1)/2)-th if N is odd.

Input Specification:

Each input file contains one test case.  For each case, the first line contains a positive integer N (<= 105).  Then N lines follow, each contains a command in one of the following 3 formats:

Push key
Pop
PeekMedian

where key is a positive integer no more than 105.

Output Specification:

For each Push command, insert key into the stack and output nothing.  For each Pop or PeekMedian command, print in a line the corresponding returned value.  If the command is invalid, print "Invalid" instead.

Sample Input:
17PopPeekMedianPush 3PeekMedianPush 2PeekMedianPush 1PeekMedianPopPopPush 5Push 4PeekMedianPopPopPopPop
Sample Output:
InvalidInvalid322124453Invalid

 思路:

题目除了正常的进栈和出栈操作外增加了获取中位数的操作, 获取中位数,我们有以下方法:

   (1):每次全部退栈,进行排序,太浪费时间,不可取。

   (2):题目告诉我们key不会超过10^5,我们可以想到用数组来标记,但不支持快速的统计操作。

                   因为同一个数可能出现多次。想到用一个array来记录长度,但是还是O(N)超时,后来上网查询,要用树状数组

   (3):然后将数组转为树状数组,可以快速的统计,再配上二分就OK了。

AC参考代码:

 

#include <iostream>#include <stdio.h>#include <string.h>#include <stack>using namespace std;const int Max_required = 100005;int tree_array[Max_required];inline int lowbit(int x){    return x&(-x);}void add(int x, int value)  //更新前n项和函数{    while (x < Max_required)    {        tree_array[x] += value;        x += lowbit(x);    }}int sum(int x)      //求前n项和函数{    int total = 0;    while (x > 0)    {        total += tree_array[x];        x -= lowbit(x);    }    return total;}int binary_find(int x)  //二分查找代码{    int low = 1, high = Max_required, mid;    while (low <= high)    {        mid = (low + high) >> 1;        int total = sum(mid);        if (total >= x)            high = mid - 1;        else if (total < x)            low = mid + 1;    }    return low;}int main(){    int n;    stack<int> st;    while (scanf("%d", &n) != EOF)    {        memset(tree_array, 0, sizeof(tree_array));        char ch[30];        while (n--)        {            scanf("%s", ch);            if (strcmp("Push", ch) == 0)            {                int pp;                scanf("%d", &pp);                st.push(pp);                add(pp, 1);            }            else if (strcmp("Pop", ch) == 0)            {                if (st.empty())                    printf("Invalid\n");                else                {                    printf("%d\n", st.top());                    add(st.top(), -1);                    st.pop();                }            }            else if (strcmp("PeekMedian", ch) == 0)            {                int len = st.size();                if (len == 0) {                    printf("Invalid\n");                    continue;                }                int res = -1;                if (len % 2 == 1)                    res = binary_find((len + 1) / 2);                else                    res = binary_find(len / 2);                printf("%d\n", res);            }        }    }    return 0;}

 

树状数组简单介绍:

假设数组a[1..n],那么查询a[1]+...+a[n]的时间是log级别的,而且是一个在线的数据结构,支持随时修改某个元素的值,复杂度也为log级别。

来观察这个图:

 

令这棵树的结点编号为C1,C2...Cn。令每个结点的值为这棵树的值的总和,那么容易发现:
C1 = A1
C2 = A1 + A2
C3 = A3
C4 = A1 + A2 + A3 + A4
C5 = A5
C6 = A5 + A6
C7 = A7
C8 = A1 + A2 + A3 + A4 + A5 + A6 + A7 + A8
...
C16 = A1 + A2 + A3 + A4 + A5 + A6 + A7 + A8 + A9 + A10 + A11 + A12 + A13 + A14 + A15 + A16
这里有一个有趣的性质:
设节点编号为x,那么这个节点管辖的区间为2^k(其中k为x二进制末尾0的个数)个元素。因为这个区间最后一个元素必然为Ax,
所以很明显:Cn = A(n – 2^k + 1) + ... + An
算这个2^k有一个快捷的办法,定义一个函数如下即可:

 

int lowbit(int x){return x&(-x);}

 

当想要查询一个SUM(n)(求a[n]的和),可以依据如下算法即可:
step1: 令sum = 0,转第二步;
step2: 假如n <= 0,算法结束,返回sum值,否则sum = sum + Cn,转第三步;
step3: 令n = n – lowbit(n),转第二步。
可以看出,这个算法就是将这一个个区间的和全部加起来。

0 0