1实现单链表的基本操作(插入、删除、查找、打印)。

好的,下面是一个用Java语言实现单链表基本操作(插入、删除、查找、打印)的示例代码:
class Node {
    int data;
    Node next;

    public Node(int data) {
        this.data = data;
        this.next = null;
    }
}

class SinglyLinkedList {
    private Node head;

    // 插入节点到链表末尾
    public void insert(int data) {
        Node newNode = new Node(data);
        if (head == null) {
            head = newNode;
        } else {
            Node current = head;
            while (current.next != null) {
                current = current.next;
            }
            current.next = newNode;
        }
    }

    // 删除指定值的节点
    public void delete(int data) {
        if (head == null) return;

        if (head.data == data) {
            head = head.next;
            return;
        }

        Node current = head;
        while (current.next != null && current.next.data != data) {
            current = current.next;
        }

        if (current.next != null) {
            current.next = current.next.next;
        }
    }

    // 查找指定值的节点
    public boolean search(int data) {
        Node current = head;
        while (current != null) {
            if (current.data == data) {
                return true;
            }
            current = current.next;
        }
        return false;
    }

    // 打印链表中的所有节点
    public void printList() {
        Node current = head;
        while (current != null) {
            System.out.print(current.data + " -> ");
            current = current.next;
        }
        System.out.println("null");
    }

    public static void main(String[] args) {
        SinglyLinkedList list = new SinglyLinkedList();
        list.insert(1);
        list.insert(2);
        list.insert(3);
        list.printList(); // 输出: 1 -> 2 -> 3 -> null

        list.delete(2);
        list.printList(); // 输出: 1 -> 3 -> null

        System.out.println(list.search(3)); // 输出: true
        System.out.println(list.search(4)); // 输出: false
    }
}
  1. Node:表示链表中的一个节点,包含数据和指向下一个节点的引用。
  2. SinglyLinkedList:实现了单链表的基本操作。
    • insert(int data):在链表末尾插入一个新节点。
    • delete(int data):删除链表中第一个值为data的节点。
    • search(int data):查找链表中是否存在值为data的节点。
    • printList():打印链表中的所有节点。
  3. main方法:测试上述功能。
你可以根据需要扩展这些基本操作,例如在特定位置插入或删除节点等。

2实现双向链表的基本操作(插入、删除、查找、打印)。

好的,下面是一个用Java语言实现双向链表基本操作(插入、删除、查找、打印)的示例代码:
class DoublyNode {
    int data;
    DoublyNode next;
    DoublyNode prev;

    public DoublyNode(int data) {
        this.data = data;
        this.next = null;
        this.prev = null;
    }
}

class DoublyLinkedList {
    private DoublyNode head;

    // 在链表末尾插入节点
    public void insert(int data) {
        DoublyNode newNode = new DoublyNode(data);
        if (head == null) {
            head = newNode;
        } else {
            DoublyNode current = head;
            while (current.next != null) {
                current = current.next;
            }
            current.next = newNode;
            newNode.prev = current;
        }
    }

    // 删除指定值的节点
    public void delete(int data) {
        if (head == null) return;

        DoublyNode current = head;
        while (current != null && current.data != data) {
            current = current.next;
        }

        if (current == null) return; // 没有找到要删除的节点

        if (current.prev != null) {
            current.prev.next = current.next;
        } else {
            head = current.next; // 如果要删除的是头节点
        }

        if (current.next != null) {
            current.next.prev = current.prev;
        }
    }

    // 查找指定值的节点
    public boolean search(int data) {
        DoublyNode current = head;
        while (current != null) {
            if (current.data == data) {
                return true;
            }
            current = current.next;
        }
        return false;
    }

    // 打印链表中的所有节点
    public void printList() {
        DoublyNode current = head;
        while (current != null) {
            System.out.print(current.data + " <-> ");
            current = current.next;
        }
        System.out.println("null");
    }

    public static void main(String[] args) {
        DoublyLinkedList list = new DoublyLinkedList();
        list.insert(1);
        list.insert(2);
        list.insert(3);
        list.printList(); // 输出: 1 <-> 2 <-> 3 <-> null

        list.delete(2);
        list.printList(); // 输出: 1 <-> 3 <-> null

        System.out.println(list.search(3)); // 输出: true
        System.out.println(list.search(4)); // 输出: false
    }
}
  1. DoublyNode:表示双向链表中的一个节点,包含数据和指向前一个节点及下一个节点的引用。
  2. DoublyLinkedList:实现了双向链表的基本操作。
    • insert(int data):在链表末尾插入一个新节点。
    • delete(int data):删除链表中第一个值为data的节点。
    • search(int data):查找链表中是否存在值为data的节点。
    • printList():打印链表中的所有节点。
  3. main方法:测试上述功能。
你可以根据需要扩展这些基本操作,例如在特定位置插入或删除节点等。


3反转单链表。

反转单链表是一个常见的操作,可以通过迭代或递归的方法来实现。下面分别给出这两种方法的实现:

3.1方法一:迭代法

class Node {
    int data;
    Node next;

    public Node(int data) {
        this.data = data;
        this.next = null;
    }
}

class SinglyLinkedList {
    private Node head;

    // 插入节点到链表末尾
    public void insert(int data) {
        Node newNode = new Node(data);
        if (head == null) {
            head = newNode;
        } else {
            Node current = head;
            while (current.next != null) {
                current = current.next;
            }
            current.next = newNode;
        }
    }

    // 打印链表中的所有节点
    public void printList() {
        Node current = head;
        while (current != null) {
            System.out.print(current.data + " -> ");
            current = current.next;
        }
        System.out.println("null");
    }

    // 反转链表
    public void reverse() {
        Node prev = null;
        Node current = head;
        Node next = null;
        while (current != null) {
            next = current.next; // 保存下一个节点
            current.next = prev; // 当前节点指向前一个节点
            prev = current;      // 前一个节点移动到当前节点
            current = next;      // 当前节点移动到下一个节点
        }
        head = prev; // 更新头节点为最后一个节点
    }

    public static void main(String[] args) {
        SinglyLinkedList list = new SinglyLinkedList();
        list.insert(1);
        list.insert(2);
        list.insert(3);
        list.printList(); // 输出: 1 -> 2 -> 3 -> null

        list.reverse();
        list.printList(); // 输出: 3 -> 2 -> 1 -> null
    }
}

3.2方法二:递归法

class Node {
    int data;
    Node next;

    public Node(int data) {
        this.data = data;
        this.next = null;
    }
}

class SinglyLinkedList {
    private Node head;

    // 插入节点到链表末尾
    public void insert(int data) {
        Node newNode = new Node(data);
        if (head == null) {
            head = newNode;
        } else {
            Node current = head;
            while (current.next != null) {
                current = current.next;
            }
            current.next = newNode;
        }
    }

    // 打印链表中的所有节点
    public void printList() {
        Node current = head;
        while (current != null) {
            System.out.print(current.data + " -> ");
            current = current.next;
        }
        System.out.println("null");
    }

    // 反转链表(递归)
    public void reverse() {
        head = reverseRecursive(head);
    }

    private Node reverseRecursive(Node node) {
        if (node == null || node.next == null) {
            return node; // 基本情况:如果节点为空或只有一个节点,直接返回该节点
        }
        Node rest = reverseRecursive(node.next); // 反转剩余部分的链表
        node.next.next = node; // 将当前节点的下一个节点的next指向当前节点
        node.next = null; // 将当前节点的next置为空
        return rest; // 返回新的头节点
    }

    public static void main(String[] args) {
        SinglyLinkedList list = new SinglyLinkedList();
        list.insert(1);
        list.insert(2);
        list.insert(3);
        list.printList(); // 输出: 1 -> 2 -> 3 -> null

        list.reverse();
        list.printList(); // 输出: 3 -> 2 -> 1 -> null
    }
}

3.3代码说明:

  1. Node:表示单链表中的一个节点,包含数据和指向下一个节点的引用。
  2. SinglyLinkedList:实现了单链表的基本操作,包括插入、打印和反转。
    • insert(int data):在链表末尾插入一个新节点。
    • printList():打印链表中的所有节点。
    • reverse():反转链表,使用迭代法或递归法实现。
  3. main方法:测试上述功能。


4反转双向链表。

反转双向链表与反转单链表类似,但需要处理两个方向的指针(nextprev)。下面分别给出迭代法和递归法的实现:

4.1方法一:迭代法

class DoublyNode {
    int data;
    DoublyNode next;
    DoublyNode prev;

    public DoublyNode(int data) {
        this.data = data;
        this.next = null;
        this.prev = null;
    }
}

class DoublyLinkedList {
    private DoublyNode head;

    // 插入节点到链表末尾
    public void insert(int data) {
        DoublyNode newNode = new DoublyNode(data);
        if (head == null) {
            head = newNode;
        } else {
            DoublyNode current = head;
            while (current.next != null) {
                current = current.next;
            }
            current.next = newNode;
            newNode.prev = current;
        }
    }

    // 打印链表中的所有节点
    public void printList() {
        DoublyNode current = head;
        while (current != null) {
            System.out.print(current.data + " <-> ");
            current = current.next;
        }
        System.out.println("null");
    }

    // 反转链表
    public void reverse() {
        DoublyNode current = head;
        DoublyNode temp = null;
        while (current != null) {
            temp = current.prev; // 保存当前节点的前一个节点
            current.prev = current.next; // 将当前节点的prev指向下一个节点
            current.next = temp; // 将当前节点的next指向前一个节点
            head = current; // 更新头节点为当前节点
            current = current.prev; // 移动到下一个节点
        }
    }

    public static void main(String[] args) {
        DoublyLinkedList list = new DoublyLinkedList();
        list.insert(1);
        list.insert(2);
        list.insert(3);
        list.printList(); // 输出: 1 <-> 2 <-> 3 <-> null

        list.reverse();
        list.printList(); // 输出: 3 <-> 2 <-> 1 <-> null
    }
}

4.2方法二:递归法

class DoublyNode {
    int data;
    DoublyNode next;
    DoublyNode prev;

    public DoublyNode(int data) {
        this.data = data;
        this.next = null;
        this.prev = null;
    }
}

class DoublyLinkedList {
    private DoublyNode head;

    // 插入节点到链表末尾
    public void insert(int data) {
        DoublyNode newNode = new DoublyNode(data);
        if (head == null) {
            head = newNode;
        } else {
            DoublyNode current = head;
            while (current.next != null) {
                current = current.next;
            }
            current.next = newNode;
            newNode.prev = current;
        }
    }

    // 打印链表中的所有节点
    public void printList() {
        DoublyNode current = head;
        while (current != null) {
            System.out.print(current.data + " <-> ");
            current = current.next;
        }
        System.out.println("null");
    }

    // 反转链表(递归)
    public void reverse() {
        head = reverseRecursive(head);
    }

    private DoublyNode reverseRecursive(DoublyNode node) {
        if (node == null || node.next == null) {
            return node; // 基本情况:如果节点为空或只有一个节点,直接返回该节点
        }
        DoublyNode rest = reverseRecursive(node.next); // 反转剩余部分的链表
        node.next.next = node; // 将当前节点的下一个节点的next指向当前节点
        node.prev = node.next; // 将当前节点的prev指向下一个节点
        node.next = null; // 将当前节点的next置为空
        return rest; // 返回新的头节点
    }

    public static void main(String[] args) {
        DoublyLinkedList list = new DoublyLinkedList();
        list.insert(1);
        list.insert(2);
        list.insert(3);
        list.printList(); // 输出: 1 <-> 2 <-> 3 <-> null

        list.reverse();
        list.printList(); // 输出: 3 <-> 2 <-> 1 <-> null
    }
}

4.3代码说明:

  1. DoublyNode:表示双向链表中的一个节点,包含数据、指向下一个节点的引用和指向前一个节点的引用。
  2. DoublyLinkedList:实现了双向链表的基本操作,包括插入、打印和反转。
    • insert(int data):在链表末尾插入一个新节点。
    • printList():打印链表中的所有节点。
    • reverse():反转链表,使用迭代法或递归法实现。
  3. main方法:测试上述功能。



5判断一个链表是否为回文链表。

要判断一个链表是否为回文链表,可以使用以下步骤:
  1. 使用快慢指针找到链表的中间节点。
  2. 反转链表的后半部分。
  3. 比较前半部分和反转后的后半部分是否相同。
  4. 恢复链表(可选)。
  5. 返回结果。
下面是一个完整的Java实现:
class ListNode {
    int val;
    ListNode next;
    ListNode(int x) { val = x; }
}

public class PalindromeLinkedList {
    public boolean isPalindrome(ListNode head) {
        if (head == null || head.next == null) return true;
        
        // Step 1: Find the middle of the linked list using slow and fast pointers
        ListNode slow = head, fast = head;
        while (fast != null && fast.next != null) {
            slow = slow.next;
            fast = fast.next.next;
        }
        
        // Step 2: Reverse the second half of the linked list
        ListNode reversedSecondHalf = reverseList(slow);
        
        // Step 3: Compare the first half and the reversed second half
        ListNode firstHalf = head;
        while (reversedSecondHalf != null) {
            if (firstHalf.val != reversedSecondHalf.val) return false;
            firstHalf = firstHalf.next;
            reversedSecondHalf = reversedSecondHalf.next;
        }
        
        return true;
    }
    
    private ListNode reverseList(ListNode head) {
        ListNode prev = null;
        while (head != null) {
            ListNode next = head.next;
            head.next = prev;
            prev = head;
            head = next;
        }
        return prev;
    }
    
    public static void main(String[] args) {
        PalindromeLinkedList solution = new PalindromeLinkedList();
        
        // Example usage:
        ListNode head = new ListNode(1);
        head.next = new ListNode(2);
        head.next.next = new ListNode(2);
        head.next.next.next = new ListNode(1);
        
        System.out.println(solution.isPalindrome(head)); // Output: true
    }
}

5.1解释:

  1. 找到中间节点:使用快慢指针法,slow每次走一步,fast每次走两步。当fast到达链表末尾时,slow正好在链表的中间位置。
  2. 反转后半部分链表:从中间节点开始反转链表的后半部分。
  3. 比较两部分:同时遍历原链表的前半部分和反转后的后半部分,逐个节点进行比较。如果所有对应节点的值都相等,则链表是回文的。
  4. 恢复链表(可选):如果需要保持链表的原始结构,可以在比较完成后再次反转后半部分链表。
这个算法的时间复杂度是O(n),空间复杂度是O(1)。


6合并两个有序链表。

合并两个有序链表是一个常见的面试题。假设我们有两个升序排列的链表,我们需要将它们合并成一个新的升序链表。
下面是一个完整的Java实现:
class ListNode {
    int val;
    ListNode next;
    ListNode(int x) { val = x; }
}

public class MergeTwoSortedLists {
    public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
        // 创建一个虚拟头节点,方便处理边界情况
        ListNode dummy = new ListNode(0);
        ListNode current = dummy;
        
        // 遍历两个链表,直到其中一个为空
        while (l1 != null && l2 != null) {
            if (l1.val <= l2.val) {
                current.next = l1;
                l1 = l1.next;
            } else {
                current.next = l2;
                l2 = l2.next;
            }
            current = current.next;
        }
        
        // 如果有一个链表还有剩余节点,直接连接到结果链表的末尾
        if (l1 != null) {
            current.next = l1;
        } else {
            current.next = l2;
        }
        
        // 返回合并后的链表(跳过虚拟头节点)
        return dummy.next;
    }
    
    public static void main(String[] args) {
        // 创建测试用例
        ListNode l1 = new ListNode(1);
        l1.next = new ListNode(2);
        l1.next.next = new ListNode(4);
        
        ListNode l2 = new ListNode(1);
        l2.next = new ListNode(3);
        l2.next.next = new ListNode(4);
        
        MergeTwoSortedLists solution = new MergeTwoSortedLists();
        ListNode mergedList = solution.mergeTwoLists(l1, l2);
        
        // 打印合并后的链表
        while (mergedList != null) {
            System.out.print(mergedList.val + " ");
            mergedList = mergedList.next;
        }
    }
}

6.1解释:

  1. 定义链表节点类ListNode类表示链表的节点,每个节点包含一个整数值和一个指向下一个节点的引用。
  2. 合并函数mergeTwoLists方法接受两个有序链表的头节点作为参数,并返回合并后的新链表的头节点。
    • 使用一个虚拟头节点dummy来简化操作,避免处理头节点为空的情况。
    • 使用一个指针current来跟踪新链表的最后一个节点。
    • 遍历两个链表,比较当前节点的值,将较小的节点连接到新链表中,并移动相应的指针。
    • 当其中一个链表遍历完后,将另一个链表的剩余部分直接连接到新链表的末尾。
  3. 主函数:在main方法中创建两个测试链表,调用mergeTwoLists方法进行合并,并打印合并后的链表。
这个算法的时间复杂度是O(n + m),其中nm分别是两个链表的长度。空间复杂度是O(1),因为我们只使用了常数级别的额外空间。

7在单链表中找到中间节点。

在单链表中找到中间节点是一个常见的问题,可以使用快慢指针法(也称为龟兔赛跑算法)来高效地解决这个问题。

7.1快慢指针法

  1. 初始化两个指针:一个慢指针slow和一个快指针fast,都指向链表的头节点。
  2. 遍历链表:快指针每次移动两步,慢指针每次移动一步。当快指针到达链表末尾时,慢指针正好位于链表的中间节点。
下面是一个完整的Java实现:
class ListNode {
    int val;
    ListNode next;
    ListNode(int x) { val = x; }
}

public class FindMiddleNode {
    public ListNode findMiddleNode(ListNode head) {
        if (head == null) return null;
        
        ListNode slow = head;
        ListNode fast = head;
        
        // 快慢指针遍历链表
        while (fast != null && fast.next != null) {
            slow = slow.next;
            fast = fast.next.next;
        }
        
        // 当快指针到达末尾时,慢指针即为中间节点
        return slow;
    }
    
    public static void main(String[] args) {
        // 创建测试用例
        ListNode head = new ListNode(1);
        head.next = new ListNode(2);
        head.next.next = new ListNode(3);
        head.next.next.next = new ListNode(4);
        head.next.next.next.next = new ListNode(5);
        
        FindMiddleNode solution = new FindMiddleNode();
        ListNode middleNode = solution.findMiddleNode(head);
        
        // 打印中间节点的值
        System.out.println("The middle node value is: " + middleNode.val); // Output: 3
    }
}

7.2解释:

  1. 定义链表节点类ListNode类表示链表的节点,每个节点包含一个整数值和一个指向下一个节点的引用。
  2. 找到中间节点的方法findMiddleNode方法接受链表的头节点作为参数,并返回中间节点。
    • 如果链表为空,直接返回null
    • 使用两个指针slowfast,初始时都指向头节点。
    • 遍历链表,快指针每次移动两步,慢指针每次移动一步。当快指针到达链表末尾时,慢指针正好位于链表的中间节点。
  3. 主函数:在main方法中创建一个测试链表,调用findMiddleNode方法找到中间节点,并打印中间节点的值。
这个算法的时间复杂度是O(n),其中n是链表的长度。空间复杂度是O(1),因为我们只使用了常数级别的额外空间。

8删除单链表中的重复元素。

删除单链表中的重复元素是一个常见的问题。我们可以使用一个哈希集合(HashSet)来跟踪已经遇到的元素,从而在遍历链表时删除重复的元素。
下面是一个完整的Java实现:
import java.util.HashSet;

class ListNode {
    int val;
    ListNode next;
    ListNode(int x) { val = x; }
}

public class RemoveDuplicatesFromLinkedList {
    public ListNode deleteDuplicates(ListNode head) {
        if (head == null) return null;
        
        HashSet<Integer> seen = new HashSet<>();
        ListNode current = head;
        seen.add(current.val);
        
        while (current.next != null) {
            if (seen.contains(current.next.val)) {
                // 跳过重复节点
                current.next = current.next.next;
            } else {
                // 记录新值并移动到下一个节点
                seen.add(current.next.val);
                current = current.next;
            }
        }
        
        return head;
    }
    
    public static void main(String[] args) {
        // 创建测试用例
        ListNode head = new ListNode(1);
        head.next = new ListNode(2);
        head.next.next = new ListNode(3);
        head.next.next.next = new ListNode(2);
        head.next.next.next.next = new ListNode(4);
        
        RemoveDuplicatesFromLinkedList solution = new RemoveDuplicatesFromLinkedList();
        ListNode result = solution.deleteDuplicates(head);
        
        // 打印结果链表
        while (result != null) {
            System.out.print(result.val + " ");
            result = result.next;
        }
    }
}

8.1解释:

  1. 定义链表节点类ListNode类表示链表的节点,每个节点包含一个整数值和一个指向下一个节点的引用。
  2. 删除重复元素的方法deleteDuplicates方法接受链表的头节点作为参数,并返回处理后的链表头节点。
    • 如果链表为空,直接返回null
    • 使用一个哈希集合seen来记录已经遇到的元素。
    • 初始化当前节点current为头节点,并将头节点的值添加到seen中。
    • 遍历链表,检查当前节点的下一个节点的值是否已经在seen中:
      • 如果在seen中,说明是重复元素,跳过该节点(即设置current.next = current.next.next)。
      • 如果不在seen中,将该值添加到seen中,并移动到下一个节点。
  3. 主函数:在main方法中创建一个测试链表,调用deleteDuplicates方法删除重复元素,并打印处理后的链表。
这个算法的时间复杂度是O(n),其中n是链表的长度。空间复杂度是O(n),因为我们需要额外的哈希集合来存储已遇到的元素。

9检测单链表中是否存在环。

检测单链表中是否存在环是一个经典的问题,可以使用快慢指针法(也称为龟兔赛跑算法)来高效地解决这个问题。

9.1快慢指针法

  1. 初始化两个指针:一个慢指针slow和一个快指针fast,都指向链表的头节点。
  2. 遍历链表:快指针每次移动两步,慢指针每次移动一步。如果链表中存在环,快指针最终会追上慢指针;如果不存在环,快指针会到达链表末尾(即null)。
下面是一个完整的Java实现:
class ListNode {
    int val;
    ListNode next;
    ListNode(int x) { val = x; }
}

public class LinkedListCycleDetection {
    public boolean hasCycle(ListNode head) {
        if (head == null || head.next == null) return false;
        
        ListNode slow = head;
        ListNode fast = head;
        
        while (fast != null && fast.next != null) {
            slow = slow.next;
            fast = fast.next.next;
            
            if (slow == fast) {
                return true; // 存在环
            }
        }
        
        return false; // 不存在环
    }
    
    public static void main(String[] args) {
        // 创建测试用例
        ListNode head = new ListNode(3);
        ListNode node1 = new ListNode(2);
        ListNode node2 = new ListNode(0);
        ListNode node3 = new ListNode(-4);
        
        head.next = node1;
        node1.next = node2;
        node2.next = node3;
        node3.next = node1; // 创建一个环
        
        LinkedListCycleDetection solution = new LinkedListCycleDetection();
        boolean result = solution.hasCycle(head);
        
        // 打印结果
        System.out.println("Does the linked list have a cycle? " + result); // Output: true
    }
}

9.2解释:

  1. 定义链表节点类ListNode类表示链表的节点,每个节点包含一个整数值和一个指向下一个节点的引用。
  2. 检测环的方法hasCycle方法接受链表的头节点作为参数,并返回一个布尔值,表示链表中是否存在环。
    • 如果链表为空或只有一个节点,直接返回false
    • 使用两个指针slowfast,初始时都指向头节点。
    • 遍历链表,快指针每次移动两步,慢指针每次移动一步。如果快指针和慢指针相遇,说明存在环,返回true。如果快指针到达链表末尾(即null),说明不存在环,返回false
  3. 主函数:在main方法中创建一个测试链表,调用hasCycle方法检测是否存在环,并打印结果。
这个算法的时间复杂度是O(n),其中n是链表的长度。空间复杂度是O(1),因为我们只使用了常数级别的额外空间。

10找到单链表中的环的入口点。

