定义一个单链表
ListNode为下文代码中用到的类。
class ListNode {
int val;
ListNode next;
public ListNode(int x) {
this.val = x;
}
}
1. 环形链表
问题:给你一个链表,如何通过O(1)的空间复杂度检测链表中是否存在环。
Leecode:linked-list-cycle
思路:使用两个指针slow和fast,slow每次向前走一步,fast每次向前走两步,如果slow和fast相遇,则表明链表中有环,否则链表中没有环。
代码实现:
public static boolean hasCycle2(ListNode head) {
if (head == null || head.next == null) return false;
ListNode slow = head; //慢指针
ListNode fast = head.next; //快指针
//判断慢指针是否与快指针相等
while (slow != fast) {
if (fast == null || fast.next == null) return false;
slow = slow.next; //慢指针每次走一步
fast = fast.next.next; //快指针每次走两步
}
return true;
}
2. 反转链表
问题:反转一个单链表。
Leetcode:reverse-linked-list
思路:初始化两个节点pre(前一个结点)和curr(当前结点),pre指向null,curr指向链表头结点。遍历链表,首先将链表头节点指向pre,也就是指向null,之后pre和curr每次都向后移动一个结点,并将curr的next指针指向pre,直到遍历完整个链表为止。
代码实现:
public static ListNode reverseList(ListNode head) {
if(head == null) return head;
ListNode pre = null; //前一个结点
ListNode curr = head; //当前结点
ListNode tmp = null; //临时变量
while (curr != null) {
tmp = curr.next; //将当前结点的next赋值给一个临时变量
curr.next = pre; //将当前结点的next反向指向pre
pre = curr; //pre向前走一步
curr = tmp; //curr向前走一步
}
return pre;
}
3. 合并两个有序链表
问题:合并两个有序链表,并返回新链表。
LeetCode:merge-two-sorted-lists
思路:因为两个链表都是有序,所以我们只需要从链表的头结点开始,依次在两个链表中拿出一个结点l1和l2,并比较两个结点值的大小,如果l1的值小于等于l2的值,那么就把l1的next指针指向l2,否则就把l2的next指针指向l1。为了实现O(1)的空间复杂度,推荐使用递归的方式。
代码实现:
public static ListNode mergeTwoLists(ListNode l1, ListNode l2) {
//如果其中一个链表为null, 直接返回另外一个链表
if (l1 == null) return l2;
if (l2 == null) return l1;
//如果l1的值小于等于l2的值, 就取l1的next结点继续比较
if (l1.val <= l2.val) {
l1.next = mergeTwoLists(l1.next, l2); //递归调用
return l1;
} else {//如果l1的值大于l2的值, 就取l2的next结点继续比较
l2.next = mergeTwoLists(l1, l2.next); //递归调用
return l2;
}
}