阿里巴巴的一道笔试题

分布式系统中的RPC请求经常出现乱序的情况。

写一个算法来将一个乱序的序列报序输出,列如,假设起始序号是1,对于(1,2,5,8,10,4,3,6,9,7)这个序列,输出是

1

2

3,4,5

6

7,8,9,10

上述例子中,3到来的时候发现4,5已经在了,因此将已经满足顺序的整个序列(3,4,5)输出为一行。


要求:

1.写一个高效的算法完成上述功能,实现要求尽可能的健壮,易于维护

2.为该算法完成单元测试。


我的思路肯定不是最佳的,只是实现了而已,如果有更好的思路和优化请发送到评论区,谢谢~

先说下我的思路:

题目说了是RPC请求,那么在发送过程中发送的包序号应该是1,2,3,4...,这里应该不用考虑丢包吧 - -。

那么这个乱序的序号,实际上就是顺序的序号打乱了,所以按顺序输出后不可能出现1,2,4,5...类似这种情况。

接着看给出的序列是1到10乱序,输出却是顺序的,只不过分块输出了。

看看输出结果可能没什么头绪,但是重点的一句话:

3到来发现4,5已经存在了,因此将满足顺序的整个序列(3,4,5) 输出为一行  

更重点的词:已经,满足顺序,一行。

已经存在说明3是在叫后面录入(分析的意思),4,5已经分析过了但是不满足输出条件而已。这里有个问题是为什么3到来发现4,5存在了输出,而不是4到来了发现

5已经存在了输出?

我认为1,2输出后,根据输出结果来看,是顺序输出的,肯定要输出3,所以一定要的等待3的出现才能顺序输出3,4,5。

那么我假设规则:依次读取每个数据,若读到的其中一个数据可以和前面输出过符合顺序则输出。

后面就好解释了,1,2,3,4,5输出后剩余序列8,10,6,9,7。

读入8,10,不符合,到6了,和已经输出过的3,4,5符合顺序序列,单独输出6。

剩余序列8,10,9,7。

很简单直到读到7符合条件输出顺序序列7,8,9,10。

以上就是我思考的过程。罗嗦了...


我的解决方案:

每次选择开头元素和此刻最小元素的一个区间,在这个区间的元素和最小的元素可以构成顺序序列则输出。

举个例子,假设序列剩余(5,8,10,4,3,6,9,7),那么最小的元素是3。

区间是(5,8,10,4,3)。

分析可得3,4,5顺序序列,输出即可。然后删除元素3,4,5,再次选取最小元素和区间就是6了。每次选取最小元素的区间就可以连接上已经输出过的,保证是顺序的。


代码:

#include <iostream>
#include <vector>
#include <algorithm>
#include <set>

int main()
{
    std::vector<int>ivec = {1,2,5,8,10,4,3,6,9,7};
    std::set<int>iset;
    while(!ivec.empty())   
    {
        /* 选取最小元素 */
        auto mid = min_element(ivec.begin(), ivec.end());
        iset.insert(*mid);
        /* 定义最小元素区间 */
        std::vector<int>tmp(ivec.begin(), mid+1);
        int t = *mid;
        int del = *mid;
        /* 查找和最小元素顺序的元素 */
        while(1)
        {
            auto iter = find(tmp.begin(), tmp.end(), ++t);
            if(iter != tmp.end())
            {
                iset.insert(*iter);
                ivec.erase(remove(ivec.begin(), ivec.end(), t));
            }
            else
            {
                break;
            }
        }
        ivec.erase(remove(ivec.begin(), ivec.end(), del));
        /* 输出序列 */
        auto end = --iset.end();
        for(auto it = iset.begin(); it != end; ++it)
        {
            std::cout << *it << ",";
        }
        std::cout << *end << std::endl;;
        iset.clear();
    }
}





            

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

夏天的技术博客

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值