2021-1-14:劍指offer前的三道連結串列題目的整理。06.從尾到頭列印連結串列+18 .刪除連結串列的節點+22 .連結串列中倒數第k個節點
阿新 • • 發佈:2021-01-15
LeetCode題解彙總
今日語錄:
這世上的愛,原本有千萬種模樣。他們的生活中,雖然沒有甜言蜜語、海誓山盟,卻有無數個庸常日子裡的點滴溫暖,和那些柴米油鹽裡的守望相助。因為懂得,所以慈悲。
當前已更新下面的三道題目:
劍指 Offer 06.從尾到頭列印連結串列
劍指 Offer 18 .刪除連結串列的節點
劍指 Offer 22 .連結串列中倒數第k個節點
自己寫的程式的規格結構,如下圖:
1.連結串列
劍指 Offer 06.從尾到頭列印連結串列
思考:利用棧“先進後出”的性質。遍歷連結串列,儲存結點值。遍歷輸出棧值。業務程式碼還是很容易寫的。
引申可見 劍指 Offer 24 . 反轉連結串列
為了在IDEA上方便除錯,需要實現“nums2ListNode”,即陣列轉連結串列的業務程式碼。
private static ListNode nums2ListNode(int[] nums) {
// 1.首先先去建立頭結點
ListNode head = new ListNode(nums[0]);
// 2.建立結點 node 去遍歷陣列元素
ListNode node = head;
// 3.從陣列的第2個元素依次遍歷
for (int i = 1; i < nums.length; i++) {
// 4.建立臨時結點
ListNode temp = new ListNode(nums[i]);
node.next = temp;
// 更新 node 節點
node = temp;
}
return head;
}
為了在IDEA上方便除錯,需要實現“printListNode”,即連結串列內容列印的業務程式碼。
private static void printListNode(ListNode head) {
StringBuffer res = new StringBuffer();
while (head. next != null) {
res.append(head.val + "->");
head = head.next;
}
res.append(head.val);
System.out.println(res);
}
完整程式碼:
ArrayList如何轉換為int[]陣列 https://blog.csdn.net/huanghanqian/article/details/73920439
這個是java8的特性
int[] res = list.stream().mapToInt(Integer::intValue).toArray();
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Stack;
public class Offer06 {
public static void main(String[] args) {
int[] nums = new int[]{1, 3, 2};
ListNode head = nums2ListNode(nums);
printListNode(head);
System.out.println(reversePrint(head));
}
private static void printListNode(ListNode head) {
StringBuffer res = new StringBuffer();
while (head.next != null) {
res.append(head.val + "->");
head = head.next;
}
res.append(head.val);
System.out.println(res);
}
private static ListNode nums2ListNode(int[] nums) {
// 1.首先先去建立頭結點
ListNode head = new ListNode(nums[0]);
// 2.建立結點 node 去遍歷陣列元素
ListNode node = head;
// 3.從陣列的第2個元素依次遍歷
for (int i = 1; i < nums.length; i++) {
// 4.建立臨時結點
ListNode temp = new ListNode(nums[i]);
node.next = temp;
// 更新 node 節點
node = temp;
}
return head;
}
public static int[] reversePrint(ListNode head) {
Stack<Integer> stack = new Stack<>();
ArrayList<Integer> list = new ArrayList<>();
while (head != null) {
stack.push(head.val);
head = head.next;
}
while (!stack.isEmpty()) {
list.add(stack.pop());
}
// ArrayList<Integer>如何轉換為int[]陣列 https://blog.csdn.net/huanghanqian/article/details/73920439
// 這個是java8的特性
int[] res = list.stream().mapToInt(Integer::intValue).toArray();
return res;
}
}
ListNode的程式碼放在外邊
public class ListNode {
int val;
ListNode next;
ListNode(int x) {
val = x;
}
}
劍指 Offer 18 .刪除連結串列的節點
思考:這個考慮可能刪除頭結點,尾節點,等情況,需要採用“虛擬頭結點”+“快慢指標”的操作。
要刪除一個節點,那麼該節點的前一個節點指向該節點的後一個節點,並將該節點的next指向null,則實現了刪除指定節點的操作。
import java.util.ArrayList;
import java.util.Stack;
public class Offer18 {
public static void main(String[] args) {
int[] nums = new int[]{4, 5, 1, 9};
ListNode head = nums2ListNode(nums);
printListNode(head);
ListNode resHead = deleteNode(head, 5);
printListNode(resHead);
}
private static void printListNode(ListNode head) {
StringBuffer res = new StringBuffer();
while (head.next != null) {
res.append(head.val + "->");
head = head.next;
}
res.append(head.val);
System.out.println(res);
}
private static ListNode nums2ListNode(int[] nums) {
// 1.首先先去建立頭結點
ListNode head = new ListNode(nums[0]);
// 2.建立結點 node 去遍歷陣列元素
ListNode node = head;
// 3.從陣列的第2個元素依次遍歷
for (int i = 1; i < nums.length; i++) {
// 4.建立臨時結點
ListNode temp = new ListNode(nums[i]);
node.next = temp;
// 更新 node 節點
node = temp;
}
return head;
}
public static ListNode deleteNode(ListNode head, int val) {
// 1.建立虛擬頭結點
ListNode dummyNode = new ListNode(0);
dummyNode.next = head;
// 2.建立快慢指標
ListNode fast = dummyNode.next;
ListNode slow = dummyNode;
// 3.遍歷查詢需要刪除的節點
while (fast != null) {
// 一個要刪除的節點的值
if (fast.val == val) {
// 該節點的前一個節點指向該節點的後一個節點
slow.next = fast.next;
// 將該節點的next指向null。這裡好像是加不加都可以。
fast.next = null;
break;
}
// 更新節點
slow = slow.next;
fast = fast.next;
}
// 這裡是考慮到頭結點就是要刪除的節點的情況
return dummyNode.next;
}
}
劍指 Offer 22 .連結串列中倒數第k個節點
思考:“快慢指標”,先讓快指標走k步,然後快慢指標同時向前走,當快指標到達連結串列末尾,慢指標指向了目標節點。
public class Offer22 {
public static void main(String[] args) {
int[] nums = new int[]{1, 2, 3, 4, 5};
ListNode head = nums2ListNode(nums);
printListNode(head);
ListNode resHead = getKthFromEnd(head, 2);
printListNode(resHead);
}
private static void printListNode(ListNode head) {
StringBuffer res = new StringBuffer();
while (head.next != null) {
res.append(head.val + "->");
head = head.next;
}
res.append(head.val);
System.out.println(res);
}
private static ListNode nums2ListNode(int[] nums) {
// 1.首先先去建立頭結點
ListNode head = new ListNode(nums[0]);
// 2.建立結點 node 去遍歷陣列元素
ListNode node = head;
// 3.從陣列的第2個元素依次遍歷
for (int i = 1; i < nums.length; i++) {
// 4.建立臨時結點
ListNode temp = new ListNode(nums[i]);
node.next = temp;
// 更新 node 節點
node = temp;
}
return head;
}
public static ListNode getKthFromEnd(ListNode head, int k) {
// 1.建立快慢指標
ListNode fast = head;
ListNode slow = head;
// 2.先讓快指標走k步
for (int i = 0; i < k; i++) {
fast = fast.next;
}
// 3.然後快慢指標同時向前走,當快指標到達連結串列末尾,慢指標指向了目標節點。
while (fast != null) {
fast = fast.next;
slow = slow.next;
}
return slow;
}
}