第九天:鏈表專項(xiàng)突破 5道題讓你徹底搞懂鏈表

鏈表題目重要順序分類:

2?兩數(shù)相加(ok)

21.?合并兩個(gè)有序鏈表(ok)? ??鏈表? 【類似于題2】

234.?回文鏈表

24 : 鏈表交換

206.?反轉(zhuǎn)鏈表??

92:? 反轉(zhuǎn)鏈表 II (特別重要,比較難)? ? ? ? ??

劍指offer:

24:反轉(zhuǎn)鏈表

25:合并鏈表

52:2個(gè)鏈表第一個(gè)公共節(jié)點(diǎn)

第2等級(jí):

23:? ?合并K個(gè)升序鏈表

141:??環(huán)形鏈表? ? ? ? ? ? ? ? ? ? ? ? ?

142:? 環(huán)形鏈表2? ? ? ? ? ? ? ? ? ? ??

148:? 排序鏈表? ? ? ? ? ? ? ? ? ? ? ? ?

160: 相交鏈表? ? ? ? ? ? ? ? ? ? ? ? ??

143:? 重排鏈表? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

19:? 刪除鏈表的倒數(shù)第 N 個(gè)結(jié)點(diǎn)? ? ??

25:? ?K 個(gè)一組翻轉(zhuǎn)鏈表? ? ? ? ? ?

總結(jié):遞歸,快慢指針比較


鏈表的6大題型:刪除,合并,反轉(zhuǎn),環(huán)形,排序, 翻轉(zhuǎn), 想加

鏈表題目分類:第一類: 刪除類-----------快慢指針

19:? 刪除鏈表的倒數(shù)第 N 個(gè)結(jié)點(diǎn)? ? ???鏈表

public ListNoderemoveNthFromEnd(ListNode head, int n) {

// n并不知道,只有遍歷完成才能得到

? ? ListNode dummy =new ListNode(0, head); // 生成一個(gè)0開始的dummy節(jié)點(diǎn)

? ? ListNode first = head;

? ? ListNode second = dummy;

? ? for (int i =0; i < n; ++i) {// 先把快指針移動(dòng)n。移動(dòng)到了3的位置

? ? ? ? first = first.next;

? ? }

while (first !=null) {// 一直遍歷到快指針結(jié)束

? ? ? ? first = first.next; // 為什么要移動(dòng)這個(gè)????因?yàn)檫@個(gè)才會(huì)移動(dòng)鏈表,或者是遍歷鏈表

? ? ? ? second = second.next;

? ? }

second.next = second.next.next;// 下一個(gè)節(jié)點(diǎn)直接指向下下個(gè)

? ? ListNode ans = dummy.next;// 因?yàn)橐祷仡^節(jié)點(diǎn)

? ? return ans;

}

刪除有序/無序鏈表中重復(fù)的元素(并不重要)

leetcode 83?

第二類: 合并鏈表(21,23)------遞歸

例題:21 Merge Two Sorted Lists 【easy】

題意:將兩個(gè)排序好的鏈表合并成新的有序鏈表

public ListNodemergeTwoListsDigui(ListNode list1, ListNode list2) {

if (list1 ==null) {

return list2;

? ? }

if (list2 ==null)return list1;

? ? if (list1.val > list2.val) {// l2小

? ? ? ? list2.next = mergeTwoListsDigui(list2.next, list1); // 下一個(gè)元素是:自己的下一個(gè)和大的元素比較

? ? ? ? return list2;

? ? }else {// l1 小

? ? ? ? list1.next = mergeTwoListsDigui(list1.next, list2); // 下一個(gè)元素是:自己的下一個(gè)和大的元素比較

? ? ? ? return list1;

? ? }

}

第三類: 翻轉(zhuǎn)類題型-------遞歸

最基礎(chǔ)最常在面試中遇到的提醒,206一定要熟練掌握

/***

* 遞歸的方式反轉(zhuǎn)鏈表

* 1.遞歸依次返回的數(shù)據(jù)

* 2。下下個(gè)指向自己

* @param head

* @return

*/

