【算法日记】Set 与 Map 经典算法

文章目录

1. 只出现一次的数字(LC136)

只出现一次的数字

题目描述

解题思路

  1. 使用异或运算符,将数组中所有数字都异或。相同的数字异或为0,剩余的就是出现一个的数字。
  2. 利用Set,当set中包含这个数字就移除,不包含就添加。遍历数组后剩余的数字就是出现一次的数字。(效率低,只是练习用)

代码实现

  • 解法一:
java 复制代码
    public int singleNumber(int[] nums) {
        int ret = 0;
        for(int i = 0;i<nums.length;i++){
            ret = ret^nums[i];
        }
        return ret;
    }
  • 解法二:
java 复制代码
 public int singleNumber(int[] nums) {
        Set <Integer> set = new HashSet<>();
        for(int i = 0;i<nums.length;i++){
            if(set.contains(nums[i]))
                set.remove(nums[i]);
            else 
                set.add(nums[i]);
        }
        for(int i = 0;i<nums.length;i++){
            if(set.contains(nums[i]))
                return nums[i];
        }
        return 0;
    }

2. 随机链表的复制(LC138)

随机链表的复制

题目描述

解题思路

  1. 利用Map建立旧节点和新节点的映射关系
  2. 对应关系:
    • cur初始表示旧节点的头结点
    • map.get(cur)表示对应的新节点;
    • cur.next表示旧节点的下一个节点;
    • map.get(cur.next)表示旧节点的下一个节点对应的新节点;
    • map.get(cur).next表示旧节点对应新节点的下一个节点。
  3. next和random关系类似

代码实现

java 复制代码
 class Node {
        int val;
        Node next;
        Node random;

        public Node(int val) {
            this.val = val;
            this.next = null;
            this.random = null;
        }
    }

    public Node copyRandomList(Node head) {
        Map<Node, Node> map = new HashMap<>();
        Node cur = head;
        //新建节点,建立映射关系
        while (cur != null) {
            Node node = new Node(cur.val);
            map.put(cur, node);
            cur = cur.next;
        }
        cur = head;
       
        //新节点复制旧节点的next和random关系
        while (cur != null) {
            map.get(cur).next = map.get(cur.next);
            map.get(cur).random = map.get(cur.random);
            cur = cur.next;
        }
        return map.get(head);
    }

3. 宝石与石头(LC771)

宝石与石头

题目描述

解题思路

利用Set保存jewels中的字符;再利用计数器,遍历stones,如果set中包含该字符,则计数器自增。

代码实现

java 复制代码
 public int numJewelsInStones(String jewels, String stones) {
        Set<Character> set = new HashSet<>();
        int cnt = 0;
        for(int i = 0;i<jewels.length();i++){
            set.add(jewels.charAt(i));
        }
        for(int i = 0;i<stones.length();i++){
            if(set.contains(stones.charAt(i)))
                cnt++;
        }
        return cnt;
    }

4. 坏键盘

坏键盘

题目描述

解题思路

  1. 先把两个字符串都转换为大写字母;
  2. 遍历输出的字符串,利用Set保存输出的所有字符;
  3. 遍历输入字符串,如果set不包含当前字符,则说明这个字符键盘是坏的。坏字符可能输入多次,所以使用brokenSet保存已检测的坏字符。
  4. 如果set和brokenSet都不包含该字符,则输出。

代码实现

java 复制代码
 public void func(String a,String b){
        a = a.toUpperCase();
        b = b.toUpperCase();

        HashSet<Character> set = new HashSet<>();
        for(int i = 0;i<b.length();i++){
            set.add(b.charAt(i));
        }

        HashSet<Character> brokenSet = new HashSet<>();
        for(int i =0;i<a.length();i++){
            char ch = a.charAt(i);
            if(!set.contains(ch) && !brokenSet.contains(ch)){
                brokenSet.add(ch);
                System.out.print(ch);
            }
        }
    }

