查找队列中最新的n个记录

20 篇文章 0 订阅

每天产生的记录入队列,查找最新的n个记录

问题描述:

/**
 * 表示一个用户行为,包含type,timestamp, info信息
 */
interface Action {
    public String getType();

    public long getTimestamp();

    public String getInfo();
}

/**
 * 表示一个用户的行为历史
 */
interface ActionHistory {
    public void addNewAction(Action action);

    public List<Action> getRecentActions(int n);

    public List<Action> getRecentActions(String type, int n);
}

给定两个接口,实现getRecentActions(int n)和getRecentActions(String type, int n)的两个方法,(不断产生的记录数据是按照时间戳Timestamp来排序,时间戳值越大表示数据越新。)分别查找:不区分类型和区分特定类型的查找最新的n条记录。

具体实现如下:

package cetcocean.alibaba;

import java.util.*;
import java.util.Map.Entry;

/**
 * @description:
 * @author: fangchangtan
 * @create: 2019-02-21 08:46
 */


public class SolutionTest {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        MyActionHistory myActionHistory = new MyActionHistory();
        //添加各种记录
        for (int i = 1; i < 50; i = i + 2) {
            MyAciton myAcitonTem = new MyAciton("myScan", i, String.valueOf(i));
            myActionHistory.addNewAction(myAcitonTem);
        }
        for (int i = 0; i < 50; i = i + 2) {
            MyAciton myAcitonTem = new MyAciton("myClick", i, String.valueOf(i));
            myActionHistory.addNewAction(myAcitonTem);
        }

        //...test 单个参数......
        List<Action> listSumActions = myActionHistory.getRecentActions(20);
        System.out.println("listSumActions.size(): " + listSumActions.size() + "   | 获得全部类别的前n项值:");
        for (int i = 0; i < listSumActions.size(); i++) {
            Action action = listSumActions.get(i);
            System.out.println("type:" + action.getType() + " ;Timestamp:" + action.getTimestamp() + ";");
        }

        //...test 两个参数......
        System.out.println("\n" + "---------------我是分割线--------------------------");
        List<Action> listTypeActions = myActionHistory.getRecentActions("myClick", 20);
        System.out.println("listTypeActions.size(): " + listTypeActions.size() + "   | 获得特定type类别的前n项值:");
        for (int i = 0; i < listTypeActions.size(); i++) {
            Action action = listTypeActions.get(i);
            System.out.println("type:" + action.getType() + " ;Timestamp:" + action.getTimestamp() + ";");
        }


    }


}

/**
 * 表示一个用户行为,包含type,timestamp, info信息
 */
interface Action {
    public String getType();

    public long getTimestamp();

    public String getInfo();
}

/**
 * 表示一个用户的行为历史
 */
interface ActionHistory {
    public void addNewAction(Action action);

    public List<Action> getRecentActions(int n);

    public List<Action> getRecentActions(String type, int n);
}

class MyAciton implements Action, Comparable<MyAciton> {
    private String type;
    private long timeStamp;
    private String info;

    public MyAciton(String type, long timeStamp, String info) {
        super();
        this.type = type;
        this.timeStamp = timeStamp;
        this.info = info;
    }

    public String getType() {
        return type;

    }

    public long getTimestamp() {
        return timeStamp;

    }

    public String getInfo() {
        return info;

    }

    @Override
    public int compareTo(MyAciton o) {//升序排序
        return this.getTimestamp() > o.getTimestamp() ? -1 : (this.getTimestamp() < o.getTimestamp() ? 1 : 0);
    }
}

class MyActionHistory implements ActionHistory {

    private static Map<String, List<Action>> mapAcitonRecord = new HashMap<>();

    @Override
    public void addNewAction(Action action) {
        // TODO Auto-generated method stub
        if (mapAcitonRecord.containsKey(action.getType())) {
            mapAcitonRecord.get(action.getType()).add(action);
        } else {
            ArrayList<Action> arrayList = new ArrayList<Action>();
            arrayList.add(action);
            mapAcitonRecord.put(action.getType(), arrayList);
        }
    }

