日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > java >内容正文

java

左神算法:将单链表的每K个节点之间逆序(Java版)

發(fā)布時間:2024/2/28 java 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 左神算法:将单链表的每K个节点之间逆序(Java版) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

本題來自左神《程序員代碼面試指南》“將單鏈表的每K個節(jié)點之間逆序”題目。

題目

給定一個單鏈表的頭節(jié)點head,實現(xiàn)一個調(diào)整單鏈表的函數(shù),使得每K 個節(jié)點之間逆序,如果最后不夠K 個節(jié)點一組,則不調(diào)整最后幾個節(jié)點。

例如:
鏈表:1->2->3->4->5->6->7->8->null,K=3。
調(diào)整后為:3->2->1->6->5->4->7->8->null。其中7、8 不調(diào)整,因為不夠一組。

題解

首先,如果K 的值小于2,不用進行任何調(diào)整。因為K<1 沒有意義,K==1 時,代表每1 個節(jié)點為1 組進行逆序,原鏈表也沒有任何變化。接下來介紹兩種方法,如果鏈表長度為N,方法一的時間復(fù)雜度為O(N),額外空間復(fù)雜度為O(K)。方法二的時間復(fù)雜度為O(N),額外空間復(fù)雜度為O(1)。本題考查面試者代碼實現(xiàn)不出錯的能力。

方法一:利用棧結(jié)構(gòu)的解法。

1.從左到右遍歷鏈表,如果棧的大小不等于K,就將節(jié)點不斷壓入棧中。

2.當(dāng)棧的大小第一次到達K 時,說明第一次湊齊了K 個節(jié)點進行逆序,從棧中依次彈出這些節(jié)點,并根據(jù)彈出的順序重新連接,這一組逆序完成后,需要記錄一下新的頭部,同時第一組的最后一個節(jié)點(原來是頭節(jié)點)應(yīng)該連接下一個節(jié)點。

例如:鏈表 1->2->3->4->5->6->7->8->null,K = 3
第一組節(jié)點進入棧,從棧頂?shù)綏5滓来螢?3 , 2 , 1 。逆序重連之后為 3->2->1->… , 然后節(jié)點 1 去連接節(jié)點 4 , 鏈表變?yōu)?3->2->1->4->5->6->7->8->null,之后從節(jié)點 4 開始不斷處理 K 個節(jié)點為一組的后續(xù)情況,也就是步驟3,并且需要記錄節(jié)點3,因為鏈表的頭部已經(jīng)改變,整個過程結(jié)束后需要返回這個新的頭節(jié)點,記為newHead。

3.步驟2 之后,當(dāng)棧的大小每次到達K 時,說明又湊齊了一組應(yīng)該進行逆序的節(jié)點,從棧中依次彈出這些節(jié)點,并根據(jù)彈出的順序重新連接。這一組逆序完成后,該組的第一個節(jié)點(原來是該組最后一個節(jié)點)應(yīng)該被上一組的最后一個節(jié)點連接上,這一組的最后一個節(jié)點(原來是該組第一個節(jié)點)應(yīng)該連接下一個節(jié)點。然后繼續(xù)去湊下一組,直到鏈表都被遍歷完。

例如:鏈表3->2->1->4->5->6->7->8->null,K = 3,第一組已經(jīng)處理完。第二組從棧頂?shù)綏5滓来螢?,5,4。逆序重連之后為6->5->4,然后節(jié)點6 應(yīng)該被節(jié)點1 連接,節(jié)點4 應(yīng)該連接節(jié)點7,鏈表變?yōu)?->2->1->6->5->4->7->8->null。然后繼續(xù)從節(jié)點7 往下遍歷。

4.最后應(yīng)該返回newHead,作為鏈表新的頭節(jié)點。

方法一的具體實現(xiàn)請參看如下代碼中的 reverseKNodes1 方法。