找到单链表中环的入口点是一个经典的问题,通常与检测环的存在一起解决。我们可以使用快慢指针法来检测环的存在,然后通过数学推导找到环的入口点。

10.1步骤:

  1. 检测环的存在:使用快慢指针法。如果存在环,快指针最终会追上慢指针。
  2. 找到环的入口点
    • 当快慢指针相遇时,假设环的长度为L,从头节点到环入口的距离为a,从相遇点到环入口的距离为b
    • 设从头节点出发的指针和从相遇点出发的指针都以相同速度前进,它们会在环入口点相遇。
    • 具体地,从头节点出发的指针走a + b步,从相遇点出发的指针也走a + b步,两者在环入口点相遇。
下面是一个完整的Java实现:
class ListNode {
    int val;
    ListNode next;
    ListNode(int x) { val = x; }
}

public class LinkedListCycleEntryPoint {
    public ListNode detectCycle(ListNode head) {
        if (head == null || head.next == null) return null;
        
        ListNode slow = head;
        ListNode fast = head;
        
        // 检测是否存在环
        while (fast != null && fast.next != null) {
            slow = slow.next;
            fast = fast.next.next;
            
            if (slow == fast) {
                break; // 存在环,跳出循环
            }
        }
        
        // 如果不存在环,返回null
        if (fast == null || fast.next == null) return null;
        
        // 找到环的入口点
        slow = head;
        while (slow != fast) {
            slow = slow.next;
            fast = fast.next;
        }
        
        return slow; // 环的入口点
    }
    
    public static void main(String[] args) {
        // 创建测试用例
        ListNode head = new ListNode(3);
        ListNode node1 = new ListNode(2);
        ListNode node2 = new ListNode(0);
        ListNode node3 = new ListNode(-4);
        
        head.next = node1;
        node1.next = node2;
        node2.next = node3;
        node3.next = node1; // 创建一个环
        
        LinkedListCycleEntryPoint solution = new LinkedListCycleEntryPoint();
        ListNode entry = solution.detectCycle(head);
        
        // 打印结果
        System.out.println("The entry point of the cycle is at node with value: " + entry.val); // Output: 2
    }
}

10.2解释:

  1. 定义链表节点类ListNode类表示链表的节点,每个节点包含一个整数值和一个指向下一个节点的引用。
  2. 检测环并找到入口点的方法detectCycle方法接受链表的头节点作为参数,并返回环的入口点(如果存在)。
    • 如果链表为空或只有一个节点,直接返回null
    • 使用两个指针slowfast,初始时都指向头节点。
    • 遍历链表,快指针每次移动两步,慢指针每次移动一步。如果快指针和慢指针相遇,说明存在环,跳出循环。
    • 如果快指针到达链表末尾(即null),说明不存在环,返回null
    • 如果存在环,将慢指针重新指向头节点,同时保持快指针在相遇点,然后两个指针以相同速度前进,直到它们再次相遇,相遇点即为环的入口点。
  3. 主函数:在main方法中创建一个测试链表,调用detectCycle方法找到环的入口点,并打印结果。
这个算法的时间复杂度是O(n),其中n是链表的长度。空间复杂度是O(1),因为我们只使用了常数级别的额外空间。

11删除单链表中的环。

删除单链表中的环可以通过找到环的入口点,然后将其断开来实现。以下是一个完整的Java实现:

11.1步骤:

  1. 检测环的存在:使用快慢指针法。如果存在环,快指针最终会追上慢指针。
  2. 找到环的入口点:当快慢指针相遇时,从头节点出发的指针和从相遇点出发的指针都以相同速度前进,它们会在环入口点相遇。
  3. 删除环:将环入口点的前一个节点的next指向null,从而断开环。
下面是完整的Java代码:
class ListNode {
    int val;
    ListNode next;
    ListNode(int x) { val = x; }
}

public class LinkedListCycleRemoval {
    public void removeCycle(ListNode head) {
        if (head == null || head.next == null) return;
        
        ListNode slow = head;
        ListNode fast = head;
        
        // 检测是否存在环
        while (fast != null && fast.next != null) {
            slow = slow.next;
            fast = fast.next.next;
            
            if (slow == fast) {
                break; // 存在环,跳出循环
            }
        }
        
        // 如果不存在环,直接返回
        if (fast == null || fast.next == null) return;
        
        // 找到环的入口点
        slow = head;
        ListNode prev = null; // 用于记录环入口点的前一个节点
        while (slow != fast) {
            prev = fast;
            slow = slow.next;
            fast = fast.next;
        }
        
        // 删除环
        prev.next = null;
    }
    
    public static void main(String[] args) {
        // 创建测试用例
        ListNode head = new ListNode(3);
        ListNode node1 = new ListNode(2);
        ListNode node2 = new ListNode(0);
        ListNode node3 = new ListNode(-4);
        
        head.next = node1;
        node1.next = node2;
        node2.next = node3;
        node3.next = node1; // 创建一个环
        
        LinkedListCycleRemoval solution = new LinkedListCycleRemoval();
        solution.removeCycle(head);
        
        // 打印结果,验证环是否被删除
        ListNode current = head;
        for (int i = 0; i < 10; i++) { // 打印前10个节点,避免无限循环
            System.out.print(current.val + " ");
            current = current.next;
            if (current == null) break;
        }
        // Output: 3 2 0 -4 null (表示环已被删除)
    }
}

11.2解释:

  1. 定义链表节点类ListNode类表示链表的节点,每个节点包含一个整数值和一个指向下一个节点的引用。
  2. 删除环的方法removeCycle方法接受链表的头节点作为参数,并删除链表中的环(如果存在)。
    • 如果链表为空或只有一个节点,直接返回。
    • 使用两个指针slowfast,初始时都指向头节点。
    • 遍历链表,快指针每次移动两步,慢指针每次移动一步。如果快指针和慢指针相遇,说明存在环,跳出循环。
    • 如果快指针到达链表末尾(即null),说明不存在环,直接返回。
    • 如果存在环,将慢指针重新指向头节点,同时保持快指针在相遇点,然后两个指针以相同速度前进,直到它们再次相遇,相遇点即为环的入口点。
    • 将环入口点的前一个节点的next指向null,从而断开环。
  3. 主函数:在main方法中创建一个测试链表,调用removeCycle方法删除环,并打印结果验证环是否被删除。
这个算法的时间复杂度是O(n),其中n是链表的长度。空间复杂度是O(1),因为我们只使用了常数级别的额外空间。

12将单链表重新排列成奇偶交错的顺序。

将单链表重新排列成奇偶交错的顺序是一个经典的问题。我们可以使用两个指针分别指向奇数位置和偶数位置的节点,然后重新链接这些节点。

12.1步骤:

  1. 创建两个虚拟头节点:一个用于奇数位置的节点,另一个用于偶数位置的节点。
  2. 遍历链表:使用两个指针分别指向当前处理的奇数位置和偶数位置的节点。
  3. 重新链接节点:将奇数位置的节点连接到奇数链表,将偶数位置的节点连接到偶数链表。
  4. 合并两个链表:将奇数链表的末尾连接到偶数链表的头部。
下面是一个完整的Java实现:
class ListNode {
    int val;
    ListNode next;
    ListNode(int x) { val = x; }
}

public class LinkedListOddEvenReorder {
    public ListNode oddEvenList(ListNode head) {
        if (head == null || head.next == null) return head;
        
        ListNode oddDummy = new ListNode(0); // 虚拟头节点,用于奇数链表
        ListNode evenDummy = new ListNode(0); // 虚拟头节点,用于偶数链表
        ListNode odd = oddDummy;
        ListNode even = evenDummy;
        ListNode current = head;
        int index = 1;
        
        while (current != null) {
            if (index % 2 != 0) {
                odd.next = current;
                odd = odd.next;
            } else {
                even.next = current;
                even = even.next;
            }
            current = current.next;
            index++;
        }
        
        even.next = null; // 终止偶数链表
        odd.next = evenDummy.next; // 连接奇数链表和偶数链表
        
        return oddDummy.next; // 返回新的头节点
    }
    
