Map按value排序的几种方法

3 篇文章 1 订阅

以LeetCode的题目为例:

有 n 个人,每个人都有一个 0 到 n-1 的唯一 id 。

给你数组 w a t c h e d V i d e o s watchedVideos watchedVideos f r i e n d s friends friends ,其中 w a t c h e d V i d e o s [ i ] watchedVideos[i] watchedVideos[i] f r i e n d s [ i ] friends[i] friends[i] 分别表示 id = i 的人观看过的视频列表和他的好友列表。

Level 1 的视频包含所有你好友观看过的视频,level 2 的视频包含所有你好友的好友观看过的视频,以此类推。一般的,Level 为 k 的视频包含所有从你出发,最短距离为 k 的好友观看过的视频。

给定你的 id 和一个 level 值,请你找出所有指定 level 的视频,并将它们按观看频率升序返回。如果有频率相同的视频,请将它们按名字字典序从小到大排列。

示例1:
输入:watchedVideos = [["A","B"],["C"],["B","C"],["D"]], friends = [[1,2],[0,3],[0,3],[1,2]], id = 0, level = 1
输出:["B","C"] 
解释:
你的 id 为 0 ,你的朋友包括:
id 为 1 -> watchedVideos = ["C"] 
id 为 2 -> watchedVideos = ["B","C"] 
你朋友观看过视频的频率为:
B -> 1 
C -> 2
示例2:
输入:watchedVideos = [["A","B"],["C"],["B","C"],["D"]], friends = [[1,2],[0,3],[0,3],[1,2]], id = 0, level = 2
输出:["D"]
解释:
你的 id 为 0 ,你朋友的朋友只有一个人,他的 id 为 3 。

分析:

要想得到最终的视频列表,首先要获得指定level的朋友的名单,显然题目中是一个广度优先搜索,且已经遍历过的节点(朋友)不需要再遍历,由此可通过一个队列来实现得到相应level的friends名单:

        int num = watchedVideos.size();
        LinkedList<Integer> friend_l = new LinkedList();
        boolean[] isSearched = new boolean[num];
        friend_l.offer(id);
        isSearched[id] = true;
        int l = 0;
        while(!friend_l.isEmpty() && l < level) {
            LinkedList<Integer> temp = new LinkedList();
            while(!friend_l.isEmpty()) {
                int cur = friend_l.pollFirst();
                for(int i : friends[cur]) {
                    if(!isSearched[i]) {
                        temp.offer(i);
                        isSearched[i] = true;
                    }
                }
            }
            friend_l = temp;
            l++;
        }

得到了第level层friends的名单后,我们希望得到所有video的列表,由于每种video可能出现多次,很自然的想法是用一个Map来记录video和出现的次数。

        HashMap<String, Integer> map = new HashMap();
        for(int i : friend_l) {
            for(String v : watchedVideos.get(i)) {
                if(map.containsKey(v)) {
                    map.put(v, map.get(v) + 1);
                } else {
                    map.put(v, 1);
                }
            }
        }

由此我们得到了video的无序Map。接下来我们按频率,也就是map的value来对其进行排序,就得到了最后的结果。

对Map进行排序

方法1:重写compare方法
        List<Map.Entry<String, Integer>> res = new ArrayList();
        for(Map.Entry<String, Integer> entry : map.entrySet()) {
            res.add(entry);
        }
        Collections.sort(res, new Comparator<Map.Entry<String, Integer>>(){
            public int compare(Map.Entry<String, Integer> e1, Map.Entry<String, Integer> e2) {
                if(e2.getValue() != e1.getValue()) {
                    return e1.getValue() - e2.getValue();
                } else {
                    return e1.getKey().compareTo(e2.getKey());
                }
            }
        });
方法2:构造优先队列
        Queue<Map.Entry<String, Integer>> queue = new PriorityQueue(new Comparator<Map.Entry<String, Integer>>(){
            public int compare(Map.Entry<String, Integer> e1, Map.Entry<String, Integer> e2) {
                if(e2.getValue() != e1.getValue()) {
                    return e1.getValue() - e2.getValue();
                } else {
                    return e1.getKey().compareTo(e2.getKey());
                }
            }
        });
        for(Map.Entry<String, Integer> entry : map.entrySet()) {
            queue.add(entry);
        }
        List<String> ret = new ArrayList();
        while(!queue.isEmpty())
            ret.add(queue.poll().getKey());
方法3:自己造轮子,写一个快排、堆排序或者归并排序
    private void quickSort(Map.Entry<String, Integer>[] entrys, int start, int end) {
        if(start >= end)
            return;
        int l = start;
        int r = end;
        Map.Entry<String, Integer> cur = entrys[start];
        boolean flag = true;
        while(l < r) {
            if(flag) {
                if(entrys[r].getValue() > cur.getValue()) {
                    r--;
                } else if(entrys[r].getValue() < cur.getValue()){
                    entrys[l] = entrys[r];
                    l++;
                    flag = !flag;
                } else {
                    if(entrys[r].getKey().compareTo(cur.getKey()) > 0) {
                        r--;
                    } else {
                        entrys[l] = entrys[r];
                        l++;
                        flag = !flag;                        
                    }
                }
            } else {
                if(entrys[l].getValue() < cur.getValue()) {
                    l++;
                } else if(entrys[l].getValue() > cur.getValue()){
                    entrys[r] = entrys[l];
                    r--;
                    flag = !flag;
                } else {
                    if(entrys[l].getKey().compareTo(cur.getKey()) < 0) {
                        l++;
                    } else {
                        entrys[r] = entrys[l];
                        r--;
                        flag = !flag;                        
                    }
                }
            }
        }
        entrys[l] =  cur;
        quickSort(entrys, start, l - 1);
        quickSort(entrys, l + 1, end);
    }

之后调用自己写的快速排序:

        Map.Entry[] entrys = new Map.Entry[map.size()];
        int idx = 0;
        for(Map.Entry<String, Integer> entry : map.entrySet()) {
            entrys[idx] = entry;
            idx++;
        }
        quickSort(entrys, 0, map.size() - 1);
        List<String> ret = new ArrayList();
        for(Map.Entry<String, Integer> entry : entrys)
            ret.add(entry.getKey());
        return ret;  

最后的效果是:重写Compare与自己造轮子的速度几乎一致,为37ms,这是因为默认的排序方法就是快速排序。使用优先队列稍微快一些,用时31ms。

要按照mapvalue进行排序,可以使用Java中的Stream API和Collections类的reverseOrder方法。首先,将map的entrySet转换为stream,然后使用sorted方法对entry进行排序排序的依据是entry的value值。最后,使用forEach方法打印排序后的结果。以下是示例代码: ``` map.entrySet().stream() .sorted(Collections.reverseOrder(Map.Entry.comparingByValue())) .forEach(System.out::println); ``` 这段代码会按照mapvalue值进行降序排序,并打印排序后的结果。引用\[1\]中的代码片段展示了如何将map的字符键值对存储到map中。引用\[3\]中的代码片段展示了如何使用Stream API对map的entry进行排序。引用\[2\]中的代码片段展示了如何使用自己编写的快速排序算法对entry进行排序,并将排序后的结果存储到List中。 #### 引用[.reference_title] - *1* *3* [怎么对map中的value进行排序](https://blog.csdn.net/Emily_1021/article/details/97395928)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [Mapvalue排序几种方法](https://blog.csdn.net/GaleZhang/article/details/103842192)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值