力扣第206、146题

206.反转链表

给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。
image.png

方法一:迭代

思路:

  1. 设3个指针,prev、curr、next
  2. prev为null,curr等于head,反转时让curr.next等于prev
  3. 因为curr要反转,以免后面的链段了,所以要有一个next变量保存curr.next
    1. var reverseList = function(head) {
    2. let prev = null;
    3. let curr = head;
    4. while (curr) {
    5. const next = curr.next;
    6. curr.next = prev;
    7. prev = curr;
    8. curr = next;
    9. }
    10. return prev;
    11. };
    复杂度分析
  • 时间复杂度:O(n),其中 n 是链表的长度。需要遍历链表一次。
  • 空间复杂度:O(1)。

    方法二:递归

  1. 拆分成两个问题,head和除了head外的反转问题
  2. 再从除了head外的问题拆成两个小问题,递归下去
  3. 到剩一个最小问题,开始回归。
    1. var reverseList = function(head) {
    2. if (head == null || head.next == null) {
    3. return head;
    4. }
    5. const newHead = reverseList(head.next);
    6. head.next.next = head;
    7. head.next = null;
    8. return newHead;
    9. };
    复杂度分析.
  • 时间复杂度: O(m),其中n是链表的长度。需要对链表的每个节点进行反转操作。
  • 空间复杂度: O(n),其中n是链表的长度。空间复杂度主要取决于递归调用的栈空间,最多为n层。

    146.LRU缓存

    请你设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构。
    实现 LRUCache 类:

  • LRUCache(int capacity) 以 正整数 作为容量 capacity 初始化 LRU 缓存

  • int get(int key) 如果关键字 key 存在于缓存中,则返回关键字的值,否则返回 -1 。
  • void put(int key, int value) 如果关键字 key 已经存在,则变更其数据值 value ;如果不存在,则向缓存中插入该组 key-value 。如果插入操作导致关键字数量超过 capacity ,则应该 逐出 最久未使用的关键字。

函数 get 和 put 必须以 O(1) 的平均时间复杂度运行。
image.png

  1. class LRUCache {
  2. constructor(capacity) {
  3. this.capacity = capacity
  4. this.map = new Map();
  5. }
  6. get(key) {
  7. let val = this.map.get(key);
  8. if (val === undefined) return -1;
  9. this.map.delete(key); // 因为被用过一次,原有位置删除
  10. this.map.set(key, val); // 放入最下面表示最新使用
  11. return val;
  12. }
  13. put(key, val) {
  14. if (this.map.has(key)) this.map.delete(key); // 如果有,删除
  15. this.map.set(key, val); // 放到最下面表示最新使用
  16. if (this.map.size > this.capacity) {
  17. // 这里有个知识点
  18. // map的entries方法,还有keys方法(可以看mdn)),会返回一个迭代器
  19. // 迭代器调用next也是顺序返回,所以返回第一个的值就是最老的,找到并删除即可
  20. this.map.delete(this.map.entries().next().value[0])
  21. }
  22. }
  23. };

题解:https://leetcode-cn.com/problems/lru-cache/solution/bu-yong-yu-yan-nei-jian-de-map-gua-dang-feng-zhuan/

  1. class ListNode {
  2. constructor(key, value) {
  3. this.key = key
  4. this.value = value
  5. this.next = null
  6. this.prev = null
  7. }
  8. }
  9. class LRUCache {
  10. constructor(capacity) {
  11. this.capacity = capacity
  12. this.hash = {}
  13. this.count = 0
  14. this.dummyHead = new ListNode()
  15. this.dummyTail = new ListNode()
  16. this.dummyHead.next = this.dummyTail
  17. this.dummyTail.prev = this.dummyHead
  18. }
  19. get(key) {
  20. let node = this.hash[key]
  21. if (node == null) return -1
  22. this.moveToHead(node)
  23. return node.value
  24. }
  25. put(key, value) {
  26. let node = this.hash[key]
  27. if (node == null) {
  28. if (this.count == this.capacity) {
  29. this.removeLRUItem()
  30. }
  31. let newNode = new ListNode(key, value)
  32. this.hash[key] = newNode
  33. this.addToHead(newNode)
  34. this.count++
  35. } else {
  36. node.value = value
  37. this.moveToHead(node)
  38. }
  39. }
  40. moveToHead(node) {
  41. this.removeFromList(node)
  42. this.addToHead(node)
  43. }
  44. removeFromList(node) {
  45. let temp1 = node.prev
  46. let temp2 = node.next
  47. temp1.next = temp2
  48. temp2.prev = temp1
  49. }
  50. addToHead(node) {
  51. node.prev = this.dummyHead
  52. node.next = this.dummyHead.next
  53. this.dummyHead.next.prev = node
  54. this.dummyHead.next = node
  55. }
  56. removeLRUItem() {
  57. let tail = this.popTail()
  58. delete this.hash[tail.key]
  59. this.count--
  60. }
  61. popTail() {
  62. let tail = this.dummyTail.prev
  63. this.removeFromList(tail)
  64. return tail
  65. }
  66. }