雙向循環鏈表
node
理解指針或引用的含義dom
將某個變量賦值給指針,實際上就是將這個變量的地址賦值給指針,或者反過來講,指針中存儲了這個變量的內存地址,指向了這個變量,經過指針就能找到這個變量。this
在編寫鏈表代碼的時候,咱們常常會有這樣的代碼:p->next=q。這行代碼是說,p 結點中的 next 指針存儲了 q 結點的內存地址。指針
還有一個更復雜的,也是咱們寫鏈表代碼常常會用到的:p->next=p->next->next。這行代碼表示,p 結點的 next 指針存儲了 p 結點的下下一個結點的內存地址。code
注意不要把指針弄丟,好比插入是時候blog
在刪除的時候要注意,釋放內存排序
在處理刪除時,head節點比較難處理,因此添加一個哨兵,而後處理完,返回哨兵的next遞歸
常常用來檢查鏈表代碼是否正確的邊界條件有這樣幾個:內存
寫在紙上,把指針賦值和調整以後的結果也畫出來,對照寫,就比較簡單了
rem
共25個已完成13個,全是中等
個常見的鏈表操做:
/** * Definition for singly-linked list. * function ListNode(val) { * this.val = val; * this.next = null; * } */ /** * @param {ListNode} head * @return {ListNode} */ var reverseList = function(head) { var prev = null; var cur = head; var next = null; while (cur !== null) { next = cur.next; cur.next = prev; prev = cur; cur = next; } return prev; } // 鏈表的遞歸實現 var reverseList = function(H) { if (H === null || H.next === null) //鏈表爲空直接返回,而H->next爲空是遞歸基 return H var newHead = reverseList(H.next) //一直循環到鏈尾 H.next.next = H //翻轉鏈表的指向 H.next = null //記得賦值NULL,防止鏈表錯亂 return newHead //新鏈表頭永遠指向的是原鏈表的鏈尾 }
使用set來存儲 var hasCycle = function(head) { const set = new Set(); if (head == null) { return false; } while(head.next !== null) { if(set.has(head)) { return true; } else { set.add(head); } head = head.next; } return false; }; 使用快慢指針 var hasCycle = function(head) { if (head == null || head.next == null) { return false; } let slow = head; let fast = head.next; while (slow != fast) { if (fast == null || fast.next == null) { return false; } slow = slow.next; fast = fast.next.next; } return true; };
var mergeTwoLists = function(l1, l2) { let preHead = new ListNode(); let cur = preHead; while (l1 && l2){ if(l1.val <= l2.val){ cur.next = new ListNode(l1.val); l1 = l1.next; } else { cur.next = new ListNode(l2.val); l2 = l2.next; } cur = cur.next; } cur.next = l1 || l2 return preHead.next; };
var swapPairs = function(head) { var dummyHead = new ListNode(0); dummyHead.next = head; p = dummyHead; while(p.next && p.next.next) { var node1 = p.next; var node2 = p.next.next; var next = node2.next; node2.next = node1; node1.next = next; p.next = node2; p = node1 } if (dummyHead.next === null) { return [] }else { return dummyHead.next; } };
空間換時間 O(n) 空間複雜度:O(N) var middleNode = function(head) { const arr = []; while(head !== null) { arr.push(head); head = head.next; } const middle = Math.floor(arr.length / 2); return arr[middle]; }; 快慢指針 var middleNode = function(head) { slow = fast = head; while (fast && fast.next) { slow = slow.next; fast = fast.next.next; } return slow; };
var swapPairs = function(head) { var dummyHead = new ListNode(0); dummyHead.next = head; p = dummyHead; while(p.next && p.next.next) { var node1 = p.next; var node2 = p.next.next; var next = node2.next; node2.next = node1; node1.next = next; p.next = node2; p = node1 } if (dummyHead.next === null) { return [] }else { return dummyHead.next; } };
把下一個的值賦給這個node,而後刪除下一個節點便可 var deleteNode = function(node) { node.val = node.next.val; node.next = node.next.next; };
由於是有序的,因此直接前一個跟後一個對比刪除就好了時間複雜度O(N) 如何是無序的使用set也能夠作到O(N), 就是空間換時間 var deleteDuplicates = function(head) { if (head == null) { return []; } let cur = head; while(cur && cur.next){ if (cur.val === cur.next.val) { cur.next = cur.next.next } else { cur = cur.next } } return head; };
var removeElements = function(head, val) { while (head !== null && head.val === val) { head = head.next; } if (head === null) { return [] } let cur = head; while(cur.next !== null) { if (cur.next.val === val) { cur.next = cur.next.next } else { cur = cur.next; } } return head; }; <!--遞歸--> if (head == null){ return null; } head.next = removeElements(head.next,val); return head.val == val ? head.next:head; // 使用頭部守位 而後返回 dummnyHead.next var removeElements = function(head, val) { let dummnyHead = new ListNode(0); dummnyHead.next = head; let cur = dummnyHead; while(cur.next !== null) { if (cur.next.val === val) { cur.next = cur.next.next } else { cur = cur.next; } } if (dummnyHead.next === null){ return [] } else { return dummnyHead.next } };
快慢針找到中間,而後把後面的翻轉,而後對比 var reverseList = function(head) { var pre = null; var cur = head; var next = null; while(cur !== null) { next = cur.next; cur.next = pre; pre = cur; cur = next; } return pre; } var isPalindrome = function(head) { if(head === null || head.next === null) { return true; } fast = slow = head; while (fast && fast.next) { slow = slow.next; fast = fast.next.next; } if(fast) slow = slow.next; let list2 = reverseList(slow); while(list2 !== null) { if (head.val !== list2.val) { return false; } head = head.next; list2 = list2.next; } return true; };
先變量兩個表,而後把長度磨平,而後在對比節點是否相等 var getIntersectionNode = function(headA, headB) { if(headA === null || headB === null) { return null; } var listA = headA; var listB = headB; var lenA = 0; var lenB = 0; while(listA !== null) { listA = listA.next; lenA++; } while(listB !== null) { listB = listB.next; lenB++; } if (lenA > lenB) { var diff = lenA - lenB; while(diff>0) { headA = headA.next; diff--; } } if (lenB > lenA) { var diff = lenB - lenA; while(diff>0) { headB = headB.next; diff--; } } while(headB!=null) { if(headA==headB) return headA; headA=headA.next; headB=headB.next; } return null; };
public class Solution { ListNode head; Random random; public Solution(ListNode h) { head = h; random = new Random(); } public int getRandom() { ListNode c = head; int r = c.val; for(int i=1;c.next != null;i++){ c = c.next; if(random.nextInt(i + 1) == i) r = c.val; } return r; } }
var len = 0, curr = root; while (curr) { len++; curr = curr.next; } var quo = Math.floor(len / k); var rem = len % k; var results = [root]; curr = root; var last = curr; while (k > 1) { for (var i = 0; i < quo; i++) { last = curr; curr = curr.next; } if (rem > 0) { last = curr; curr = curr.next; rem--; } if (last) { last.next = null; } results.push(curr); k--; } return results.map(item => item === null ? []: item);
先遍歷一遍,拿到長度,而後len / k 就是要分紅幾個,而後len % k 就是有一個是多1的
[1,2,3,4,5,6,7,8,9,10]
===>
[4,3,3]
var deleteDuplicates = function(head) { if (head == null) { return []; } let cur = head; while(cur && cur.next){ if (cur.val === cur.next.val) { cur.next = cur.next.next } else { cur = cur.next } } return head; };
var addTwoNumbers = function(l1, l2) { if (!l1) return l2 if (!l2) return l1 let p1 = l1 let p2 = l2 let val, carry const ret = new ListNode() let cur = ret while (p1 || p2) { let current = add(p1, p2, carry) cur.val = current.val carry = current.carry if (p1) p1 = p1.next if (p2) p2 = p2.next if (p1 || p2) { cur.next = new ListNode() cur = cur.next } } if (carry) { cur.next = new ListNode(carry) } return ret }; function add(p1, p2, _carry = 0) { let val = ((p1 && p1.val) || 0) + ((p2 && p2.val) || 0) + _carry let carry = (val >= 10) ? 1 : 0 if (carry) { val -= 10 } return { val, carry } }