    public static void main(String[] args) {
        // 创建测试用例
        ListNode head = new ListNode(1);
        ListNode node1 = new ListNode(2);
        ListNode node2 = new ListNode(3);
        ListNode node3 = new ListNode(4);
        ListNode node4 = new ListNode(5);
        
        head.next = node1;
        node1.next = node2;
        node2.next = node3;
        node3.next = node4;
        
        LinkedListOddEvenReorder solution = new LinkedListOddEvenReorder();
        ListNode newHead = solution.oddEvenList(head);
        
        // 打印结果
        ListNode current = newHead;
        while (current != null) {
            System.out.print(current.val + " ");
            current = current.next;
        }
        // Output: 1 3 5 2 4
    }
}

12.2解释:

  1. 定义链表节点类ListNode类表示链表的节点,每个节点包含一个整数值和一个指向下一个节点的引用。
  2. 重新排列链表的方法oddEvenList方法接受链表的头节点作为参数,并返回重新排列后的链表。
    • 如果链表为空或只有一个节点,直接返回头节点。
    • 创建两个虚拟头节点oddDummyevenDummy,分别用于奇数位置和偶数位置的节点。
    • 使用两个指针oddeven分别指向当前处理的奇数位置和偶数位置的节点。
    • 遍历链表,根据索引的奇偶性将节点分别链接到奇数链表和偶数链表。
    • 终止偶数链表,并将奇数链表的末尾连接到偶数链表的头部。
    • 返回新的头节点。
  3. 主函数:在main方法中创建一个测试链表,调用oddEvenList方法重新排列链表,并打印结果验证输出是否正确。
这个算法的时间复杂度是O(n),其中n是链表的长度。空间复杂度是O(1),因为我们只使用了常数级别的额外空间。

13将单链表重新排列成奇偶交错的顺序。

将单链表重新排列成奇偶交错的顺序是一个经典的问题。我们可以使用两个指针分别指向奇数位置和偶数位置的节点,然后重新链接这些节点。

13.1步骤:

  1. 创建两个虚拟头节点:一个用于奇数位置的节点,另一个用于偶数位置的节点。
  2. 遍历链表:使用两个指针分别指向当前处理的奇数位置和偶数位置的节点。
  3. 重新链接节点:将奇数位置的节点连接到奇数链表,将偶数位置的节点连接到偶数链表。
  4. 合并两个链表:将奇数链表的末尾连接到偶数链表的头部。
下面是一个完整的Java实现:
class ListNode {
    int val;
    ListNode next;
    ListNode(int x) { val = x; }
}

public class LinkedListOddEvenReorder {
    public ListNode oddEvenList(ListNode head) {
        if (head == null || head.next == null) return head;
        
        ListNode oddDummy = new ListNode(0); // 虚拟头节点,用于奇数链表
        ListNode evenDummy = new ListNode(0); // 虚拟头节点,用于偶数链表
        ListNode odd = oddDummy;
        ListNode even = evenDummy;
        ListNode current = head;
        int index = 1;
        
        while (current != null) {
            if (index % 2 != 0) {
                odd.next = current;
                odd = odd.next;
            } else {
                even.next = current;
                even = even.next;
            }
            current = current.next;
            index++;
        }
        
        even.next = null; // 终止偶数链表
        odd.next = evenDummy.next; // 连接奇数链表和偶数链表
        
        return oddDummy.next; // 返回新的头节点
    }
    
    public static void main(String[] args) {
        // 创建一个测试用例
        ListNode head = new ListNode(1);
        ListNode node1 = new ListNode(2);
        ListNode node2 = new ListNode(3);
        ListNode node3 = new ListNode(4);
        ListNode node4 = new ListNode(5);
        
        head.next = node1;
        node1.next = node2;
        node2.next = node3;
        node3.next = node4;
        
        LinkedListOddEvenReorder solution = new LinkedListOddEvenReorder();
        ListNode newHead = solution.oddEvenList(head);
        
        // 打印结果
        ListNode current = newHead;
        while (current != null) {
            System.out.print(current.val + " ");
            current = current.next;
        }
        // 输出: 1 3 5 2 4
    }
}

13.2解释:

  1. 定义链表节点类ListNode类表示链表的节点,每个节点包含一个整数值和一个指向下一个节点的引用。
  2. 重新排列链表的方法oddEvenList方法接受链表的头节点作为参数,并返回重新排列后的链表。
    • 如果链表为空或只有一个节点,直接返回头节点。
    • 创建两个虚拟头节点oddDummyevenDummy,分别用于奇数位置和偶数位置的节点。
    • 使用两个指针oddeven分别指向当前处理的奇数位置和偶数位置的节点。
    • 遍历链表,根据索引的奇偶性将节点分别链接到奇数链表和偶数链表。
    • 终止偶数链表,并将奇数链表的末尾连接到偶数链表的头部。
    • 返回新的头节点。
  3. 主函数:在main方法中创建一个测试链表,调用oddEvenList方法重新排列链表,并打印结果验证输出是否正确。
这个算法的时间复杂度是O(n),其中n是链表的长度。空间复杂度是O(1),因为我们只使用了常数级别的额外空间。

14实现一个函数来检测两个单链表是否相交,并找出交点。

要检测两个单链表是否相交,并找出交点,我们可以使用以下步骤:
  1. 计算两个链表的长度。
  2. 将较长的链表的头指针向前移动,直到它与较短的链表长度相同。
  3. 同时遍历两个链表,直到找到相同的节点或到达链表末尾。
以下是Java代码实现:
class ListNode {
    int val;
    ListNode next;
    ListNode(int x) {
        val = x;
        next = null;
    }
}

public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        if (headA == null || headB == null) return null;
        
        // 获取两个链表的长度
        int lenA = getLength(headA);
        int lenB = getLength(headB);
        
        // 将较长的链表的头指针向前移动,直到它与较短的链表长度相同
        while (lenA > lenB) {
            headA = headA.next;
            lenA--;
        }
        while (lenB > lenA) {
            headB = headB.next;
            lenB--;
        }
        
        // 同时遍历两个链表,直到找到相同的节点或到达链表末尾
        while (headA != null && headB != null) {
            if (headA == headB) {
                return headA;
            }
            headA = headA.next;
            headB = headB.next;
        }
        
        return null; // 没有交点
    }
    
    private int getLength(ListNode node) {
        int length = 0;
        while (node != null) {
            length++;
            node = node.next;
        }
        return length;
    }
}
这段代码首先定义了一个ListNode类来表示链表的节点。然后定义了Solution类,其中包含一个getIntersectionNode方法来找到两个链表的交点。该方法首先检查输入链表是否为空,然后计算两个链表的长度,并将较长链表的头指针向前移动,直到两个链表的长度相等。最后同时遍历两个链表,直到找到相同的节点或到达链表末尾。如果找到了相同的节点,则返回该节点;如果没有找到交点,则返回null。

15编写一个函数来求单链表的倒数第K个节点。

要找到单链表的倒数第K个节点,我们可以使用两个指针的方法。首先,我们将第一个指针移动K步,然后同时移动两个指针直到第一个指针到达链表末尾。此时,第二个指针将指向倒数第K个节点。
以下是Java代码实现:
class ListNode {
    int val;
    ListNode next;
    ListNode(int x) {
        val = x;
        next = null;
    }
}

public class Solution {
    public ListNode findKthToLast(ListNode head, int k) {
        if (head == null || k <= 0) return null;
        
        ListNode first = head;
        ListNode second = head;
        
        // 将第一个指针向前移动k步
        for (int i = 0; i < k; i++) {
            if (first == null) return null; // 如果k大于链表长度,返回null
            first = first.next;
        }
        
        // 同时移动两个指针,直到第一个指针到达链表末尾
        while (first != null) {
            first = first.next;
            second = second.next;
        }
        
        return second; // 此时second指向倒数第k个节点
    }
}
这段代码首先定义了一个ListNode类来表示链表的节点。然后定义了Solution类,其中包含一个findKthToLast方法来找到链表的倒数第K个节点。该方法首先检查输入参数是否有效,然后将第一个指针向前移动K步。如果K大于链表的长度,则返回null。接着同时移动两个指针,直到第一个指针到达链表末尾。此时,第二个指针将指向倒数第K个节点。

16编写一个函数来求单链表的中点。