public ListNodereverseListDigui(ListNode head) {

if (head ==null || head.next ==null) {

return head;

? ? }

ListNode res = reverseListDigui(head.next); // res=5? head=4

? ? head.next.next = head; // 4->5->null變成4->5->4

? ? head.next =null;// 4->null

? ? return res;

}

翻轉(zhuǎn)部分單鏈表---92(用到206題)

public ListNodereverseBetween(ListNode head, int left, int right) {

ListNode dummyNode =new ListNode(-1);

? ? dummyNode.next = head;

? ? ListNode pre = dummyNode;

? ? for (int i =0; i < left -1; i++) {

pre = pre.next;

? ? }

ListNode rightNode = pre;

? ? for (int i =0; i < right - left +1; i++) {

rightNode = rightNode.next;

? ? }

ListNode leftNode = pre.next;

? ? ListNode curr = rightNode.next;

? ? pre.next =null;

? ? rightNode.next =null;

? ? reverseLinkedList(leftNode);

? ? pre.next = rightNode;

? ? leftNode.next = curr;

? ? return dummyNode.next;

}

/***

* 206題,遞歸的方式反轉(zhuǎn)鏈表

* @param head

*/

public void reverseLinkedList(ListNode head) {

// 也可以使用遞歸反轉(zhuǎn)一個(gè)鏈表

? ? ListNode pre =null;

? ? ListNode cur = head;

? ? while (cur !=null) {

ListNode next = cur.next;

? ? ? ? cur.next = pre;

? ? ? ? pre = cur;

? ? ? ? cur = next;

? ? }

}

25:

public ListNodereverseKGroup(ListNode head, int k) {

ListNode dummy =new ListNode(0);

? ? dummy.next = head;

? ? ListNode pre = dummy;

? ? ListNode end = dummy;

? ? while (end.next !=null) {

for (int i =0; i < k && end !=null; i++) end = end.next;

? ? ? ? if (end ==null)break;

? ? ? ? ListNode start = pre.next;

? ? ? ? ListNode next = end.next;

? ? ? ? end.next =null;

? ? ? ? pre.next = reverse(start);

? ? ? ? start.next = next;

? ? ? ? pre = start;

? ? ? ? end = pre;

? ? }

return dummy.next;

}

/**

* 206

* @param head

* @return

*/

private ListNodereverse(ListNode head) {

ListNode pre =null;

? ? ListNode curr = head;

? ? while (curr !=null) {

ListNode next = curr.next;

? ? ? ? curr.next = pre;

? ? ? ? pre = curr;

? ? ? ? curr = next;

? ? }

return pre;

}

第四類:??環(huán)形鏈表------快慢指針

例題:141 Linked List Cycle 【easy】

例題:142 Linked List Cycle 【easy】

public ListNodedetectCycle(ListNode head) {

if (head ==null || head.next ==null) {

return null;

? ? }

ListNode fast = head, slow = head;

? ? // step1: 快慢指針一起走,指針碰頭快回頭

? ? while (fast !=null && fast.next !=null) {

fast = fast.next.next;

? ? ? ? slow = slow.next;

? ? ? ? if (fast == slow) {

break;

? ? ? ? }

}

if (fast ==null || fast.next ==null) {

return null;

? ? }

fast = head;

? ? // step2:一步一步走,再相遇就是goal

? ? while (fast != slow) {

fast = fast.next;

? ? ? ? slow = slow.next;

? ? }

return fast;

}

相交鏈表: 相交鏈表(160)

public ListNodegetIntersectionNode(ListNode headA, ListNode headB) {

if (headA ==null || headB ==null) {

return null;

? ? }

ListNode pA = headA, pB = headB;

? ? while (pA != pB) {

pA = pA ==null ? headB : pA.next; // 寫法,pA = pA == null

? ? ? ? pB = pB ==null ? headA : pB.next;

? ? }

return pA;

}

第六類:排序鏈表

143

