LeetCode 链表专题

1、sort-list
题目描述
Sort a linked list in O(n log n) time using constant space complexity.
【思路】考虑归并排序,学到的一个方法是,分出了左右两个部分后,把左部分的最后一个链表的节点的next指向null,这样就自然形成了两个链表
【注意】踩过的坑见代码注释

public class Main {
    public static void main(String[] args) {
        ListNode head = new ListNode(3);
        head.next = new ListNode(4);
        head.next.next = new ListNode(1);
        ListNode res = new Main().sortList(head);
        System.out.println(res.val);
    }

    public ListNode sortList(ListNode head) {
        if (head == null || head.next == null) { //注意这里,如果只有一个节点的话和null一样也直接返回,不然一个节点的时候下面的逻辑会一直跑,导致栈溢出
            return head;
        }
        ListNode slow = head, fast = head.next;
        while (fast != null && fast.next != null) {
            fast = fast.next.next;
            slow = slow.next;
        }
        ListNode headSecond = slow.next;
        slow.next = null;
        return mergeList(sortList(head), sortList(headSecond));
    }

    public ListNode mergeList(ListNode head1, ListNode head2) {
        ListNode newHead = new ListNode(0);
        ListNode node = newHead;
        ListNode node1 = head1, node2 = head2;
        while (node1 != null && node2 != null) {
            if (node1.val < node2.val) {
                node.next = node1;
                node1 = node1.next;
                node = node.next;
            } else {
                node.next = node2;
                node2 = node2.next;
                node = node.next;
            }
        }
        if (node1 != null) {  //注意这里如果用while的话记得node和node1都要往后跳,不然程序结果输出错误
            node.next = node1;
        }
        if (node2 != null) {
            node.next = node2;
        }
        return newHead.next;
    }

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

2、reorder-list

题目描述

Given a singly linked list L: L 0→L 1→…→L n-1→L n,
reorder it to: L 0→L n →L 1→L n-1→L 2→L n-2→…

You must do this in-place without altering the nodes' values.

For example,
Given{1,2,3,4}, reorder it to{1,4,2,3}.

【思考】考虑用双端队列,将所有节点依次存入队列中,充队列头节点推出节点,接着从队列尾推出节点,然后是队列头,交替推出,直到队列为空。注意边界条件

import java.util.Deque;
import java.util.LinkedList;
public class Solution {
    public void reorderList(ListNode head) {
        if (head == null) {
            return;
        }
        Deque<ListNode> deque = new LinkedList<>();
        ListNode node = head;
        while (node != null) {
            deque.add(node);
            node = node.next;
        }
        node = head;
        while (deque.size() != 0) {
            node.next = deque.pollFirst();
            node = node.next;
            if (deque.size() != 0) {
                node.next = deque.pollLast();
                node = node.next;
            }
        }
        node.next = null;
    }
}

3、linked-list-cycle-ii

题目描述

Given a linked list, return the node where the cycle begins. If there is no cycle, returnnull.

Follow up:
Can you solve it without using extra space?
public class Solution {
    public ListNode detectCycle(ListNode head) {
        ListNode slow = head, fast = head;
        boolean flag = false;
        while (fast != null && fast.next != null) {  //此处注意fast != null 如果用slow != null时如果fast指针是null的时候会判断fast.next抛出空指针异常,在链表1->2的时候是会出现空指针的。事实上是只要通过fast指针判断就可以。
            slow = slow.next;
            fast = fast.next.next;
            if (slow == fast) {
                flag = true;
                break;
            }
        }
        if (!flag) {
            return null;
        } else {
            slow = head;
            while (slow != fast) {
                slow = slow.next;
                fast = fast.next;
            }
            return slow;
        }
    }
}

4、copy-list-with-random-pointer

题目描述

A linked list is given such that each node contains an additional random pointer which could point to any node in the list or null.

Return a deep copy of the list.

【思路】大概如下图所示,用map做节点间的一一对应关系,这样node1跳到下一节点的时候,原链表的node也跟着跳到下一节点,并且可以通过random指向随机节点,随机节点通过map获取复制链表中的随机节点,node1可以直接指向了
这里写图片描述

import java.util.HashMap;

/**
 * Created by Administrator on 2018/3/29 0029.
 */
public class Main {
    public RandomListNode copyRandomList(RandomListNode head) {
        RandomListNode newHead = new RandomListNode(0);
        RandomListNode node = head, newLastNode = newHead, copyNode = null;
        HashMap<RandomListNode, RandomListNode> map = new HashMap<>();
        while (node != null) {
            copyNode = new RandomListNode(node.label);
            map.put(node, copyNode);
            newLastNode.next = copyNode;
            newLastNode = newLastNode.next;
            node = node.next;
        }
        newLastNode = newHead.next;
        node = head;
        while (newLastNode != null) {
            if (map.containsKey(node.random)) {
                newLastNode.random = map.get(node.random);
            }
            node = node.next;
            newLastNode = newLastNode.next;
        }
        return newHead.next;
    }