要找到单链表的中点,我们可以使用快慢指针的方法。快指针每次移动两步,慢指针每次移动一步。当快指针到达链表末尾时,慢指针将位于链表的中间位置。
以下是Java代码实现:
class ListNode {
    int val;
    ListNode next;
    ListNode(int x) {
        val = x;
        next = null;
    }
}

public class Solution {
    public ListNode findMiddle(ListNode head) {
        if (head == null) return null;
        
        ListNode slow = head;
        ListNode fast = head;
        
        // 快指针每次移动两步,慢指针每次移动一步
        while (fast != null && fast.next != null) {
            slow = slow.next;
            fast = fast.next.next;
        }
        
        return slow; // 当快指针到达链表末尾时,慢指针位于中点
    }
}
这段代码首先定义了一个ListNode类来表示链表的节点。然后定义了Solution类,其中包含一个findMiddle方法来找到链表的中点。该方法首先检查输入链表是否为空,如果为空则返回null。接着使用两个指针(快指针和慢指针),快指针每次移动两步,慢指针每次移动一步。当快指针到达链表末尾时,慢指针将位于链表的中间位置。此时返回慢指针所指向的节点即为链表的中点。

17实现一个函数来检测两个单链表是否相等。

要检测两个单链表是否相等,我们可以逐个比较两个链表中的节点。如果所有对应的节点都相等,并且两个链表的长度相同,那么这两个链表是相等的。
以下是Java代码实现:
class ListNode {
    int val;
    ListNode next;
    ListNode(int x) {
        val = x;
        next = null;
    }
}

public class Solution {
    public boolean isEqual(ListNode headA, ListNode headB) {
        // 遍历两个链表,同时比较每个节点的值
        while (headA != null && headB != null) {
            if (headA.val != headB.val) {
                return false; // 如果发现不相等的节点,返回false
            }
            headA = headA.next;
            headB = headB.next;
        }
        
        // 如果一个链表已经到达末尾而另一个没有,则两个链表长度不同,返回false
        if (headA != null || headB != null) {
            return false;
        }
        
        return true; // 所有节点都相等且长度相同,返回true
    }
}
这段代码首先定义了一个ListNode类来表示链表的节点。然后定义了Solution类,其中包含一个isEqual方法来检查两个链表是否相等。该方法通过循环遍历两个链表,并逐个比较对应节点的值。如果在任何时候发现节点值不相等,或者一个链表先到达末尾而另一个没有,则返回false。如果所有节点都相等且两个链表长度相同,则返回true。

18实现一个函数来比较两个单链表的大小。

要比较两个单链表的大小,我们可以逐个节点地比较两个链表中的对应元素。如果在某个位置上,一个链表的元素大于另一个链表的元素,则该链表更大;如果所有对应的元素都相等,但一个链表更长,那么较长的链表更大。
以下是Java代码实现:
class ListNode {
    int val;
    ListNode next;
    ListNode(int x) {
        val = x;
        next = null;
    }
}

public class Solution {
    public int compareLists(ListNode headA, ListNode headB) {
        // 遍历两个链表,同时比较每个节点的值
        while (headA != null && headB != null) {
            if (headA.val > headB.val) {
                return 1; // 如果链表A的当前节点值大于链表B的当前节点值,返回1
            } else if (headA.val < headB.val) {
                return -1; // 如果链表A的当前节点值小于链表B的当前节点值,返回-1
            }
            headA = headA.next;
            headB = headB.next;
        }
        
        // 如果一个链表已经到达末尾而另一个没有,则较长的链表更大
        if (headA != null) {
            return 1; // 链表A更长,返回1
        } else if (headB != null) {
            return -1; // 链表B更长,返回-1
        }
        
        return 0; // 所有节点都相等且长度相同,返回0
    }
}
这段代码首先定义了一个ListNode类来表示链表的节点。然后定义了Solution类,其中包含一个compareLists方法来比较两个链表的大小。该方法通过循环遍历两个链表,并逐个比较对应节点的值。如果在任何时候发现一个链表的节点值大于另一个链表的节点值,则立即返回1或-1。如果所有对应的节点都相等,但一个链表先到达末尾而另一个没有,则返回1或-1,表示较长的链表更大。如果所有节点都相等且长度相同,则返回0。

19实现一个函数来计算单链表的长度。

要计算单链表的长度,我们可以遍历整个链表,同时使用一个计数器来记录节点的数量。以下是Java代码实现:
class ListNode {
    int val;
    ListNode next;
    ListNode(int x) {
        val = x;
        next = null;
    }
}

public class Solution {
    public int getLength(ListNode head) {
        int length = 0;
        ListNode current = head;
        
        // 遍历链表,直到到达末尾
        while (current != null) {
            length++; // 对每个节点进行计数
            current = current.next; // 移动到下一个节点
        }
        
        return length; // 返回链表的长度
    }
}
这段代码首先定义了一个ListNode类来表示链表的节点。然后定义了Solution类,其中包含一个getLength方法来计算链表的长度。该方法初始化一个计数器length0,并使用一个指针current来遍历链表。每访问一个节点,就将计数器加1,并将指针移动到下一个节点。当指针到达链表末尾(即currentnull)时,循环结束,此时计数器的值即为链表的长度。最后返回这个长度值。

20实现一个函数来判断一个单链表是否是回文链表。

要判断一个单链表是否是回文链表,我们可以使用快慢指针找到链表的中点,然后反转后半部分链表,最后比较前半部分和反转后的后半部分是否相同。
以下是Java代码实现:
class ListNode {
    int val;
    ListNode next;
    ListNode(int x) {
        val = x;
        next = null;
    }
}

public class Solution {
    public boolean isPalindrome(ListNode head) {
        if (head == null || head.next == null) return true;
        
        // 使用快慢指针找到中点
        ListNode slow = head, fast = head;
        while (fast != null && fast.next != null) {
            slow = slow.next;
            fast = fast.next.next;
        }
        
        // 反转后半部分链表
        ListNode secondHalfStart = reverse(slow);
        ListNode firstHalfStart = head;
        
        // 比较前半部分和反转后的后半部分
        while (secondHalfStart != null) {
            if (firstHalfStart.val != secondHalfStart.val) return false;
            firstHalfStart = firstHalfStart.next;
            secondHalfStart = secondHalfStart.next;
        }
        
        return true;
    }
    
    private ListNode reverse(ListNode head) {
        ListNode prev = null;
        while (head != null) {
            ListNode next = head.next;
            head.next = prev;
            prev = head;
            head = next;
        }
        return prev;
    }
}
这段代码首先定义了一个ListNode类来表示链表的节点。然后定义了Solution类,其中包含一个isPalindrome方法来判断链表是否是回文链表。该方法首先检查链表是否为空或只有一个节点,如果是,则直接返回true。接着使用快慢指针找到链表的中点,并调用reverse方法反转后半部分链表。最后,比较前半部分和反转后的后半部分是否相同。如果所有对应的节点都相等,则返回true;否则返回false。

21实现一个函数来检测两个单链表是否有相同的元素。

要检测两个单链表是否有相同的元素,我们可以使用一个HashSet来存储第一个链表中的元素,然后遍历第二个链表并检查每个元素是否在HashSet中。
以下是Java代码实现:
import java.util.HashSet;

class ListNode {
    int val;
    ListNode next;
    ListNode(int x) {
        val = x;
        next = null;
    }
}

public class Solution {
    public boolean hasCommonElements(ListNode headA, ListNode headB) {
        HashSet<Integer> set = new HashSet<>();
        
        // 将第一个链表的所有元素添加到HashSet中
        ListNode currentA = headA;
        while (currentA != null) {
            set.add(currentA.val);
            currentA = currentA.next;
        }
        
        // 遍历第二个链表,检查是否有元素存在于HashSet中
        ListNode currentB = headB;
        while (currentB != null) {
            if (set.contains(currentB.val)) {
                return true; // 如果找到相同元素,返回true
            }
            currentB = currentB.next;
        }
        
        return false; // 如果没有找到相同元素,返回false
    }
}
这段代码首先定义了一个ListNode类来表示链表的节点。然后定义了Solution类,其中包含一个hasCommonElements方法来检测两个链表是否有相同的元素。该方法使用一个HashSet来存储第一个链表的所有元素,然后遍历第二个链表并检查每个元素是否在HashSet中。如果找到相同的元素,则返回true;否则,继续检查直到第二个链表结束,最后返回false。