public void reorderList(ListNode head) {

if (head ==null) {

return;

? ? }

ListNode mid = middleNode(head);

? ? ListNode l1 = head;

? ? ListNode l2 = mid.next;

? ? mid.next =null;

? ? l2 = reverseList(l2);

? ? mergeList(l1, l2);

}

public ListNodemiddleNode(ListNode head) {

ListNode slow = head;

? ? ListNode fast = head;

? ? while (fast.next !=null && fast.next.next !=null) {

slow = slow.next;

? ? ? ? fast = fast.next.next;

? ? }

return slow;

}

public ListNodereverseList(ListNode head) {

ListNode prev =null;

? ? ListNode curr = head;

? ? while (curr !=null) {

ListNode nextTemp = curr.next;

? ? ? ? curr.next = prev;

? ? ? ? prev = curr;

? ? ? ? curr = nextTemp;

? ? }

return prev;

}

public void mergeList(ListNode l1, ListNode l2) {

ListNode l1_tmp;

? ? ListNode l2_tmp;

? ? while (l1 !=null && l2 !=null) {

l1_tmp = l1.next;

? ? ? ? l2_tmp = l2.next;

? ? ? ? l1.next = l2;

? ? ? ? l1 = l1_tmp;

? ? ? ? l2.next = l1;

? ? ? ? l2 = l2_tmp;

? ? }

}

148:(用到21題)

public ListNodesortList(ListNode head) {

return sortList(head, null);

}

private ListNodesortList(ListNode head, ListNode tail) {

if (head ==null) {

return head;

? ? }

if (head.next == tail) {

head.next =null;

? ? ? ? return head;

? ? }

ListNode slow = head, fast = head;

? ? while (fast != tail) {

slow = slow.next;

? ? ? ? fast = fast.next;

? ? ? ? if (fast != tail) {

fast = fast.next;

? ? ? ? }

}

ListNode mid = slow;

? ? ListNode listNode1 = sortList(head, mid);

? ? ListNode listNode2 = sortList(mid, tail);

? ? ListNode sorted = merge(listNode1, listNode2);

? ? return sorted;

}

private ListNodemerge(ListNode list1, ListNode list2) {

if (list1 ==null) {

return list2;

? ? }

if (list2 ==null)return list1;

? ? if (list1.val > list2.val) {// l2小

? ? ? ? list2.next = merge(list2.next, list1); // 下一個(gè)元素是:自己的下一個(gè)和大的元素比較

? ? ? ? return list2;

? ? }else {// l1 小

? ? ? ? list1.next = merge(list1.next, list2); // 下一個(gè)元素是:自己的下一個(gè)和大的元素比較

? ? ? ? return list1;

? ? }

}

回文鏈表: 234

public boolean isPalindrome(ListNode head) {

if (head ==null) {

return true;

? ? }

ListNode firstHalfEnd = endOfFirstHalf(head);

? ? ListNode secondHalfStart = reverseList(firstHalfEnd.next);

? ? ListNode p1 = head;

? ? ListNode p2 = secondHalfStart;

? ? boolean result =true;

? ? while (result && p2 !=null) {

if (p1.val != p2.val) {

result =false;

? ? ? ? }

p1 = p1.next;

? ? ? ? p2 = p2.next;

? ? }

firstHalfEnd.next = reverseList(secondHalfStart);

? ? return result;

}

private ListNodereverseList(ListNode head) {

ListNode prev =null;

? ? ListNode curr = head;

? ? while (curr !=null) {

ListNode nextTemp = curr.next;

? ? ? ? curr.next = prev; // 交換

? ? ? ? prev = curr;

? ? ? ? curr = nextTemp;

? ? }

return prev;

}

private ListNodeendOfFirstHalf(ListNode head) {

ListNode fast = head;

? ? ListNode slow = head;

? ? while (fast.next !=null && fast.next.next !=null) {

fast = fast.next.next;

? ? ? ? slow = slow.next;

? ? }

return slow;

}

第七類:拆分鏈表

例題:86 Partition List 【medium】

