19

LeetCode 链表题 ( Java )

 4 years ago
source link: http://www.cnblogs.com/lyuzt/p/11962759.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

leetcode 237. 删除链表中的节点

链接: https://leetcode-cn.com/problems/delete-node-in-a-linked-list/

示例 :

输入: head = [4,5,1,9], node = 5
输出: [4,1,9]
解释: 给定你链表中值为 5 的第二个节点,那么在调用了你的函数之后,该链表应变为 4 -> 1 -> 9.

这道题比较简单, 修改之前节点的  next 指针,使其指向之后的节点

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public void deleteNode(ListNode node) {
        node.val = node.next.val;
        node.next = node.next.next;
    }
}

leetcode 160. 相交链表

链接: https://leetcode-cn.com/problems/intersection-of-two-linked-lists/

编写一个程序,找到两个单链表相交的起始节点。

如下面的两个链表:

aYnYryJ.png!web

在节点 c1 开始相交。要求返回 c1 这个节点。

先得到两条链表的长度差 offset,再将长链表跳过 offset 个节点,然后再让这两个链表轮流逐个遍历节点,直到相遇。

比如上图 A 和 B 差一个长度差为 1,先跳过 b1 这个结点到达 b2,然后 A 开始从 a1 遍历,到达 a2, B 到达 b3; 随后 A 到达 c1,B 到达 c1,两点相遇,返回 c1.

public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        if(headA == null || headB == null)
            return null;

        int lengthA = getListLength(headA);
        int lengthB = getListLength(headB);
        ListNode longList = headA;
        ListNode shortList = headB;
        int offset = Math.abs(lengthA - lengthB);
        if(lengthA < lengthB){
            longList = headB;
            shortList = headA;
        }
        for(int i=0; i < offset; i++){
            longList = longList.next;
        }
        while(shortList != longList){
            shortList = shortList.next;
            longList = longList.next;
        }
        return shortList;
    }
    public int getListLength(ListNode p){
        int length = 0;
        while(p != null){
            length++;
            p = p.next;
        }
        return length;
    }
}

我又看了这道题的题解,看到有其他解法:两条链表先遍历一轮(消除长度差),当链表到达结尾的时候,反而让到达链表末尾的节点指向另一个链表的头部,然后再接着遍历,这样就消除了两条链表的长度差,可以大致理解为: 两个人以同样的速度跑步,跑的路程也一致,那么肯定会同一个时间点到达终点。

public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
    if (headA == null || headB == null) return null;
    ListNode pA = headA, pB = headB;
    while (pA != pB) {
        pA = pA == null ? headB : pA.next;
        pB = pB == null ? headA : pB.next;
    }
    return pA;
}

leetcode 206. 反转链表

示例:

输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL

此题的思路是 逐个反转,先变成 NULL<-1  2->3->4->5->NULL; 然后是 1<-2  3->4->5->NULL; 接着是 1<-2<-3  4->5->NULL,以此类推。那么我们首先就要先创建一个空节点为 prev,使得 1 指向它,但是,需要先把 2 这个节点保存起来,不然当 1 指向 NULL 后就失去了 2 以后的数据。完成第一次反转后就一直迭代下去。 可能表达得不太行,看代码吧:

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode reverseList(ListNode head) {
        ListNode prev = null;
        while(head != null) {
            ListNode next = head.next;
            head.next = prev;           // 翻转
            
            prev = head;
            head = next;
        }
        return prev;
    }
}

如果文字解释看不懂,代码也看不懂,那就视频吧,推荐这个小姐姐讲的   用Java解决翻转链表 Leetcode206 Reverse Linked List  

leetcode 141. 环形链表

给定一个链表,判断链表中是否有环。

为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。

示例 1:

输入:head = [3,2,0,-4], pos = 1
输出:true
解释:链表中有一个环,其尾部连接到第二个节点。

RBrUfe6.png!web

示例 3:

输入:head = [1], pos = -1
输出:false
解释:链表中没有环。

JZ7BVba.png!web

QRzaUrV.png!web

(1) 哈希

遇到这种类型得题目一般大部分都是用 hash , 通过遍历把每个节点存起来,如果该节点后续还被访问到,则表示该链表为环形链表。

public boolean hasCycle(ListNode head) {
    Set<ListNode> nodes = new HashSet<>();
    while (head != null) {
        if (nodes.contains(head)) {
            return true;
        } else {
            nodes.add(head);
        }
        head = head.next;
    }
    return false;
}

(2)双指针

定义两个指针,从 head 开始,慢指针移动一步,快指针移动两步,如果两个指针相遇则为环形链表,否则不是。这个道理就跟两个不同速度的人在同一条跑道上跑步一样,如果是环形的总会相遇。

public boolean hasCycle(ListNode head) {
        if (head == null || head.next == null)
            return false;
        ListNode slow = head;
        ListNode fast = head.next;
        while(fast != null && fast.next != null) {
            if (slow == fast){
                return true;
            }
            slow = slow.next;
            fast = fast.next.next;
        }
        return false;
    }

leetcode 19. 删除链表的倒数第N个节点

给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。

示例:

给定一个链表: 1->2->3->4->5, 和 n = 2.

当删除了倒数第二个节点后,链表变为 1->2->3->5.

(1)第一种方法:由于不清楚链表的长度,因此可以先遍历链表得到其长度,然后第二次遍历将倒数第N个节点删除,即被删除节点的前一个节点指向删除节点的后一个节点:

public ListNode removeNthFromEnd(ListNode head, int n) {
    ListNode dummy = new ListNode(0);
    dummy.next = head;
    int length  = 0;
    ListNode list = head;
    while (list != null) {
        length++;
        list = list.next;
    }
    length -= n;
    list = dummy;
    while (length > 0) {
        length--;
        list = list.next;
    }
    list.next = list.next.next;
    return dummy.next;
}

(2)第二种方法:使用双指针,先让其中一个指针走 N+1 步,然后两个指针同时移动,到达被删除节点的前一个节点时把它删除:

bMjey2A.png!web

mmuyyqj.png!web

6J3e2mE.png!web

ABZfEf7.png!web

public ListNode removeNthFromEnd(ListNode head, int n) {
        ListNode dummy = new ListNode(0);
        dummy.next = head;
        ListNode p = dummy;
        ListNode q = dummy;
        for (int i = 0; i <= n; i++) {
            q = q.next;
        }
        while (q != null) {
            p = p.next;
            q = q.next;
        }
        p.next = p.next.next;
        return dummy.next;
   }

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK