1. 程式人生 > 其它 >2021-1-14:劍指offer前的三道連結串列題目的整理。06.從尾到頭列印連結串列+18 .刪除連結串列的節點+22 .連結串列中倒數第k個節點

2021-1-14:劍指offer前的三道連結串列題目的整理。06.從尾到頭列印連結串列+18 .刪除連結串列的節點+22 .連結串列中倒數第k個節點

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;
    }
}