5. 前K个高频单词(LC692)

前K个高频单词

题目描述

解题思路

  1. 先利用Map建立起单词和频次的映射关系
  2. 题目要求找频次大的单词,因此建立小根堆,重写比较器
    • 每一次堆顶元素比较时,可以理解为"频次小的要出队,相同频次下序列靠后的要出队",因此频次小具有优先级,相同频次下,序列靠后具有优先级
  3. 遍历map,入队
    • 堆元素小于K时,全部入队
    • 堆元素大于等于K时:
      • 频次大于堆顶元素则入队
      • 频次与堆顶元素相同时,序列更小则入队
  4. 由于是小根堆,堆元素出队的顺序是频次由小到大,而题目要求由大到小,所以要调用reverse方法,逆序存放。

代码实现

java 复制代码
 public List<String> topKFrequent(String[] words, int k) {
        //1. 统计频率
        Map<String,Integer> map = new HashMap<>();
        for(String s:words){
            if(map.containsKey(s))
                map.put(s, map.get(s)+1);
            else
                map.put(s,1);

        }

        //2. 建立小根堆 (频次小的优先,相同频次下排序靠后的优先)
        PriorityQueue<Map.Entry<String,Integer>> minHeap = new PriorityQueue<>(new Comparator<Map.Entry<String,Integer>>() {
            @Override
            public int compare(Map.Entry<String, Integer> o1, Map.Entry<String, Integer> o2) {
                if(o1.getValue().equals(o2.getValue()))
                    return o2.getKey().compareTo(o1.getKey());
                return o1.getValue()-o2.getValue();
            }
        });

        //3. 遍历map
        for(Map.Entry<String,Integer> entry :map.entrySet()){
            //个数不足k时全部入队
            if(minHeap.size()<k)
                minHeap.offer(entry);

                //元素大于等于K时,逐个与堆顶元素比较
            else{
                Map.Entry<String,Integer> top = minHeap.peek();
                //频次大于堆顶元素则入队
                if(top.getValue().compareTo(entry.getValue())<0){
                    minHeap.poll();
                    minHeap.offer(entry);
                }
                //频次相等时,序列靠前入队
                else if(top.getValue().compareTo(entry.getValue())==0){
                    if(top.getKey().compareTo(entry.getKey())>0){
                        minHeap.poll();
                        minHeap.offer(entry);
                    }
                }
            }
        }
        //4. 把字符串放进List中
        List<String> ret = new ArrayList<>();
        while(!minHeap.isEmpty()){
            ret.add(minHeap.poll().getKey());
        }

        //5. 出队的序列是频次由小到大,调用reverse方法逆序排放
        Collections.reverse(ret);
        return ret;
    }
相关推荐
Wei&Yan1 小时前
数据结构——顺序表(静/动态代码实现)
数据结构·c++·算法·visual studio code
团子的二进制世界1 小时前
G1垃圾收集器是如何工作的?
java·jvm·算法
吃杠碰小鸡1 小时前
高中数学-数列-导数证明
前端·数学·算法
故事不长丨1 小时前
C#线程同步:lock、Monitor、Mutex原理+用法+实战全解析
开发语言·算法·c#
long3161 小时前
Aho-Corasick 模式搜索算法
java·数据结构·spring boot·后端·算法·排序算法
近津薪荼1 小时前
dfs专题4——二叉树的深搜(验证二叉搜索树)
c++·学习·算法·深度优先
熊文豪2 小时前
探索CANN ops-nn:高性能哈希算子技术解读
算法·哈希算法·cann
熊猫_豆豆2 小时前
YOLOP车道检测
人工智能·python·算法
艾莉丝努力练剑2 小时前
【Linux:文件】Ext系列文件系统(初阶)
大数据·linux·运维·服务器·c++·人工智能·算法
偷吃的耗子3 小时前
【CNN算法理解】:CNN平移不变性详解:数学原理与实例
人工智能·算法·cnn