Leetcode 203.移除链表元素

题目:203. 移除链表元素

初始思路

很经典的删除链表节点题目。

代码

  1. var removeElements = function (head, val) {
  2. // 添加一个虚拟头结点 不用考虑删除第一个节点的情况
  3. const dummyHead = new ListNode(0)
  4. // 虚拟头结点链接着原来的head节点
  5. dummyHead.next = head
  6. // temp是遍历用的指针
  7. let temp = dummyHead
  8. while (temp.next !== null) {
  9. if (temp.next.val == val) {
  10. // 如果等于这个值就往后链接节点
  11. temp.next = temp.next.next
  12. } else {
  13. // 如果不等于就继续遍历
  14. temp = temp.next
  15. }
  16. }
  17. // 返回虚拟头结点的下一个节点,就是题目需要的新链表的头结点
  18. return dummyHead.next
  19. };

感想

  1. 删除节点的操作很简单,就是把next节点链接到next.next节点上。
  2. 重点是考察虚拟头结点的使用,如果不使用虚拟头结点的话,需要考虑删除的是不是头结点。使用了虚拟头结点之后,把所有节点都看成一样性质的节点,减少了判断。

Leetcode 707.设计链表

题目:707. 设计链表 coderwhy的JavaScript数据结构与算法:https://www.bilibili.com/video/BV1x7411L7Q7 讲解:https://www.bilibili.com/video/BV1FU4y1X7WD

初始思路

之前看coderwhy老师的课的时候手写了一遍单向链表和双向链表,有熟悉的感觉,但是写起来还是很复杂很痛苦!下标很麻烦,而且有一些越界判断。

代码

  1. class Node {
  2. constructor(val, next) {
  3. this.val = val
  4. this.next = next
  5. }
  6. }
  7. var MyLinkedList = function () {
  8. this.head = null
  9. this.tail = null
  10. this.length = 0
  11. };
  12. /**
  13. * @param {number} index
  14. * @return {number}
  15. * 获取链表中第 index 个节点的值。如果索引无效,则返回-1。
  16. */
  17. MyLinkedList.prototype.get = function (index) {
  18. if (index < 0 || index >= this.length) return -1
  19. let current = this.head
  20. let temp = 0
  21. while (temp++ < index) {
  22. current = current.next
  23. }
  24. return current.val
  25. };
  26. /**
  27. * @param {number} val
  28. * @return {void}
  29. * 在链表的第一个元素之前添加一个值为 val 的节点。插入后,新节点将成为链表的第一个节点。
  30. */
  31. MyLinkedList.prototype.addAtHead = function (val) {
  32. let newNode = new Node(val, this.head)
  33. this.head = newNode
  34. this.length++
  35. if (!this.tail) {
  36. // 如果尾结点是空,指向新节点
  37. this.tail = newNode
  38. }
  39. };
  40. /**
  41. * @param {number} val
  42. * @return {void}
  43. * 将值为 val 的节点追加到链表的最后一个元素。
  44. */
  45. MyLinkedList.prototype.addAtTail = function (val) {
  46. let newNode = new Node(val, null)
  47. this.length++
  48. if (this.tail) {
  49. this.tail.next = newNode
  50. this.tail = newNode
  51. return
  52. }
  53. this.tail = newNode
  54. this.head = newNode
  55. };
  56. /**
  57. * @param {number} index
  58. * @param {number} val
  59. * @return {void}
  60. * 在链表中的第 index 个节点之前添加值为 val 的节点。如果 index 等于链表的长度,则该节点将附加到链表的末尾。如果 index 大于链表长度,则不会插入节点。如果index小于0,则在头部插入节点。
  61. */
  62. MyLinkedList.prototype.addAtIndex = function (index, val) {
  63. if (index > this.length) return
  64. if (index <= 0) {
  65. this.addAtHead(val)
  66. return
  67. }
  68. if (index == this.length) {
  69. this.addAtTail(val)
  70. return
  71. }
  72. let temp = 0 // 遍历索引初始化为0
  73. let current = this.head // 遍历的当前节点初始化为head
  74. let previous = null // 遍历的上一节点初始化为null
  75. let newNode = new Node(val, null)
  76. while (temp++ < index) {
  77. previous = current
  78. current = current.next
  79. }
  80. // 在当前节点和当前节点的上一节点之间插入新节点,即改变它们的指向
  81. newNode.next = current
  82. previous.next = newNode
  83. this.length++
  84. };
  85. /**
  86. * @param {number} index
  87. * @return {void}
  88. * 如果索引 index 有效,则删除链表中的第 index 个节点。
  89. */
  90. MyLinkedList.prototype.deleteAtIndex = function (index) {
  91. // 越界判断
  92. if (index < 0 || index >= this.length) return
  93. if (index == 0) {
  94. // 删除头结点
  95. this.head = this.head.next
  96. // 如果删除的这个节点同时是尾结点,也需要处理
  97. if (index === this.length - 1) {
  98. this.tail = this.head
  99. }
  100. } else {
  101. let temp = 0
  102. let current = this.head
  103. let previous = null
  104. while (temp++ < index) {
  105. previous = current
  106. current = current.next
  107. }
  108. // 处理尾结点
  109. if (index === this.length - 1) {
  110. this.tail = previous
  111. } else {
  112. // 让上一节点的 next 指向当前的节点的 next,相当于删除了当前节点。
  113. previous.next = current.next
  114. }
  115. }
  116. this.length--
  117. };

感想

  1. 写起来真的很痛苦,只能说熟能生巧吧。
  2. 写法和代码随想录提供的思路不一样,是按照coderwhy老师的思路写的。
  3. coderwhy老师的课真的讲的不错,可惜没时间看,之后有空把课程补完。

Leetcode 206.反转链表

题目:206. 反转链表

初始思路

暴力解法就是新建一个链表存储反转后的链表,但是浪费空间,之前在原地修改链表即可。

代码

  1. var reverseList = function (head) {
  2. let current = head
  3. let previous = null
  4. // 从前往后遍历
  5. while (current) {
  6. // 提前存储next节点
  7. let next = current.next
  8. // 让每个节点的next指向前一个节点
  9. current.next = previous
  10. // 更新previous位置
  11. previous = current
  12. // 更新current位置
  13. current = next
  14. }
  15. return previous
  16. };

感想

  1. 没有上一道题复杂。
  2. 还是要掌握原地反转链表的方法,指向弯弯绕绕的有点难写写
  3. 图示
    image.png