題意:給定一個(gè)鏈表以及一個(gè)目標(biāo)值,把小于該目標(biāo)值的所有節(jié)點(diǎn)都移至鏈表的前端,大于或等于目標(biāo)值的節(jié)點(diǎn)移至鏈表的尾端,同時(shí)要保持這兩部分在原先鏈表中的相對(duì)位置。

test case:

解題思路:?二分法。設(shè)置兩個(gè)指針left和right,順序遍歷整條鏈表,left、mid、target三者比較,根據(jù)情況left右移或者right左移。關(guān)鍵就在于邊界情況和元素有重復(fù)。

當(dāng) nums[mid] = nums[left] 時(shí),這時(shí)由于很難判斷 target 會(huì)落在哪,那么只能采取 left++

當(dāng) nums[mid] > nums[left] 時(shí),這時(shí)可以分為兩種情況,判斷左半部比較簡(jiǎn)單

當(dāng) nums[mid] < nums[left] 時(shí),這時(shí)可以分為兩種情況,判斷右半部比較簡(jiǎn)單

code

鏈表:(單鏈表:反轉(zhuǎn)、插入、刪除)

基礎(chǔ)知識(shí):鏈表如何實(shí)現(xiàn),如何遍歷鏈表。鏈表可以保證頭部尾部插入刪除操作都是O(1),查找任意元素位置O(N)

基礎(chǔ)題目:

Leetcode 206. Reverse Linked List

Leetcode 876. Middle of the Linked List

注意:快慢指針和鏈表反轉(zhuǎn)幾乎是所有鏈表類問題的基礎(chǔ),尤其是反轉(zhuǎn)鏈表,代碼很短,建議直接背熟。

第8類:鏈表相加求和

題目: 假設(shè)鏈表中每一個(gè)節(jié)點(diǎn)的值都在 0-9 之間,那么鏈表整體可以代表一個(gè)整數(shù)。 例如: 9->3->7 可以代表 937 給定兩個(gè)這樣的鏈表,頭節(jié)點(diǎn)為 head1 head2 生成鏈表相加的新鏈表。 如 9->3->7 和 6 -> 3 生成的新鏈表應(yīng)為 1 -> 0 -> 0 -> 0

總結(jié)鏈表: 基本操作:反轉(zhuǎn)鏈表,合并一個(gè)鏈表,找鏈表的中間節(jié)點(diǎn). 刪除一個(gè)節(jié)點(diǎn),添加一個(gè)節(jié)點(diǎn).

采用的方法:遞歸,快慢指針,迭代法

如何判斷一個(gè)單鏈表有環(huán)?鏈表翻轉(zhuǎn);

鏈表每 k 位逆序;

K個(gè)一組反轉(zhuǎn)鏈表(重點(diǎn))

鏈表反轉(zhuǎn)

算法題:兩個(gè)有序鏈表合并

6.算法題,鏈表求和

鏈表表示一個(gè)數(shù)字,求兩個(gè)數(shù)字相加之和,返回一個(gè)鏈表

算法題:給定一個(gè)鏈表L1、L2,每個(gè)元素是為10以內(nèi)的正整數(shù),鏈表表示一個(gè)數(shù)字,表頭為高位。 求兩個(gè)鏈表之差,以鏈表形式返回

給定兩個(gè)鏈表,存儲(chǔ)著兩個(gè)16進(jìn)制數(shù),鏈表的一個(gè)節(jié)點(diǎn)存儲(chǔ)著16進(jìn)制數(shù)的其中一個(gè)數(shù),從高位到低位,求相加的值,返回一個(gè)鏈表,鏈表中保存相加的結(jié)果。(先反轉(zhuǎn)鏈表,然后逐位相加,記錄進(jìn)位值,再與高位相加)手寫代碼

判斷單鏈表相交,找出節(jié)點(diǎn),手寫代碼

算法題:查找單鏈表中倒數(shù)第k個(gè)節(jié)點(diǎn)

從長(zhǎng)序列中找出前K大的數(shù)字

算法題:冒泡排序的鏈表實(shí)現(xiàn)

鏈表逆序(頭條幾乎是必考的)

