1057. Stack (30)

102 篇文章 0 订阅
3 篇文章 0 订阅

1057. Stack (30)

时间限制
100 ms
内存限制
65536 kB
代码长度限制
16000 B
判题程序
Standard
作者
CHEN, Yue

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:
17
Pop
PeekMedian
Push 3
PeekMedian
Push 2
PeekMedian
Push 1
PeekMedian
Pop
Pop
Push 5
Push 4
PeekMedian
Pop
Pop
Pop
Pop
Sample Output:
Invalid
Invalid
3
2
2
1
2
4
4
5
3
Invalid

这题和以前做的mystack是一样,但是以前的算法结构的测试数据可能比较少,我当时的链表模式的通关了,这次我就学他们用的树状数组写的。然后还看到另一个是两个multiset(这个目前还没有用过,默认升序的好像是这样)的和stack(这里的也有用到,就是后进先出)的
输入N;接着N行命令,push进入一个,pop输出最后进一个数并让他出来,Peekmedian输出这些还在栈中的从小到大的中间的那个数,偶数个第N/2,奇数个(N+1)/2;

以前的链表的,在此处超时3个:http://xujiayu317.blog.163.com/blog/static/254752092014431105127155/
联动三种做法的,一种超时,一种和我下面的一样,最后一种http://blog.csdn.net/cstopcoder/article/details/24496853
联动树状数组http://duanple.blog.163.com/blog/static/7097176720081131113145832/

评测结果

时间结果得分题目语言用时(ms)内存(kB)用户
8月02日 17:22答案正确301057C++ (g++ 4.7.2)251332datrilla

测试点

测试点结果用时(ms)内存(kB)得分/满分
0答案正确163615/15
1答案正确2512045/5
2答案正确2511525/5
3答案正确2513323/3
4答案正确16922/2
  
#include<iostream>   
#include<stack> 
#define MAX 100001/*不多于100000_no more than 10^5.*/
using namespace std;   
/*htt p://duanple.blog.163.com/blog/static/7097176720081131113145832/*/
int lowBit_from_right_to_left_first_One(int key)
{
  return key&(-key);/*例子:比如二进制(key补码)000110  那么返回000010这个值是2;级别2=2^1;
                                            100011  那么返回000001这个值是1;级别1=2^0;
                                            101000  那么返回001000这个值是8;级别8=2^3;
                                            000000  那么返回000000这个值是0;级别0;
                      ------------------------------------
            等价于key&(key^(key-1));
            key不为零时最高能被2的k次方整除,结果就等于2^k;
            当key结果为零时,结果为零;
            ----------------------------------------------
            key&(-key) 一种情况key为零,结果为0;
            另一种情况假如key为正数,-key为负数在计算机中用补码表示
            (-key补=key的原从低位(右边向左),在没有遇到第一个1包括第一个1都保持不变,接下去直到符号位包括符号位全变反[1变0,0变1])
            --------------------------------------------------
            key&(key^(key-1)对于key与key-1的区别在于key减1的时候像高位借位,而借位的情况在二进制中当key的最低位为0,而要减去的是1,
            显然,会被借位的最高位【从低位(右边向左),在遇到的第一个1】,所以key和key-1在这个1的左边本身全一样,在1的右边包括1全不一样;
            key^(异或)key-1;按位异或,没有进位的加(同清零,不同置1),接着和原来的key按位与&没有进位的乘(1&1=1其他都为0)
            显然key和key^(key-1只有刚刚1的那个位置一样且都为1;
            */
}
void insertCountkey(int*Countkey,int key,int add_dec)
{
  while (key <= MAX)
  {
    Countkey[key] += add_dec;
    key += lowBit_from_right_to_left_first_One(key);
  }/*设key的级别为2^k实现Countkey[key] 增加一个add或减少一个dec
     接着对于级别大于2^k的第一个newkey实现Countkey[newkey]增加一个add标记或减少一个dec
     注释:这些大于2^k的newkey=2^(k+1);2^(k+2)……<=MAX;
          所以显然,只有Countkey[2^k]包含所有1<key<=2^k的数量
                      Countkey[2^k+1]=Countkey[2^k+1];只包含他自己即key=2^k+1的数量;
                      Countkey[2^k+2]=包含key=2^k+1和key=2^k+2的数量;
      结合下面的low_and_函数,假如此时
    low_and_(int*Countkey, int 2^k)那么直接获得sum+=Countkey[2^k],key=0;结束时sum=所有1<key<=2^k的数量
    low_and_(int*Countkey, int 2^k+1)那么会先sum+=Countkey[2^k+1],key=2^k;接着sum+=Countkey[2^k],key=0;结束时sum=所有1<key<=2^k+1的数量;
    low_and_(int*Countkey, int 2^k+2)那么会先sum+=Countkey[2^k+2],key=2^k;接着sum+=Countkey[2^k],key=0;结束时sum=所有1<key<=2^k+2的数量; 
  */
} 
int low_and_(int*Countkey, int key)
{
  int sum = 0;
  while (key > 0)
  {
    sum += Countkey[key];
    key -= lowBit_from_right_to_left_first_One(key);
  }
  return sum;/* 
         下面的2^k是不断变动的。
           如果这一key是n*2^k(n为奇数),那么会实现sum+和key-; 
           如果这一key已经是2^k,那么最后一次key-=lowBit_from_right_to_left_first_One;
                        (key=0;结束,由Binary indexed tree-树状数组 特性知道,此时的sum=Countkey[2^k]+……+Countkey[key最开始];
                
             */
}
int findmid(int*Countkey,int mid)
{
  int low = 0, high = MAX ;
  int midtemp,countSum;
  while (low <= high)
  {
    midtemp = (low + high) / 2;
    countSum = low_and_(Countkey, midtemp);
      if (countSum>= mid)high = midtemp-1;
      else low = midtemp + 1;
  }
  return low;
}
void Push(stack<int>*Last_In_First_Out, int*Countkey)
{
  int key;
  scanf("%d", &key); 
  (*Last_In_First_Out).push(key); 
  insertCountkey(Countkey,key,1);
}
void Pop(stack<int>*Last_In_First_Out, int*Countkey)
{
  if ((*Last_In_First_Out).empty())printf("Invalid\n");
  else 
  {
    printf("%d\n",Last_In_First_Out->top());
    insertCountkey(Countkey, Last_In_First_Out->top(), -1);
    Last_In_First_Out->pop();
  }
}
void PeekMedian(stack<int>*Last_In_First_Out, int*Countkey)
{

  if ((*Last_In_First_Out).empty())printf("Invalid\n");
  else
  {
    printf("%d\n",findmid(Countkey,((*Last_In_First_Out).size() + 1) / 2)); 
  }
}
int main()
{   
  stack<int> Last_In_First_Out;
  int Countkey[MAX]={0};
  int N; 
  char order[11];
  scanf("%d", &N); 
  while (N--)
  {
    scanf("%s",order); 
    switch(order[1])
    {
    case 'u':
      Push(&Last_In_First_Out, Countkey);
      break;
    case 'o':
      Pop(&Last_In_First_Out, Countkey);
      break;
    case 'e': 
      PeekMedian(&Last_In_First_Out, Countkey);
      break;
    }
  } 
  system("pause");
  return 0;
}  

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值