    class RandomListNode {
        int label;
        RandomListNode next, random;
        RandomListNode(int x) {
            this.label = x;
        }
    }

}

5、convert-sorted-list-to-binary-search-tree

Given a singly linked list where elements are sorted in ascending order, convert it to a height balanced BST.

【思路】通过快慢指针找中点,以中点作为根节点,左边的部分做左子树,右边的部分做右子树。
牛客网因为生成树的顺序问题过不了,在LeetCode上能过。

public class Main {
    public static void main(String[] args) {
    }

    public TreeNode sortedListToBST(ListNode head) {
        if (head == null) {
            return null;
        }
        ListNode slow = head, fast = head.next, preslow = null;
        while (fast != null && fast.next != null) {
            preslow = slow;
            slow = slow.next;
            fast = fast.next.next;
        }
        TreeNode root = new TreeNode(slow.val);
        if (preslow != null) {
            preslow.next = null;
            root.left = sortedListToBST(head);
        }
        root.right = sortedListToBST(slow.next);
        return root;
    }

    class TreeNode{
        int val;
        TreeNode left;
        TreeNode right;
        public TreeNode(int x) {
            val = x;
        }
    }

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

}

6、reverse-linked-list-ii

题目描述

Reverse a linked list from position m to n. Do it in-place and in one-pass.

For example:
Given1->2->3->4->5->NULL, m = 2 and n = 4,

return1->4->3->2->5->NULL.

Note: 
Given m, n satisfy the following condition:
1 ≤ m ≤ n ≤ length of list.

【思路】在反转链表的基础上改写,找到反转之前起始节点的前一个节点pre,反转最后一个节点的后一个节点pos,找到要反转的起始节点和最后一个节点的下一个节点(当做正常反转链表的null用)。

public class Solution {
    public ListNode reverseBetween(ListNode head, int m, int n) {
        int len = 0;
        ListNode node = head;
        ListNode pre = null, pos = null; //pre反转链表起始点的前一个节点,pos反转链表的最后节点的后一个节点
        while (node != null) {
            len++;
            if (len == m-1) {
                pre = node;
            }
            if (len == n + 1) {
                pos = node;
            }
            node = node.next;
        }
        ListNode node1 = pre == null? head : pre.next;
        ListNode head1 = reverseList(node1, pos);
        node1.next = pos;
        if (pre == null){
            return head1;
        }
        pre.next = head1;
        return head;
    }

