数据结构与算法 —— 链表:环形链表、反转链表、合并两个有序链表(Java实现)

定义一个单链表

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;
	}
}
A&F
发布了14 篇原创文章 · 获赞 3 · 访问量 4942

猜你喜欢

转载自blog.csdn.net/lovetechlovelife/article/details/102639905