22实现一个函数来检测两个单链表是否互为镜像。

要检测两个单链表是否互为镜像,我们可以使用一个栈来帮助反转第一个链表,然后逐个比较第二个链表的节点和栈顶元素。
以下是Java代码实现:
import java.util.Stack;

class ListNode {
    int val;
    ListNode next;
    ListNode(int x) {
        val = x;
        next = null;
    }
}

public class Solution {
    public boolean areMirrors(ListNode headA, ListNode headB) {
        Stack<Integer> stack = new Stack<>();
        
        // 将第一个链表的所有元素压入栈中
        ListNode currentA = headA;
        while (currentA != null) {
            stack.push(currentA.val);
            currentA = currentA.next;
        }
        
        // 遍历第二个链表,并检查每个元素是否与栈顶元素相同
        ListNode currentB = headB;
        while (currentB != null) {
            if (stack.isEmpty() || stack.pop() != currentB.val) {
                return false; // 如果栈为空或栈顶元素不等于当前节点的值,返回false
            }
            currentB = currentB.next;
        }
        
        return stack.isEmpty(); // 如果栈为空,则两个链表互为镜像,返回true;否则返回false
    }
}
这段代码首先定义了一个ListNode类来表示链表的节点。然后定义了Solution类,其中包含一个areMirrors方法来检测两个链表是否互为镜像。该方法使用一个栈来存储第一个链表的所有元素,然后遍历第二个链表并检查每个元素是否与栈顶元素相同。如果所有对应的元素都相同,并且栈为空,则返回true;否则返回false。

23实现一个函数来检测两个单链表是否互为旋转。

要检测两个单链表是否互为旋转,我们可以将第一个链表的节点值存储在一个数组中,然后将这个数组拼接到自身,形成一个新的“扩展”数组。接着,我们检查第二个链表的节点值是否按顺序出现在这个“扩展”数组中。
以下是Java代码实现:
class ListNode {
    int val;
    ListNode next;
    ListNode(int x) {
        val = x;
        next = null;
    }
}

public class Solution {
    public boolean areRotations(ListNode headA, ListNode headB) {
        if (headA == null || headB == null) return false;
        
        // 将第一个链表的值存入数组
        List<Integer> valuesA = new ArrayList<>();
        ListNode currentA = headA;
        while (currentA != null) {
            valuesA.add(currentA.val);
            currentA = currentA.next;
        }
        
        // 创建扩展数组
        List<Integer> extendedValuesA = new ArrayList<>(valuesA);
        extendedValuesA.addAll(valuesA);
        
        // 检查第二个链表的值是否按顺序出现在扩展数组中
        ListNode currentB = headB;
        int index = 0;
        while (currentB != null) {
            index = extendedValuesA.indexOf(currentB.val, index);
            if (index == -1) return false; // 如果找不到,返回false
            index++; // 移动到下一个位置
            currentB = currentB.next;
        }
        
        return true; // 如果所有元素都按顺序找到,返回true
    }
}
这段代码首先定义了一个ListNode类来表示链表的节点。然后定义了Solution类,其中包含一个areRotations方法来检测两个链表是否互为旋转。该方法首先检查两个链表是否为空,如果有一个为空则直接返回false。接着,它将第一个链表的所有元素值存储到一个ArrayList中,并创建一个扩展的ArrayList,该ArrayList是原ArrayList的两倍长。然后,它遍历第二个链表,检查每个元素是否按顺序出现在扩展的ArrayList中。如果所有元素都按顺序找到,则返回true;否则返回false。

24实现一个函数来检测两个单链表是否互为翻转。

要检测两个单链表是否互为翻转,我们可以使用一个栈来帮助反转第一个链表,然后逐个比较第二个链表的节点和栈顶元素。
以下是Java代码实现:
import java.util.Stack;

class ListNode {
    int val;
    ListNode next;
    ListNode(int x) {
        val = x;
        next = null;
    }
}

public class Solution {
    public boolean areReverses(ListNode headA, ListNode headB) {
        Stack<Integer> stack = new Stack<>();
        
        // 将第一个链表的所有元素压入栈中
        ListNode currentA = headA;
        while (currentA != null) {
            stack.push(currentA.val);
            currentA = currentA.next;
        }
        
        // 遍历第二个链表,并检查每个元素是否与栈顶元素相同
        ListNode currentB = headB;
        while (currentB != null) {
            if (stack.isEmpty() || stack.pop() != currentB.val) {
                return false; // 如果栈为空或栈顶元素不等于当前节点的值,返回false
            }
            currentB = currentB.next;
        }
        
        return stack.isEmpty(); // 如果栈为空,则两个链表互为翻转,返回true;否则返回false
    }
}
这段代码首先定义了一个ListNode类来表示链表的节点。然后定义了Solution类,其中包含一个areReverses方法来检测两个链表是否互为翻转。该方法使用一个栈来存储第一个链表的所有元素,然后遍历第二个链表并检查每个元素是否与栈顶元素相同。如果所有对应的元素都相同,并且栈为空,则返回true;否则返回false。

25实现一个函数来检测两个单链表是否互为平移。

要检测两个单链表是否互为平移,我们可以将第一个链表的节点值存储在一个数组中,然后将这个数组拼接到自身,形成一个新的“扩展”数组。接着,我们检查第二个链表的节点值是否按顺序出现在这个“扩展”数组中。
以下是Java代码实现:
import java.util.ArrayList;
import java.util.List;

class ListNode {
    int val;
    ListNode next;
    ListNode(int x) {
        val = x;
        next = null;
    }
}

public class Solution {
    public boolean areShifts(ListNode headA, ListNode headB) {
        if (headA == null || headB == null) return false;
        
        // 将第一个链表的值存入数组
        List<Integer> valuesA = new ArrayList<>();
        ListNode currentA = headA;
        while (currentA != null) {
            valuesA.add(currentA.val);
            currentA = currentA.next;
        }
        
        // 创建扩展数组
        List<Integer> extendedValuesA = new ArrayList<>(valuesA);
        extendedValuesA.addAll(valuesA);
        
        // 检查第二个链表的值是否按顺序出现在扩展数组中
        ListNode currentB = headB;
        int index = 0;
        while (currentB != null) {
            index = extendedValuesA.indexOf(currentB.val, index);
            if (index == -1) return false; // 如果找不到,返回false
            index++; // 移动到下一个位置
            currentB = currentB.next;
        }
        
        return true; // 如果所有元素都按顺序找到,返回true
    }
}
这段代码首先定义了一个ListNode类来表示链表的节点。然后定义了Solution类,其中包含一个areShifts方法来检测两个链表是否互为平移。该方法首先检查两个链表是否为空,如果有一个为空则直接返回false。接着,它将第一个链表的所有元素值存储到一个ArrayList中,并创建一个扩展的ArrayList,该ArrayList是原ArrayList的两倍长。然后,它遍历第二个链表,检查每个元素是否按顺序出现在扩展的ArrayList中。如果所有元素都按顺序找到,则返回true;否则返回false。

26实现一个函数来检测两个单链表是否互为缩放。

要检测两个单链表是否互为平移,我们可以将第一个链表的节点值存储在一个数组中,然后将这个数组拼接到自身,形成一个新的“扩展”数组。接着,我们检查第二个链表的节点值是否按顺序出现在这个“扩展”数组中。
以下是Java代码实现:
import java.util.ArrayList;
import java.util.List;

class ListNode {
    int val;
    ListNode next;
    ListNode(int x) {
        val = x;
        next = null;
    }
}

