链表 数组:增加或者删除非首尾元素时,需要移动元素
链表:增加或者删除非首尾元素时,不需要移动元素,只需要修改其next的指向即可
注: JavaScript 没有链表结构,所以我们需要用Object来模拟链表
题目 删除链表中的节点 https://leetcode-cn.com/problems/delete-node-in-a-linked-list/
时间复杂度:O(1)
空间复杂度:O(1)
1 2 3 4 5 6 7 8 var deleteNode = function (node ) { node.val = node.next .val node.next = node.next .next };
题目 反转链表 https://leetcode-cn.com/problems/reverse-linked-list/
时间复杂度:O(n)
空间复杂度:O(1) // p2里面都是p1的,所以不是新内存,temp因为是单个值,不是数组与矩阵,所以是O(1)
思路:每次循环的时候首先保存之后的链表,再讲当前链表指向新的链表,最后循环”之后的链表“,进而实现
1 2 3 4 5 6 [1,2,3,4,5] => [] [2,3,4,5] => [1] [3,4,5] => [1,2] [4,5] => [1,2,3] [5] => [1,2,3,4] [] => [1,2,3,4,5]
写法1 双指针 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 var reverseList = function (head ) { let p1 = head let p2 = null while (p1) { const temp = p1.next p1.next = p2 p2 = p1 p1 = temp } return p2 };
写法2 递归 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 var reverseList = function (head ) { return reverse (null , head) }; function reverse (now, old ) { if (!old) { return now } let temp = old.next old.next = now return reverse (old, temp) }
题目 两数相加 https://leetcode-cn.com/problems/add-two-numbers/
时间复杂度:O(n)
空间复杂度:O(n)
思路:同时循环两个链表,在将数据放入一个新的链表中,对十位数需要进行额外的处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 var addTwoNumbers = function (l1, l2 ) { let all = new ListNode (0 ) let three = all let carry = 0 while (l1 || l2) { let val = (l1 ? l1.val : 0 ) + (l2 ? l2.val : 0 ) + carry carry = Math .floor (val / 10 ) three.next = new ListNode (val % 10 ) three = three.next if (l1) { l1 = l1.next } if (l2) { l2 = l2.next } } if (carry) { three.next = new ListNode (carry) three = three.next } return all.next };
题目 删除排序链表中的重复元素 https://leetcode-cn.com/problems/remove-duplicates-from-sorted-list/
时间复杂度:O(n)
空间复杂度:O(1)
思路:遇到同样的,删除自己,没遇到,指针向后一位
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 var deleteDuplicates = function (head ) { let all = head while (all && all.next ) { if (all.val == all.next .val ) { all.next = all.next .next } else { all = all.next } } return head }
题目 环形链表 https://leetcode-cn.com/problems/linked-list-cycle/
题目解析: 给定一个特殊的链表,链表的最后一位再次指向链表中的某一个,这样会形成一个环,pos参数是未知的,通过算法判断该链表是否有环
写法1 特殊值法 时间复杂度:O(n)
空间复杂度:O(1)
特殊值一定要保证不能在链表中出现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 var hasCycle = function (head ) { let all = head; while (all) { if (all.val == '123456789' ) { all = null return true } else { all.val = '123456789' all = all.next } } return false };
写法2 快慢指针
为什么快指针与慢指针一定会相遇?
一旦快指针进入环中,每次都离慢指针进一步,因为到了追上的时候,要么相隔1步,下一步相遇,要么相隔2步,下下次一定相遇
快指针与慢指针相遇的时候,慢指针是否绕环超过了一圈
不会,假设环长为N,环外长度为n,N一定大于n;并且根据第一题可知每次快指针都距离慢指针进一步,所以N与n最终会距离n,所以N>n
时间复杂度:O(n)
空间复杂度:O(1)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 var hasCycle = function (head ) { let p1 = head let p2 = head while (p1 && p2 && p2.next ) { p1 = p1.next p2 = p2.next .next if (p1 === p2) { return true } } return false };
JavaScript原型链 1 2 3 obj -> Object.prototype -> null // 对象 func -> Function.prototype -> Object.prototype -> null // 方法 arr -> Array.prototype -> Object.prototype -> null // 数组
如果A沿着原型链能找到B.protype,那么 A instanceof B一定为true
如果A对象上面没有找到X属性,那么就会沿着原型链找到X属性
例如:Object.prototype.x = ‘x’,那么函数func.x也会为x,因为Function.prototype指向Object.prototype
instanceof如何实现?(遍历原型链)
遍历链表,寻找是否存在一致的
1 2 3 4 5 6 7 8 9 10 function instanceOf (params, type ) { let p = params while (p) { if (p === type.prototype ) { return true } p = p.__proto__ } return false }
应用 使用链表获取json的值
在知道全部键的情况下,或者说知道json中数据的的某个值,可以使用链表,嵌套for过于暴力
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 const json = { a : { b : { c : 1 } } } const path = ['a' , 'b' , 'c' ]let p = jsonpath.map (e => { p = p[e] }) console .log (p);
总结
链表中的元素不是连续的,而是通过next指针连接的
JavaScript没有链表,但是Object可有模拟链表
常用操作:遍历链表,修改链表next
JavaScript的原型链也是链表,使用__proto__
进行连接