【程序员面试金典】面试题 10.10. 数字流的秩

文章描述了一道面试题,要求设计数据结构和算法来支持跟踪整数流并实时计算每个数字的秩。解题思路是利用插入排序保持序列有序,然后使用二分查找找到小于或等于给定数字的值的个数。在插入新数字时,采用从后向前的插入排序策略,而在查找秩时,通过左开右闭区间进行二分查找上界。
摘要由CSDN通过智能技术生成

【程序员面试金典】面试题 10.10. 数字流的秩

题目描述

描述:假设你正在读取一串整数。每隔一段时间,你希望能找出数字 x 的秩(小于或等于 x 的值的个数)。请实现数据结构和算法来支持这些操作,也就是说:

实现 track(int x) 方法,每读入一个数字都会调用该方法;

实现 getRankOfNumber(int x) 方法,返回小于或等于 x 的值的个数。

注意:本题相对原题稍作改动

示例:

输入:
["StreamRank", "getRankOfNumber", "track", "getRankOfNumber"]
[[], [1], [0], [0]]
输出:
[null,0,null,1]

提示:

x <= 50000
track 和 getRankOfNumber 方法的调用次数均不超过 2000 次

解题思路

思路1:最直观的想法是,插入排序+二分查找。由于每读入一个数字就会调用track方法,故可以使用插入排序,每次插入一个元素时,可以认为原有的元素已经有序,故从后向前遍历数组,如果当前元素小于前一个元素,则交换两个元素,比如1 2 3 4,插入元素2,那么从后向前遍历1 2 3 4 2,第一次交换得到1 2 3 2 4,第二次交换得到1 2 2 3 4。由于要求求解小于等于x的值的个数,故应该找到第一个大于x的值所在的位置,那么此时我们可以使用左开右闭区间[left,right),当res[mid]小于等于x,就令left=mid+1,反之当res[mid]大于x,则令right=mid,因为此时mid可能是第一个大于x的喔!

vector<int> res;
StreamRank() {
}  
void track(int x) 
{
   //每读入一个数字就会调用该方法 故可以使用插入排序
   res.push_back(x);
   //插入排序从后向前
   for(int i=res.size()-1;i>0;i--)
   {
       if(res[i]<res[i-1])
          swap(res[i],res[i-1]);
   }
}
int getRankOfNumber(int x) 
{
   //有序则使用二分查找找上界
   int left=0,right=res.size();
   //左开右闭区间!
   while(left<right)
   {
       int mid=left+(right-left)/2;
       //找到第一个大于x的数
       if(res[mid]<=x)
         left=mid+1;
       //大于则有可能是第一个大于x的
       else
         right=mid;
   }
   return left; //left指向的是第一个大于x的下标 那么left+1-1就是个数
}

总结:要找的是第一个大于x的值!故使用[left,x+1),很自然而然的使用左开右闭区间!如果使用的是[left,x],那么由于存在重复元素,故很难界定是否找到的是最后一个x。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值