    public static ListNode reverseList(ListNode head, ListNode tail){
        ListNode pre = null;
        ListNode cur = head;
        ListNode post;
        while (cur != tail){
            post = cur.next;
            cur.next = pre;
            pre = cur;
            cur  = post;
        }
        return pre;

    }
}

7、partition-list

题目描述

Given a linked list and a value x, partition it such that all nodes less than x come before nodes greater than or equal to x.

You should preserve the original relative order of the nodes in each of the two partitions.

For example,
Given1->4->3->2->5->2and x = 3,
return1->2->2->4->3->5.

【注意】注意点在注释中,要预先保存next的值

public class Solution {
    public ListNode partition(ListNode head, int x) {
        ListNode sH = null, sT = null, bH = null, bT = null; //bH,bT中包含相等
        ListNode node = head;
        while (node != null) {  // node是当前节点,应该让node前面的节点next指向null,不然sT编程了node,相当于变相在给node赋值。每次保存node的下一个节点next
            ListNode pos = node.next;
            if (node.val < x) {
                if (sH == null) {
                    sH = node;
                    sT = node;
                } else {
                    sT.next = node;
                    sT = sT.next;
                }
            } else {
                if (bH == null) {
                    bH = node;
                    bT = node;
                } else {
                    bT.next = node;
                    bT = bT.next;
                }
            }
            node.next = null;
            node = pos;
        }
        if (sH == null) {
            return bH;
        } else {
            if (bH == null) {
                return sH;
            } else {
                sT.next = bH;
                return sH;
            }

        }

    }
}

8、remove-duplicates-from-sorted-list-ii

题目描述

Given a sorted linked list, delete all nodes that have duplicate numbers, leaving only distinct numbers from the original list.

For example,
Given1->2->3->3->4->4->5, return1->2->5.
Given1->1->1->2->3, return2->3.

【注意】注意边界条件,和lastNode赋值给新链表后要更新到最新的node的值。不然就是死循环了。

题目描述

Given a sorted linked list, delete all nodes that have duplicate numbers, leaving only distinct numbers from the original list.

For example,
Given1->2->3->3->4->4->5, return1->2->5.
Given1->1->1->2->3, return2->3.
public class Main {
    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(3);
        head.next.next.next.next = new ListNode(5);
        ListNode res = new Main().deleteDuplicates(head);
        return;
    }

    public ListNode deleteDuplicates(ListNode head) {
        if (head == null) {
            return null;
        }
        ListNode newHead = new ListNode(0);
        ListNode newNode = newHead, lastNode = head, node = head.next; //lastNode能保证是第一个出现的数,即和前面的数都不同。
        while (node != null) {
            if (node.val == lastNode.val) {
                while (node != null && node.val == lastNode.val) {
                    node = node.next;
                }
                lastNode = node;
                node = node == null? null : node.next;
            } else {
                newNode.next = lastNode;
                lastNode = node;  //注意这句话很重要,node进入了这里,能证明和前面的值都不相同。
                newNode = newNode.next;
                node = node.next;
            }
        }
        newNode.next = lastNode;
        return newHead.next;
    }

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

9、remove-duplicates-from-sorted-list

题目描述

Given a sorted linked list, delete all duplicates such that each element appear only once.

For example,
Given1->1->2, return1->2.
Given1->1->2->3->3, return1->2->3.
public class Main {
    public static void main(String[] args) {

    }

    public ListNode deleteDuplicates(ListNode head) {
        if (head == null) {
            return null;
        }
        ListNode node = head.next, cur = head;

        while (node != null) {
            if (node.val != cur.val) {
                cur.next = node;
                cur = cur.next;

            }
            node = node.next;
            cur.next = null;//这个的位置很重要,不断开的话相同的有可能还是连在一起
        }
        return head;
    }

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

}

10、merge-two-sorted-lists

Merge two sorted linked lists and return it as a new list. The new list should be made by splicing together the nodes of the first two lists.
public class Main {
    public static void main(String[] args) {

    }

    public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
        ListNode newHead = new ListNode(0);
        ListNode node = newHead;
        while (l1 != null && l2 != null) {
            if (l1.val < l2.val) {
                node.next = l1;
                l1 = l1.next;  //注意选择哪个链表的节点,哪个链表的节点就要向后跳
            } else {
                node.next = l2;
                l2 = l2.next;
            }
            node = node.next;
        }
        if (l1 != null) {
            node.next = l1;
        }
        if (l2 != null) {
            node.next = l2;
        }
        return newHead.next;
    }

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

11、rotate-list

题目描述

Given a list, rotate the list to the right by k places, where k is non-negative.

For example:
Given1->2->3->4->5->NULLand k =2,
return4->5->1->2->3->NULL.

【注意】k如果是大于链表长度的话就要取模,如果是0的话,不要动。之后就是倒数第k个节点,右面的挪到左边去。

public class Main {
    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);
        ListNode res = new Main().rotateRight(head, 2);
        return;

    }

    public ListNode rotateRight(ListNode head, int n) {
        if (head == null) {
            return head;
        }
        int count = 0;
        ListNode node = head;
        while (node != null) {
            node = node.next;
            count++;
        }
        n = n % count;
        if (n == 0) {
            return head;
        }
        ListNode fast = head;
        while (n > 0 && fast != null) {
            fast = fast.next;
            n--;
        }
        ListNode slow = head, preslow = null, prefast = null;
        while (fast != null) {
            prefast = fast;
            fast = fast.next;
            preslow = slow;
            slow = slow.next;
        }
        preslow.next = null;
        prefast.next = head;
        return slow;
    }

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


}

12、reverse-nodes-in-k-group

题目描述

Given a linked list, reverse the nodes of a linked list k at a time and return its modified list.

If the number of nodes is not a multiple of k then left-out nodes in the end should remain as it is.

You may not alter the values in the nodes, only nodes itself may be changed.

Only constant memory is allowed.

For example,
Given this linked list:1->2->3->4->5

For k = 2, you should return:2->1->4->3->5

For k = 3, you should return:3->2->1->4->5

public class Main {


    public ListNode reversekGroup(ListNode head, int k) {
        if (k < 2){
            return head;
        }
        ListNode pre = null, cur = head, post;
        int count = 0;
        while (cur != null) {
            post = cur.next;
            if (count == k - 1) {
                ListNode start = (pre == null) ? head : pre.next;
                head = pre == null ? cur : head;
                reverseList(pre, start, cur, post);
                pre = start;
                count = -1;
            }
            cur = post;
            ++count;
        }
        return head;

    }

    public void reverseList(ListNode left, ListNode start, ListNode end, ListNode right){
        ListNode pre = left, cur = start, post = null;
        while (cur != right){
            post = cur.next;
            cur.next = pre;
            pre = cur;
            cur = post;
        }
        if (left != null){
            left.next = end;
        }
        start.next = right;
    }

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

13、swap-nodes-in-pairs

题目描述

Given a linked list, swap every two adjacent nodes and return its head.

For example,
Given1->2->3->4, you should return the list as2->1->4->3.

Your algorithm should use only constant space. You may not modify the values in the list, only nodes itself can be changed.
public class Main {
    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);
        ListNode res = new Main().swapPairs(head);
        return;

    }

    public ListNode swapPairs(ListNode head) {
        if (head == null) {
            return null;
        }
        ListNode newHead = new ListNode(0);
        ListNode node = newHead, first = head, second = head.next;
        while (second != null) {
            ListNode posSecond = second.next;
            node.next = second;
            second.next = first;
            first.next = null;
            node = first;
            first = posSecond; //注意此处,将事先保存的second节点的最后一个节点赋值给first
            second = first == null ? null : first.next; //这里是看后面的second还有没有,注意要用first,不能用second.next.next
        }
        node.next = first;
        return newHead.next;
    }

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

}

14、merge-k-sorted-lists

题目描述

Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity.

【思考】考虑优先队列(堆排序)维护一个k个值的堆,每个链表取一个值扔进去。小根堆,每次取堆顶元素。归并排序两两链表先合并,然后再两两合并。

代码有点复杂,是LeetCode的hard题目,有空做吧。

15、remove-nth-node-from-end-of-list

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

例如,

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

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


说明:

给的 n 始终是有效的。

尝试一次遍历实现。

public class Main {
    public static void main(String[] args) {

    }


    public ListNode removeNthFromEnd(ListNode head, int n) {
        if (head == null) {
            return null;
        }
        ListNode slow = head, fast = head, preslow = null;
        while (fast != null) {
            if (n != 0) {
                fast = fast.next;
                --n;
            } else {
                preslow = slow;
                slow = slow.next;
                fast = fast.next;
            }
        }
        if (preslow == null) {
            return head.next;
        } else {
            preslow.next = slow.next;
            return head;
        }

    }

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

16、add-two-numbers

给定两个非空链表来代表两个非负整数,位数按照逆序方式存储,它们的每个节点只存储单个数字。将这两数相加会返回一个新的链表。

你可以假设除了数字 0 之外,这两个数字都不会以零开头。

示例:

输入:(2 -> 4 -> 3) + (5 -> 6 -> 4)
输出:7 -> 0 -> 8
原因:342 + 465 = 807
public class Main {
    public static void main(String[] args) {
        ListNode head1 = new ListNode(2);
        head1.next = new ListNode(4);
        head1.next.next = new ListNode(3);
        ListNode head2 = new ListNode(5);
        head2.next = new ListNode(6);
        head2.next.next = new ListNode(4);
        ListNode head = new Main().addTwoNumbers(head1, head2);
        return;

    }

    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        int d1 = 0, d2 = 0,d = 0, carry = 0;
        ListNode head = new ListNode(0);
        ListNode node = head;
        while (l1 != null || l2 != null) {
            d1 = l1 == null ? 0 : l1.val;
            d2 = l2 == null ? 0 : l2.val;
            d = d1 + d2 + carry;
            if (d >= 10) {
                carry = 1;
            } else {
                carry = 0;
            }
            d = d % 10;
            node.next = new ListNode(d);
            node = node.next;
            l1 = l1 == null ? null : l1.next;
            l2 = l2 == null ? null : l2.next;
        }
        if (carry == 1) {
            node.next = new ListNode(1);
        }
        return head.next;
    }

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

17、median-of-two-sorted-arrays

There are two sorted arrays A and B of size m and n respectively. Find the median of the two sorted arrays. The overall run time complexity should be O(log (m+n)).

【点评】这道题不像是链表的题目,在log(M + N)的复杂度下找到两个排序数组的中位数。代码参考这位大神的博客的https://blog.csdn.net/chen_xinjia/article/details/69258706写的很清楚!

public class Main {
    public static double findMedianSortedArrays(int[] A, int[] B) {
        int N1 = A.length;
        int N2 = B.length;
        if (N1 > N2) {// 确保N1是短的部分。
            return findMedianSortedArrays(B, A);
        }

        if (N1 == 0)
            return ((double) B[(N2 - 1) / 2] + (double) B[N2 / 2]) / 2;
        int size = N1 + N2;
        int cutL = 0, cutR = N1;
        int cut1 = N1 / 2;
        int cut2 = size / 2 - cut1;

        while (cut1 <= N1) {
            cut1 = (cutR - cutL) / 2 + cutL;
            cut2 = size / 2 - cut1;

            double L1 = (cut1 == 0) ? Integer.MIN_VALUE : A[cut1 - 1];
            double L2 = (cut2 == 0) ? Integer.MIN_VALUE: B[cut2 - 1];
            double R1 = (cut1 == N1) ? Integer.MAX_VALUE : A[cut1];
            double R2 = (cut2 == N2) ? Integer.MAX_VALUE : B[cut2];
            if (L1 > R2)
                cutR = cut1 - 1;
            else if (L2 > R1)
                cutL = cut1 + 1;
            else {// Otherwise, that's the right cut.
                if (size % 2 == 0) {// 偶数个数的时候
                    L1 = (L1 > L2 ? L1 : L2);
                    R1 = (R1 < R2 ? R1 : R2);
                    return (L1 + R1) / 2;
                }

                else {
                    R1 = (R1 < R2 ? R1 : R2);
                    return R1;
                }
            }
        }
        return -1;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值