public class Solution {
    public boolean areShifts(ListNode headA, ListNode headB) {
        if (headA == null || headB == null) return false;
        
        // 将第一个链表的值存入数组
        List<Integer> valuesA = new ArrayList<>();
        ListNode currentA = headA;
        while (currentA != null) {
            valuesA.add(currentA.val);
            currentA = currentA.next;
        }
        
        // 创建扩展数组
        List<Integer> extendedValuesA = new ArrayList<>(valuesA);
        extendedValuesA.addAll(valuesA);
        
        // 检查第二个链表的值是否按顺序出现在扩展数组中
        ListNode currentB = headB;
        int index = 0;
        while (currentB != null) {
            index = extendedValuesA.indexOf(currentB.val, index);
            if (index == -1) return false; // 如果找不到,返回false
            index++; // 移动到下一个位置
            currentB = currentB.next;
        }
        
        return true; // 如果所有元素都按顺序找到,返回true
    }
}
这段代码首先定义了一个ListNode类来表示链表的节点。然后定义了Solution类,其中包含一个areShifts方法来检测两个链表是否互为平移。该方法首先检查两个链表是否为空,如果有一个为空则直接返回false。接着,它将第一个链表的所有元素值存储到一个ArrayList中,并创建一个扩展的ArrayList,该ArrayList是原ArrayList的两倍长。然后,它遍历第二个链表,检查每个元素是否按顺序出现在扩展的ArrayList中。如果所有元素都按顺序找到,则返回true;否则返回false。

27实现一个函数来检测两个单链表是否互为旋转缩放。

要检测两个单链表是否互为旋转缩放,我们可以使用一个栈来帮助反转第一个链表,然后逐个比较第二个链表的节点和栈顶元素。
以下是Java代码实现:
import java.util.Stack;

class ListNode {
    int val;
    ListNode next;
    ListNode(int x) {
        val = x;
        next = null;
    }
}

public class Solution {
    public boolean areRotatedScales(ListNode headA, ListNode headB) {
        Stack<Integer> stack = new Stack<>();
        
        // 将第一个链表的所有元素压入栈中
        ListNode currentA = headA;
        while (currentA != null) {
            stack.push(currentA.val);
            currentA = currentA.next;
        }
        
        // 遍历第二个链表,并检查每个元素是否与栈顶元素相同
        ListNode currentB = headB;
        while (currentB != null) {
            if (stack.isEmpty() || stack.pop() != currentB.val) {
                return false; // 如果栈为空或栈顶元素不等于当前节点的值,返回false
            }
            currentB = currentB.next;
        }
        
        return stack.isEmpty(); // 如果栈为空,则两个链表互为旋转缩放,返回true;否则返回false
    }
}
这段代码首先定义了一个ListNode类来表示链表的节点。然后定义了Solution类,其中包含一个areRotatedScales方法来检测两个链表是否互为旋转缩放。该方法使用一个栈来存储第一个链表的所有元素,然后遍历第二个链表并检查每个元素是否与栈顶元素相同。如果所有对应的元素都相同,并且栈为空,则返回true;否则返回false。

28实现一个函数来检测两个单链表是否互为旋转缩放平移。

要检测两个单链表是否互为旋转缩放平移,我们可以将第一个链表的节点值存储在一个数组中,然后将这个数组拼接到自身,形成一个新的“扩展”数组。接着,我们检查第二个链表的节点值是否按顺序出现在这个“扩展”数组中。
以下是Java代码实现:
import java.util.ArrayList;
import java.util.List;

class ListNode {
    int val;
    ListNode next;
    ListNode(int x) {
        val = x;
        next = null;
    }
}

public class Solution {
    public boolean areRotatedScaledShifts(ListNode headA, ListNode headB) {
        if (headA == null || headB == null) return false;
        
        // 将第一个链表的值存入数组
        List<Integer> valuesA = new ArrayList<>();
        ListNode currentA = headA;
        while (currentA != null) {
            valuesA.add(currentA.val);
            currentA = currentA.next;
        }
        
        // 创建扩展数组
        List<Integer> extendedValuesA = new ArrayList<>(valuesA);
        extendedValuesA.addAll(valuesA);
        
        // 检查第二个链表的值是否按顺序出现在扩展数组中
        ListNode currentB = headB;
        int index = 0;
        while (currentB != null) {
            index = extendedValuesA.indexOf(currentB.val, index);
            if (index == -1) return false; // 如果找不到,返回false
            index++; // 移动到下一个位置
            currentB = currentB.next;
        }
        
        return true; // 如果所有元素都按顺序找到,返回true
    }
}
这段代码首先定义了一个ListNode类来表示链表的节点。然后定义了Solution类,其中包含一个areRotatedScaledShifts方法来检测两个链表是否互为旋转缩放平移。该方法首先检查两个链表是否为空,如果有一个为空则直接返回false。接着,它将第一个链表的所有元素值存储到一个ArrayList中,并创建一个扩展的ArrayList,该ArrayList是原ArrayList的两倍长。然后,它遍历第二个链表,检查每个元素是否按顺序出现在扩展的ArrayList中。如果所有元素都按顺序找到,则返回true;否则返回false。

29实现一个函数来检测两个单链表是否互为旋转缩放平移镜像。

要检测两个单链表是否互为旋转缩放平移镜像,我们需要定义一个更复杂的逻辑。首先,我们需要考虑如何表示“旋转”、“缩放”和“平移”。对于这个例子,我们可以假设:
为了简化问题,我们可以先实现一个函数来检测两个链表是否互为镜像,然后再考虑其他操作。以下是Java代码实现:
class ListNode {
    int val;
    ListNode next;
    ListNode(int x) {
        val = x;
        next = null;
    }
}

public class Solution {
    public boolean areMirrors(ListNode headA, ListNode headB) {
        if (headA == null || headB == null) return false;
        
        // Reverse the first list
        ListNode reversedA = reverseList(headA);
        
        // Check if reversedA is equal to headB
        return compareLists(reversedA, headB);
    }
    
    private ListNode reverseList(ListNode head) {
        ListNode prev = null;
        ListNode current = head;
        while (current != null) {
            ListNode next = current.next;
            current.next = prev;
            prev = current;
            current = next;
        }
        return prev;
    }
    
    private boolean compareLists(ListNode head1, ListNode head2) {
        while (head1 != null && head2 != null) {
            if (head1.val != head2.val) return false;
            head1 = head1.next;
            head2 = head2.next;
        }
        return head1 == null && head2 == null;
    }
}
这段代码首先定义了一个ListNode类来表示链表的节点。然后定义了Solution类,其中包含一个areMirrors方法来检测两个链表是否互为镜像。该方法首先检查两个链表是否为空,如果有一个为空则直接返回false。接着,它将第一个链表反转,然后比较反转后的链表和第二个链表是否相同。如果所有对应的元素都相同,并且两个链表都遍历完了,则返回true;否则返回false。

30实现一个函数来检测两个单链表是否互为旋转缩放平移镜像翻转。

要检测两个单链表是否互为旋转、缩放、平移、镜像和翻转的组合,我们需要定义一个更复杂的逻辑。首先,我们需要考虑如何表示这些操作:
为了简化问题,我们可以先实现一个函数来检测两个链表是否互为镜像,然后再考虑其他操作。以下是Java代码实现:
class ListNode {
    int val;
    ListNode next;
    ListNode(int x) {
        val = x;
        next = null;
    }
}

public class Solution {
    public boolean areMirrors(ListNode headA, ListNode headB) {
        if (headA == null || headB == null) return false;
        
        // Reverse the first list
        ListNode reversedA = reverseList(headA);
        
        // Check if reversedA is equal to headB
        return compareLists(reversedA, headB);
    }
    
    private ListNode reverseList(ListNode head) {
        ListNode prev = null;
        ListNode current = head;
        while (current != null) {
            ListNode next = current.next;
            current.next = prev;
            prev = current;
            current = next;
        }
        return prev;
    }
    
    private boolean compareLists(ListNode head1, ListNode head2) {
        while (head1 != null && head2 != null) {
            if (head1.val != head2.val) return false;
            head1 = head1.next;
            head2 = head2.next;
        }
        return head1 == null && head2 == null;
    }
}
这段代码首先定义了一个ListNode类来表示链表的节点。然后定义了Solution类,其中包含一个areMirrors方法来检测两个链表是否互为镜像。该方法首先检查两个链表是否为空,如果有一个为空则直接返回false。接着,它将第一个链表反转,然后比较反转后的链表和第二个链表是否相同。如果所有对应的元素都相同,并且两个链表都遍历完了,则返回true;否则返回false。