【A】1.5 无序集合/映射

有序集合(映射)容器一般基于平衡二叉搜素树实现,无序集合(映射)容器则一般基于哈希表实现。
哈希表,是数组基于某种映射规则(函数)的⼀种扩展:

  • 外部表现为 hash_table['key'] = value,直接通过关键字(浮点数,字符串甚至结构体)索引
  • 内部实现为 linear_list[hash(key)] = value,依靠哈希函数把复杂信息映射到一个较小的值域,并作为索引

哈希函数设计得越好,数据分布越均匀,碰撞概率越小。理想情况下,哈希表的插入、查询、删除时间复杂度均为\(O(1)\)。所以,当我们遇到了要快速判断一个元素是否出现集合里的问题,就可以考虑哈希法。

题目 思路 备注
242. 有效的字母异位词383. 赎金信 字符统计|hash(char)=char-'a' 等价于判断两个频次统计表是否相等
349. 两个数组的交集 对集合\(B\)元素,查询是否也存在于\(A\) 注意不要一边访问一边删除,HashSet
202. 快乐数 模拟,查询是否运算陷入无限死循环 另一个检测环的方式是快慢指针
1. 两数之和 \(x\)前,查询是否存在值\(target-x\) 下标作为附加信息需要存储,HashMap
454. 四数相加 II 查询\(A+B\)中是否存在\(0-c+d\) 将一个四重循环拆分为两个二重循环
874. 模拟行走机器人 模拟,查询当前格点是否属于障碍物 哈希设计;地图方向数组
49. 字母异位词分组 字母基元 -> 异位词列表 分组和哈希冲突“挂链”的相似性;哈希设计

146. LRU缓存

image

图1.5.1 样例


  • 双链表:用于按时间顺序保存数据,便于中间删除
  • 哈希表:用于利用关键字索引相应结点,便于查询
  • 取值
    • 如果关键字存在:定位结点,删除结点、头插、返回 node.val
    • 如果关键字不存在:返回 -1
  • 添加
    • 如果关键字存在:定位结点、删除结点、头插
    • 如果关键字不存在:创建结点、创建索引、头插
      • 容量已满:删除索引,淘汰尾部结点

灵感来源:AC136.邻值查找

image

图1.5.2 实现:双链表+哈希表


点击查看代码
import java.util.HashMap;

class LRUCache {
    int capacity;
    Node head;
    Node tail;
    HashMap<Integer, Node> map;

    public LRUCache(int capacity) {
        this.capacity = capacity;
        head = new Node(-1, -1);
        tail = new Node(-1, -1);
        head.next = tail;
        tail.prev = head;
        map = new HashMap<>();
    }

    public int get(int key) {
        // 定位结点,若不存在返回 -1
        Node node = map.get(key);
        if (node == null) return -1;
        // 更新使用状态,链表:删除、头插
        node.suicide();
        node.append(head);
        // 哈希:无需修改
        return node.val;
    }

    public void put(int key, int value) {
        // 定位结点,更新属性
        if (map.containsKey(key)) {
            Node node = map.get(key);
            node.val = value;
            // 更新使用状态,链表:删除、头插
            node.suicide();
            node.append(head);
            return;
        }

        // 容量已满,淘汰末尾(最久未使用)
        if (map.size() == capacity) {
            map.remove(tail.prev.key);
            tail.prev.suicide();
        }

        // 创建结点
        Node node = new Node(key, value);
        // 哈希:创建索引
        map.put(key, node);
        // 链表:头插
        node.append(head);
    }

    class Node {
        int val;
        int key;
        Node prev;
        Node next;

        Node(int key, int val) {
            this.key = key;
            this.val = val;
        }

        void suicide() {
            this.prev.next = this.next;
            this.next.prev = this.prev;
        }

        void append(Node head) {
            this.next = head.next;
            this.prev = head;
            head.next.prev = this;
            head.next = this;
        }
    }
}

30. 串联所有单词的子串

posted @ 2023-02-09 04:07  安如衫  阅读(41)  评论(0)    收藏  举报