public ListNode reverseList(ListNode head)? ? {? ? ? ? if (head== null)? ? ? ? {? ? ? ? ? ? return null;}? ? ? ? if (head.next== null)? ? ? ? {? ? ? ? ? ? return head;}? ? ? ? ListNodeprev= null;ListNodecurrent= head;while (current != null)? ? ? ? {? ? ? ? ? ? ListNodenext= current.next;current.next= prev;prev= current;current= next;}? ? ? ? return prev;}復(fù)制代碼

刪除排序數(shù)組中的重復(fù)項(xiàng)

public int removeDuplicates(int[]nums)? ? {? ? ? ? intlength= nums.length;if (length==0|| length ==1)? ? ? ? {? ? ? ? ? ? return length;}? ? ? ? intsize=1;intpre= nums[0];for (inti=1; i < length; ){? ? ? ? ? ? if (nums[i]== pre)? ? ? ? ? ? {? ? ? ? ? ? ? ? i++;} else? ? ? ? ? ? {pre= nums[size++] = nums[i++];}? ? ? ? }? ? ? ? return size;}復(fù)制代碼

數(shù)組中找到重復(fù)元素

n個(gè)長(zhǎng)為n的有序數(shù)組,求最大的n個(gè)數(shù)

用O(1)的時(shí)間復(fù)雜度刪除單鏈表中的某個(gè)節(jié)點(diǎn) 把后一個(gè)元素賦值給待刪除節(jié)點(diǎn),這樣也就相當(dāng)于是刪除了當(dāng)前元素,只有刪除最后一個(gè)元素的時(shí)間為o(N)平均時(shí)間復(fù)雜度仍然為O(1)

public void deleteNode(ListNode node) {? ? ? ? ? ListNodenext= node.next;node.val= next.val;node.next= next.next;}復(fù)制代碼

刪除單鏈表的倒數(shù)第N個(gè)元素 兩個(gè)指針,第一個(gè)先走N步第二個(gè)再走,時(shí)間復(fù)雜度為O(N),參考link

public ListNode removeNthFromEnd(ListNode head, int n) {? ? ? ? ? if (head== null)? ? ? ? ? {? ? ? ? ? ? ? return null;}? ? ? ? ? if (head.next== null)? ? ? ? ? {? ? ? ? ? ? ? returnn==1? null : head;}? ? ? ? ? intsize=0;ListNodepoint= head;ListNodenode= head;do? ? ? ? ? {? ? ? ? ? ? ? if (size >= n + 1)? ? ? ? ? ? ? {point= point.next;}node= node.next;size++;} while (node != null);if (size== n)? ? ? ? ? {? ? ? ? ? ? ? return head.next;}node= point.next;point.next= node == null ? null : node.next;return head;}復(fù)制代碼

從長(zhǎng)序列中找出前K大的數(shù)字

用數(shù)組實(shí)現(xiàn)雙頭棧

publicstaticclass Stack<T>{? ? ? ? ? ? ? ? ? ? public Stack(intcap)? ? ? ? ? {? ? ? ? ? ? ? if (cap<=0)? ? ? ? ? ? ? {? ? ? ? ? ? ? ? ? thrownewIllegalArgumentException();? ? ? ? ? ? ? }array=newObject[cap];left=0;right=cap-1;? ? ? ? ? }? ? ? ? ? ? private Object[]array;? ? ? ? ? privateintleft;? ? ? ? ? privateintright;? ? ? ? ? ? ? ? ? ? public void push1(T val)? ? ? ? ? {intindex=left+1;? ? ? ? ? ? ? if (index<right)? ? ? ? ? ? ? {array[index]=val;? ? ? ? ? ? ? }left=index;? ? ? ? ? }@SuppressWarnings("unchecked")? ? ? ? ? public T pop1()? ? ? ? ? {? ? ? ? ? ? ? if (left>0)? ? ? ? ? ? ? {return(T)array[left--];}returnnull;? ? ? ? ? }? ? ? ? ? ? ? ? ? ? public void push2(T val)? ? ? ? ? {intindex=right-1;? ? ? ? ? ? ? if (index>left)? ? ? ? ? ? ? {array[index]=val;? ? ? ? ? ? ? }right=index;? ? ? ? ? }@SuppressWarnings("unchecked")? ? ? ? ? public T pop2()? ? ? ? ? {? ? ? ? ? ? ? if (right<array.length)? ? ? ? ? ? ? {return(T)array[right++];? ? ? ? ? ? ? }returnnull;? ? ? ? ? }? ? ? }復(fù)制代碼

兩個(gè)鏈表求和,返回結(jié)果也用鏈表表示 1 -> 2 -> 3 + 2 -> 3 -> 4 = 3 -> 5 -> 7

public ListNode addTwoNumbers(ListNode node1, ListNode node2)? ? ? {? ? ? ? ? ListNodehead= null;ListNodetail= null;booleanupAdd=false;while (!(node1== null && node2 == null))? ? ? ? ? {? ? ? ? ? ? ? ListNodemidResult= null;if (node1 != null)? ? ? ? ? ? ? {midResult= node1;node1= node1.next;}? ? ? ? ? ? ? if (node2 != null)? ? ? ? ? ? ? {? ? ? ? ? ? ? ? ? if (midResult== null)? ? ? ? ? ? ? ? ? {midResult= node2;} else? ? ? ? ? ? ? ? ? {? ? ? ? ? ? ? ? ? ? ? midResult.val += node2.val;}node2= node2.next;}? ? ? ? ? ? ? if (upAdd)? ? ? ? ? ? ? {? ? ? ? ? ? ? ? ? midResult.val += 1;}? ? ? ? ? ? ? if (midResult.val >= 10)? ? ? ? ? ? ? {upAdd=true;midResult.val %= 10;}? ? ? ? ? ? ? else? ? ? ? ? ? ? {upAdd=false;}? ? ? ? ? ? ? if (head== null)? ? ? ? ? ? ? {head= midResult;tail= midResult;} else? ? ? ? ? ? ? {tail.next= midResult;tail= midResult;}? ? ? ? ? }? ? ? ? ? if (upAdd)? ? ? ? ? {tail.next= new ListNode(1);}? ? ? ? ? return head;}復(fù)制代碼

交換鏈表兩兩節(jié)點(diǎn)

public ListNode swapPairs(ListNode head)? ? ? {? ? ? ? ? if (head== null)? ? ? ? ? {? ? ? ? ? ? ? return null;}? ? ? ? ? if (head.next== null)? ? ? ? ? {? ? ? ? ? ? ? return head;}? ? ? ? ? ListNodecurrent= head;ListNodeafter= current.next;ListNode nextCurrent;head= after;do? ? ? ? ? {nextCurrent= after.next;after.next= current;if (nextCurrent== null)? ? ? ? ? ? ? {current.next= null;break;}current.next= nextCurrent.next;after= nextCurrent.next;if (after== null)? ? ? ? ? ? ? {current.next= nextCurrent;break;}current= nextCurrent;} while (true);return head;}復(fù)制代碼

找出數(shù)組中和為給定值的兩個(gè)元素,如:[1, 2, 3, 4, 5]中找出和為6的兩個(gè)元素。

public int[]twoSum(int[]mun,int target)? ? ? {? ? ? ? ? Maptable= new HashMap<>();for (inti=0; i < mun.length; ++i){? ? ? ? ? ? ? Integervalue= table.get(target - mun[i]);if (value != null)? ? ? ? ? ? ? {? ? ? ? ? ? ? ? ? return new int[]{i, value};}? ? ? ? ? ? ? table.put(mun[i], i);}? ? ? ? ? return null;}

單鏈表的基本操作(增刪改查)

獲取單鏈表的長(zhǎng)度

public int getLength(Node head){

if(head ==null){

return 0;

? ? }

int len =0;

? ? while(head !=null){

len++;

? ? ? ? head = head.next;

? ? }

return len;

}

查詢指定索引的節(jié)點(diǎn)值或指定值得節(jié)點(diǎn)值的索引

