算法----链表

359 阅读4分钟

算法之路

字符串

数组

1 环列表入口节点

给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。

为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。注意,pos 仅仅是用于标识环的情况,并不会作为参数传递到函数中。

说明:不允许修改给定的链表。

来源:力扣(LeetCode 链接:leetcode-cn.com/problems/li…

public ListNode detectCycle(ListNode head) {
       if ((head == null) || (head.next == null)) {
            return null;
        }
        ListNode fast = head;
        ListNode slow = head;
        while ((fast != null) && (fast.next != null)) {
            fast = fast.next.next;
            slow = slow.next;
            if (slow == fast) {
                ListNode temp = head;
                if (temp == fast) {
                    return fast;
                }
                while (true) {
                    fast = fast.next;
                    temp = temp.next;
                    if (fast == temp) {
                        break;
                    }
                }
                return fast;
            }
        }
        return null;
    }

2 反转链表

反转一个单链表。

示例:

输入: 1->2->3->4->5->NULL 输出: 5->4->3->2->1->NULL 进阶: 你可以迭代或递归地反转链表。你能否用两种方法解决这道题?

来源:力扣(LeetCode)

链接:leetcode-cn.com/problems/re…

class Solution {
    public ListNode reverseList(ListNode head) {
        ListNode pre = null, cur = head, next = null;
        while(cur != null) {
            next = cur.next;
            cur.next = pre;
            pre = cur;
            cur = next;
        }
        return pre;
    }
}

3 合并两个有序链表

将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 

 

示例 1:

输入:l1 = [1,2,4], l2 = [1,3,4] 输出:[1,1,2,3,4,4] 示例 2:

输入:l1 = [], l2 = [] 输出:[]

来源:力扣(LeetCode)

链接:leetcode-cn.com/problems/me…

class Solution {
    public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
        ListNode l = new ListNode(0);
        ListNode p = l;

        while (l1 != null && l2 != null) {
            if (l1.val < l2.val) {
                p.next = l1;
                l1 = l1.next;
            } else {
                p.next = l2;
                l2 = l2.next;
            }
            p = p.next;
        }

        if (l1 != null) {
            p.next = l1;
        }
        if (l2 != null) {
            p.next = l2;
        }
        return l.next;
    }
}

4 K 个一组翻转链表

给你一个链表,每 k 个节点一组进行翻转,请你返回翻转后的链表。

k 是一个正整数,它的值小于或等于链表的长度。

如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。

进阶:

你可以设计一个只使用常数额外空间的算法来解决此问题吗? 你不能只是单纯的改变节点内部的值,而是需要实际进行节点交换。

示例 1:

输入:head = [1,2,3,4,5], k = 2 输出:[2,1,4,3,5] 示例 2:

输入:head = [1,2,3,4,5], k = 3 输出:[3,2,1,4,5]

来源:力扣(LeetCode)

链接:leetcode-cn.com/problems/re…

public ListNode reverseKGroup(ListNode head, int k) {
       if (head == null || head.next == null) {
            return head;
        }
        int count = 0;
        ListNode curr = head;
        while (count != k && curr != null) {
            curr = curr.next;
            count++;
        }

        if (count == k) {
            curr = reverseKGroup(curr, k);
            while (count-- > 0) { //翻转
                ListNode tmp = head.next;
                head.next = curr;
                curr = head;
                head = tmp;
            }
            head = curr;
        }
        return head;
    }

5 删除排序链表中的重复元素

存在一个按升序排列的链表,给你这个链表的头节点 head ,请你删除所有重复的元素,使每个元素 只出现一次 。

返回同样按升序排列的结果链表。

 

示例 1:

输入:head = [1,1,2] 输出:[1,2] 示例 2:

输入:head = [1,1,2,3,3] 输出:[1,2,3]

来源:力扣(LeetCode)

链接:leetcode-cn.com/problems/re…

public ListNode deleteDuplicates(ListNode head) {
       
        if (head == null || head.next == null) {
            return head;
        }

        ListNode pre = head;
        ListNode next = head.next;

        while (next != null) {
            if (pre.val == next.val) {
                pre.next = next.next;
            } else {
                pre = next;
            }
            next = next.next;
        }
        return head;
    }

6 环形链表

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

如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。

如果链表中存在环,则返回 true 。 否则,返回 false 。

 

进阶:

你能用 O(1)(即,常量)内存解决此问题吗?

来源:力扣(LeetCode)

链接:leetcode-cn.com/problems/li…

 public boolean hasCycle(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;
            }
            fast = fast.next.next;
            slow = slow.next;
        }
        return true;
    }

7 链表中倒数第k个节点

输入一个链表,输出该链表中倒数第k个节点。为了符合大多数人的习惯,本题从1开始计数,即链表的尾节点是倒数第1个节点。

例如,一个链表有 6 个节点,从头节点开始,它们的值依次是 1、2、3、4、5、6。这个链表的倒数第 3 个节点是值为 4 的节点。

 

示例:

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

返回链表 4->5.

来源:力扣(LeetCode)

链接:leetcode-cn.com/problems/li…

public ListNode getKthFromEnd(ListNode head, int k) {
        if (head == null || head.next == null) {
            return head;
        }
        ListNode dummy = new ListNode(0);
        dummy.next = head;

        ListNode fast = dummy;
        ListNode slow = dummy;

        int j = 0;
        while (dummy != null) {
            if (j >= k) {
                slow = slow.next;
            }
            fast = fast.next;
            j++;
            dummy = dummy.next;
        }
        return slow;
    }

8 删除链表的倒数第 N 个结点

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

进阶:你能尝试使用一趟扫描实现吗?

 

示例 1:

输入:head = [1,2,3,4,5], n = 2 输出:[1,2,3,5]

来源:力扣(LeetCode)

链接:leetcode-cn.com/problems/re…

 public ListNode removeNthFromEnd(ListNode head, int n) {
        ListNode fast = head;
        ListNode slow = head;
        for (int j = 0; j < n; j++) {
            fast = fast.next;
        }
        if (fast == null) { 
            return head.next;
        }
        while (fast.next != null) {
            fast = fast.next;
            slow = slow.next;
        }
        slow.next = slow.next.next; 
        return head;
    }

9 回文链表

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

示例 1:

输入: 1->2 输出: false 示例 2:

输入: 1->2->2->1 输出: true

链接:leetcode-cn.com/problems/pa…

class Solution {
       public boolean isPalindrome(ListNode head) {
        if (head == null || head.next == null) {
            return true;
        }
        ListNode fast = head;
        ListNode slow = head;
        while (fast.next != null && fast.next.next != null) {
            fast = fast.next.next;
            slow = slow.next;
        }
        slow = rerverse(slow.next);
        while (slow != null) {
            if (slow.val != head.val) {
                return false;
            }
            head = head.next;
            slow = slow.next;
        }
        return true;
    }

    public ListNode rerverse(ListNode head) {
        if (head == null || head.next == null) {
            return head;
        }
        ListNode prev = null;
        while (head != null) {
            ListNode temp = head.next;
            head.next = prev;
            prev = head;
            head = temp;
        }
        return prev;
    }
}

10 相交链表

输入两个链表,找出它们的第一个公共节点。

如下面的两个链表:

在节点 c1 开始相交。

 

示例 1:

输入:intersectVal = 8, listA = [4,1,8,4,5], listB = [5,0,1,8,4,5], skipA = 2, skipB = 3 输出:Reference of the node with value = 8 输入解释:相交节点的值为 8 (注意,如果两个列表相交则不能为 0)。从各自的表头开始算起,链表 A 为 [4,1,8,4,5],链表 B 为 [5,0,1,8,4,5]。在 A 中,相交节点前有 2 个节点;在 B 中,相交节点前有 3 个节点。

来源:力扣(LeetCode)

链接:leetcode-cn.com/problems/li…

public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        if (headA == null || headB == null) {
            return null;
        }
        ListNode h1 = headA;
        ListNode h2 = headB;
        while (h1 != h2) {
            h1 = h1 == null ? headB : h1.next;
            h2 = h2 == null ? headA : h2.next;
        }
        return h1;
    }
}