    @Override
    public List<Action> getRecentActions(int n) {
        // TODO Auto-generated method stub
        return getSumTopN(n);
    }

    @Override
    public List<Action> getRecentActions(String type, int n) {
        return getTypeTopN(type, n);
    }


    public Map<String, List<Action>> getMapRecord() {
        // TODO Auto-generated method stub
        return mapAcitonRecord;
    }

    /**
     * 获得指定类型的最新n条记录
     *
     * @param type
     * @param n
     * @return
     */
    public List<Action> getTypeTopN(String type, int n) {
        ArrayList<Action> resultList = new ArrayList<>();
        if (mapAcitonRecord.containsKey(type)) {
            List<Action> list = mapAcitonRecord.get(type);
            int size = list.size();
            //防止非法参数传入
            if (n < 0 || n > size) {
                return resultList;
            }
            for (int i = size - 1; i >= size - n; i--) {
                resultList.add(list.get(i));
            }
            return resultList;
        }
        return resultList;
    }

    /**
     * 获取全部类型的最近topN记录
     *
     * @param n
     * @return
     */
    public List<Action> getSumTopN(int n) {
        //计数已经弹出第count个元素;保证增长的count==n
        int count = 0;
        Map<String, Integer> currIndexMap = new HashMap<>();
        ArrayList<Action> resultList = new ArrayList<>();

        //初始化保存各个类型的最有各个元素的下标,到currIndexMap
        for (Entry<String, List<Action>> entry : mapAcitonRecord.entrySet()) {
            String type = entry.getKey();
            List<Action> queueList = entry.getValue();
            int index = queueList.size() - 1;
            currIndexMap.put(type, index);
        }

        int typeSize = currIndexMap.size();//总的类型type数量
        PriorityQueue<Action> priorityQueue = new PriorityQueue<>();//其实际上是一个大顶锥的实现
        for (Entry<String, List<Action>> entry : mapAcitonRecord.entrySet()) {
            String type = entry.getKey();
            List<Action> queueList = entry.getValue();
            //将各个类型type的最后一个元素添加到priorityQueue,实际一共typeSize个
            priorityQueue.offer(queueList.get(currIndexMap.get(type)));
        }

        while (!priorityQueue.isEmpty()) {
            Action maxAction = priorityQueue.poll();//弹出最大的元素:最新时间戳
            resultList.add(maxAction);
            count++;
            if (count == n) {//计数增加到n时候,就停止循环
                break;
            }
            //更新到下一个下标:并将下一个目标的元素添加到大顶堆中
            String type = maxAction.getType();
            int nextIndex = currIndexMap.get(type) - 1;
            //单个队列中向前找的过程中,没有其他元素的值了:此时防止空指针出现,此时,该类型已经不存在了,直接将该type的指针记录清空
            if (nextIndex < 0) {
                currIndexMap.remove(type);
            }else {
                currIndexMap.put(type, nextIndex);
                priorityQueue.offer(mapAcitonRecord.get(type).get(nextIndex));
            }
            //最终所有type的元素都弹出,此时currIndexMap为空,表示没有元素可以加入优先级队列了.此时直接弹出所有的元素。
            if (currIndexMap.size() == 0) {
                while (!priorityQueue.isEmpty()) {
                    Action maxActionTem = priorityQueue.poll();//弹出最大的元素:最新时间戳
                    resultList.add(maxActionTem);
                    count++;
                }
                return resultList;
            }
        }
        return resultList;
    }


}

思考:1.时间复杂度+空间复杂度
时间复杂度:其中n表示topN中的前n大,k表示type类型数量
O(nklogk)
2.堆排序使用PriorityQueue是java原始提供的内部采用堆排序的方式实现返回最大值(大顶锥)。实现不停的插入元素,并返回最大值【注意重写其中的方法】。
3.该问题是一个【业务设计】+【算法结构】的问题。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值