/** 獲取指定角標(biāo)的節(jié)點(diǎn)值 */

public int getValueOfIndex(Node head, int index)throws Exception {

if (index <0 || index >= getLength(head)) {

throw new Exception("角標(biāo)越界!");

? ? }

if (head ==null) {

throw new Exception("當(dāng)前鏈表為空!");

? ? }

Node dummyHead = head;

? ? while (dummyHead.next !=null && index >0) {

dummyHead = dummyHead.next;

? ? ? ? index--;

? ? }

return dummyHead.value;

}

/** 獲取節(jié)點(diǎn)值等于 value 的第一個(gè)元素角標(biāo) */

public int getNodeIndex(Node head, int value) {

int index = -1;

? ? Node dummyHead = head;

? ? while (dummyHead !=null) {

index++;

? ? ? ? if (dummyHead.value == value) {

return index;

? ? ? ? }

dummyHead = dummyHead.next;

? ? }

return -1;

}

鏈表添加一個(gè)元素

頭部添加一個(gè)元素

public NodeaddAtHead(Node head, int value){

Node newHead =new Node(value);

? ? newHead.next = head;

? ? return newHead;

}

尾部添加一個(gè)元素

public void addAtTail(Node head, int value){

Node node =new Node(value);

? ? Node dummyHead = head;

? ? //找到未節(jié)點(diǎn) 注意這里是當(dāng)元素的下一個(gè)元素為空的時(shí)候這個(gè)節(jié)點(diǎn)即為未節(jié)點(diǎn)

? ? while( dummyHead.next !=null){

dummyHead = dummyHead.next;

? ? }

dummyHead.next = node;

}

鏈表刪除一個(gè)元素

由單鏈表的增加刪除可以看出,鏈表的想要對(duì)指定索引進(jìn)行操作(增加,刪除),的時(shí)候必須獲取該索引的前一個(gè)元素。記住這句話,對(duì)鏈表算法題很有用。

public NodedeleteElement(Node head, int index)throws Exception {

int size = getLength(head);

? ? if (index <0 || index >= size) {

throw new Exception("角標(biāo)越界!");

? ? }

if (index ==0) {

return deleteHead(head);

? ? }else if (index == size -1) {

deleteTail(head);

? ? }else {

Node pre = head;

? ? ? ? while (pre.next !=null && index >1) {

pre = pre.next;

? ? ? ? ? ? index--;

? ? ? ? }

//循環(huán)結(jié)束后 pre 保存的是索引的上一個(gè)節(jié)點(diǎn) 將其指向索引的下一個(gè)元素

? ? ? ? if (pre.next !=null) {

pre.next = pre.next.next;

? ? ? ? }

}

return head;

}

尋找單鏈表的中間元素:快慢指針? (類似于判讀一個(gè)鏈表是否有環(huán))----題目(143)歸并排序

已知一個(gè)單鏈表求倒數(shù)第 N 個(gè)節(jié)點(diǎn)()

常用技巧

1.使用dummy node。dummy node就是在鏈表的head前加一個(gè)節(jié)點(diǎn)指向head,即dummy->head,可以理解成一個(gè)虛擬節(jié)點(diǎn)。多針對(duì)于單鏈表沒有前向指針的問題,保證鏈表的head不會(huì)在刪除操作中丟失。通常情況下,如果鏈表的head會(huì)發(fā)生變化,譬如刪除或者被修改等,可以創(chuàng)建dummy node:

ListNodedummy=newListNode(0);dummy.next = head;復(fù)制代碼

這樣就使得操作head節(jié)點(diǎn)與操作其他節(jié)點(diǎn)沒有區(qū)別。

2.雙指針法。對(duì)于尋找鏈表的某個(gè)特定位置,或者判斷是否有環(huán)等問題時(shí),可以用兩個(gè)指針變量fast和slow:

ListNodeslow=head;ListNodefast=head;復(fù)制代碼