/*** 方法一:借助棧*/ public static Node reverseKNodes1(Node head, int K) {if (K < 2) {return head;}Stack<Node> stack = new Stack<Node>();Node newHead = head;Node cur = head;Node pre = null;Node next = null;while (cur != null) {next = cur.next;stack.push(cur);if (stack.size() == K) { // 湊齊一組pre = resign1(stack, pre, next); // 將棧中節(jié)點重新連接實現(xiàn)反轉(zhuǎn)newHead = newHead == head ? cur : newHead; // 僅第一組節(jié)點滿足 newHead == head,用于設(shè)置新頭結(jié)點為反轉(zhuǎn)后的返回節(jié)點。對于此后其他組,這一判斷均形同虛設(shè)。}cur = next;}return newHead; }/*** 將stack中的節(jié)點彈出并連接在left和right中間,形成形如 left -> (...stack...) -> right 的鏈表* @return 反轉(zhuǎn)后right節(jié)點的前驅(qū)結(jié)點*/ public static Node resign1(Stack<Node> stack, Node left, Node right) {Node cur = stack.pop();if (left != null) {left.next = cur;}Node next = null;while (!stack.isEmpty()) {next = stack.pop();cur.next = next;cur = next;}cur.next = right;return cur; }

方法二:不需要棧結(jié)構(gòu),在原鏈表中直接調(diào)整。

用變量記錄每一組開始的第一個節(jié)點和最后一個節(jié)點,然后直接逆序調(diào)整,把這一組的節(jié)點都逆序。和方法一一樣,同樣需要注意第一組節(jié)點的特殊處理,以及之后的每個組在逆序重連之后,需要讓該組的第一個節(jié)點(原來是最后一個節(jié)點)被之前組的最后一個節(jié)點連接上,將該組的最后一個節(jié)點(原來是第一個節(jié)點)連接下一個節(jié)點。

方法二的具體實現(xiàn)請參看如下代碼中的 reverseKNodes2 方法。

/*** 方法二:在鏈表中原地翻轉(zhuǎn)*/ public static Node reverseKNodes2(Node head, int K) {if (K < 2) {return head;}Node cur = head;Node start = null;Node pre = null;Node next = null;int count = 1;while (cur != null) {next = cur.next;if (count == K) { // 湊齊一組start = pre == null ? head : pre.next;head = pre == null ? cur : head;resign2(pre, start, cur, next); // 反轉(zhuǎn)當(dāng)前組。參數(shù)分別為:前驅(qū),起始,終止,后繼pre = start;count = 0;}count++;cur = next;}return head; }public static void resign2(Node left, Node start, Node end, Node right) {Node pre = start;Node cur = start.next;Node next = null;while (cur != right) { // 反轉(zhuǎn)鏈表標(biāo)準(zhǔn)操作next = cur.next;cur.next = pre;pre = cur;cur = next;}if (left != null) {left.next = end;}start.next = right; }

附:全部代碼(包含測試用例)

package chapter_2_listproblem;import java.util.Stack;public class Problem_12_ConvertEveryKNodesInList {public static class Node {public int value;public Node next;public Node(int data) {this.value = data;}}/*** 方法一:借助棧*/public static Node reverseKNodes1(Node head, int K) {if (K < 2) {return head;}Stack<Node> stack = new Stack<Node>();Node newHead = head;Node cur = head;Node pre = null;Node next = null;while (cur != null) {next = cur.next;stack.push(cur);if (stack.size() == K) { // 湊齊一組pre = resign1(stack, pre, next); // 將棧中節(jié)點重新連接實現(xiàn)反轉(zhuǎn)newHead = newHead == head ? cur : newHead; // 僅第一組節(jié)點滿足 newHead == head,用于設(shè)置新頭結(jié)點為反轉(zhuǎn)后的返回節(jié)點。對于此后其他組,這一判斷均形同虛設(shè)。}cur = next;}return newHead;}/*** 將stack中的節(jié)點彈出并連接在left和right中間,形成形如 left -> (...stack...) -> right 的鏈表* @return 反轉(zhuǎn)后right節(jié)點的前驅(qū)結(jié)點*/public static Node resign1(Stack<Node> stack, Node left, Node right) {Node cur = stack.pop();if (left != null) {left.next = cur;}Node next = null;while (!stack.isEmpty()) {next = stack.pop();cur.next = next;cur = next;}cur.next = right;return cur;}/*** 方法二:在鏈表中原地翻轉(zhuǎn)*/public static Node reverseKNodes2(Node head, int K) {if (K < 2) {return head;}Node cur = head;Node start = null;Node pre = null;Node next = null;int count = 1;while (cur != null) {next = cur.next;if (count == K) { // 湊齊一組start = pre == null ? head : pre.next;head = pre == null ? cur : head;resign2(pre, start, cur, next); // 反轉(zhuǎn)當(dāng)前組。參數(shù)分別為:前驅(qū),起始,終止,后繼pre = start;count = 0;}count++;cur = next;}return head;}public static void resign2(Node left, Node start, Node end, Node right) {Node pre = start;Node cur = start.next;Node next = null;while (cur != right) { // 反轉(zhuǎn)鏈表標(biāo)準(zhǔn)操作next = cur.next;cur.next = pre;pre = cur;cur = next;}if (left != null) {left.next = end;}start.next = right;}// for testpublic static void printLinkedList(Node head) {System.out.print("Linked List: ");while (head != null) {System.out.print(head.value + " ");head = head.next;}System.out.println();}public static void main(String[] args) {Node head = null;int K = 3;printLinkedList(head);head = reverseKNodes1(head, K);printLinkedList(head);head = reverseKNodes2(head, K);printLinkedList(head);System.out.println("=======================");head = new Node(1);K = 3;printLinkedList(head);head = reverseKNodes1(head, K);printLinkedList(head);head = reverseKNodes2(head, K);printLinkedList(head);System.out.println("=======================");head = new Node(1);head.next = new Node(2);K = 2;printLinkedList(head);head = reverseKNodes1(head, K);printLinkedList(head);head = reverseKNodes2(head, K);printLinkedList(head);System.out.println("=======================");head = new Node(1);head.next = new Node(2);K = 3;printLinkedList(head);head = reverseKNodes1(head, K);printLinkedList(head);head = reverseKNodes2(head, K);printLinkedList(head);System.out.println("=======================");head = new Node(1);head.next = new Node(2);head.next.next = new Node(3);head.next.next.next = new Node(4);K = 2;printLinkedList(head);head = reverseKNodes1(head, K);printLinkedList(head);head = reverseKNodes2(head, K);printLinkedList(head);System.out.println("=======================");head = new Node(1);head.next = new Node(2);head.next.next = new Node(3);head.next.next.next = new Node(4);head.next.next.next.next = new Node(5);head.next.next.next.next.next = new Node(6);head.next.next.next.next.next.next = new Node(7);head.next.next.next.next.next.next.next = new Node(8);K = 3;printLinkedList(head);head = reverseKNodes1(head, K);printLinkedList(head);head = reverseKNodes2(head, K);printLinkedList(head);System.out.println("=======================");} }

輸出結(jié)果:

Linked List: Linked List: Linked List: ======================= Linked List: 1 Linked List: 1 Linked List: 1 ======================= Linked List: 1 2 Linked List: 2 1 Linked List: 1 2 ======================= Linked List: 1 2 Linked List: 1 2 Linked List: 1 2 ======================= Linked List: 1 2 3 4 Linked List: 2 1 4 3 Linked List: 1 2 3 4 ======================= Linked List: 1 2 3 4 5 6 7 8 Linked List: 3 2 1 6 5 4 7 8 Linked List: 1 2 3 4 5 6 7 8 =======================Process finished with exit code 0

總結(jié)

以上是生活随笔為你收集整理的左神算法:将单链表的每K个节点之间逆序(Java版)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。