以不同的速度遍歷該鏈表,以找到目標(biāo)位置。注意:在測(cè)試時(shí),需要分別選取鏈表長(zhǎng)度為奇數(shù)和偶數(shù)的test case,可以驗(yàn)證算法在一般情況下的正確性避免遺漏。

3.交換節(jié)點(diǎn)的處理。如果需要交換兩個(gè)節(jié)點(diǎn)的位置,譬如24題?Swap Nodes in Pairs,需要交換兩個(gè)相鄰位置的節(jié)點(diǎn),對(duì)于這兩個(gè)前驅(qū)節(jié)點(diǎn),他們的next指針會(huì)受到影響,這兩個(gè)節(jié)點(diǎn)本身也會(huì)受到影響,可以用以下步驟:

1)先交換兩個(gè)前驅(qū)節(jié)點(diǎn)的next指針的值

2)再交換這兩個(gè)節(jié)點(diǎn)的next指針的值

無論這兩個(gè)節(jié)點(diǎn)的相對(duì)位置和絕對(duì)位置如何,以上的處理方式均可成立

4.同時(shí)操作兩個(gè)鏈表的處理。遇到這種題目,循環(huán)的條件一般可以用while(list1 && list2),當(dāng)循環(huán)跳出來后,再處理剩下非空的鏈表,這相當(dāng)于:邊界情況特殊處理,常規(guī)情況常規(guī)處理

鏈表的問題是面試當(dāng)中常常會(huì)問到的,比如鏈表的倒置,刪除鏈表中某個(gè)結(jié)點(diǎn),合并兩個(gè)排序鏈表,合并 k 個(gè)排序鏈表,排序兩個(gè)無序鏈表等。

這些題目一般有一些相應(yīng)的技巧可以解決。

第一,引入哨兵結(jié)點(diǎn)。如我們開頭說的 dummy node 結(jié)點(diǎn)。在任何時(shí)候,不管鏈表是不是空,head結(jié)點(diǎn)都會(huì)一直指向這個(gè)哨兵結(jié)點(diǎn)。我們也把這種有哨兵結(jié)點(diǎn)的鏈表叫做帶頭鏈表。

第二,雙指針法。這種用法適用于查找鏈表中某個(gè)位置,判斷鏈表是否有環(huán)等

第三,分之歸并法。這種用法適用于鏈表的排序處理,如合并 k 個(gè)排序鏈表,排序兩個(gè)無序鏈表等。

第四,在解答的過程中,要多考慮邊界情況。

鏈表為空

鏈表中只有一個(gè)結(jié)點(diǎn)

鏈表中只包含兩個(gè)結(jié)點(diǎn)

代碼在處理頭結(jié)點(diǎn)跟尾結(jié)點(diǎn)是否存在什么問題

鏈表的相關(guān)重要的操作:

1.dummo:添加頭節(jié)點(diǎn)。 因?yàn)闀?huì)移動(dòng)鏈表。所以要有一個(gè)保存最開始的

2.pr-->node

3.next-->node??

如何移動(dòng)指針

特點(diǎn):沒有指向前面的指針,所以需要定義一個(gè)pre

最后返回dummy .next()。就是鏈表

鏈表的一些操作:

1.如何遍歷一個(gè)鏈表

while (head !=null) {

head=head.next;

}

2.如何指向下一個(gè)指針

head=head.next;區(qū)別:

// head.next = head.next.next;

// head=head.next;

鏈表專項(xiàng)突破

https://juejin.cn/post/6855865111354851335

https://juejin.cn/post/6844903573508063246

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,578評(píng)論 6 544
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,701評(píng)論 3 429
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,691評(píng)論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,974評(píng)論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,694評(píng)論 6 413
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 56,026評(píng)論 1 329
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,015評(píng)論 3 450
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 43,193評(píng)論 0 290
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,719評(píng)論 1 336
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,442評(píng)論 3 360
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,668評(píng)論 1 374
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,151評(píng)論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,846評(píng)論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,255評(píng)論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,592評(píng)論 1 295
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 52,394評(píng)論 3 400
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,635評(píng)論 2 380

推薦閱讀更多精彩內(nèi)容