Class

  1. public class ListNode {
  2. int val;
  3. ListNode next;
  4. ListNode() {}
  5. ListNode(int val) {
  6. this.val = val;
  7. }
  8. ListNode(int val, ListNode next) {
  9. this.val = val;
  10. this.next = next;
  11. }
  12. }

反转链表

//迭代
public ListNode reverseList(ListNode head) {
    ListNode pre = null;
    while(head !=  null) {
        ListNode temp = head.next;
        head.next = pre;
        pre = head;
        head = temp;
    }
    return pre;
}

//递归
public ListNode reverseList(ListNode head) {
    if(head == null || head.next == null) return head;
    ListNode newHead = reverseList(haed.next);
    head.next.next = head;
    head.next = null;
    return newHaed;
}

反转链表II

反转从left节点到right节点的链表

//找到左右节点 然后翻转  因为Node只有next指针,所以只能拼接next节点 前节点需要手动拼接
class Solution {
    public ListNode reverseBetween(ListNode head, int left, int right) {
        ListNode hair = new ListNode(-1);
        hair.next = head;
        ListNode pre_left = hair;

        for (int i = 0; i < left - 1; i++) {
            pre_left = pre_left.next;
        }

        ListNode rightNode = pre_left;
        ListNode leftNode = pre_left.next;

        for(int i = 0; i < right - left + 1; i++) {
            rightNode = rightNode.next;
        }

        myReverse(leftNode, rightNode);
        pre_left.next = rightNode;

        return hair.next;
    }
    //与反转链表相似 只是tail.next不再为null
    public void myReverse(ListNode head, ListNode tail) {
        ListNode end = tail.next;
        ListNode pre = tail.next;
        while(head != end) {
            ListNode temp  = head.next;
            head.next = pre;
            pre = head;
            head = temp;
        }
    }
}

K个一组反转链表

//分成两部分
//1 遍历分组
//2 按组翻转
//需要建立 辅助头节点  维护 翻转链表的左右指针
class Solution {
    public ListNode reverseKGroup(ListNode head, int k) {
        ListNode hair = new ListNode(0);
        hair.next = head;
        ListNode pre_left = hair;
        while(head != null){
            ListNode right = pre_left;
            for(int i = 0 ; i < k; i++) {
                right = right.next;
                if(right == null) return hair.next;
            }
            //反转k组链表,只能通过next拼接后面节点,前面节点需要手动连接
            myReverse(head, right);
            //保留前一个节点手动连接
            pre_left.next = right;

            pre_left = head;
            head = head.next; 
        }
        return hair.next;
    }
    //与反转链表相似 只是tail.next不再为null
    public void myReverse(ListNode head, ListNode tail){
        ListNode end = tail.next;
        ListNode pre = tail.next;
        while(head != end){
            ListNode temp  = head.next;
            head.next = pre;
            pre = head;
            head = temp;
        }
    }
}

合并两个有序链表

class Solution {
    public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
        ListNode prehead = new ListNode(-1);

        ListNode prev = prehead;
        while(l1 != null && l2 != null){
            if(l1.val <= l2.val){
                prev.next = l1;
                l1 = l1.next;
            } else{
                prev.next = l2;
                l2 = l2.next;
            }
            prev = prev.next;
        }
        prev.next = l1 == null ? l2 : l1;
        return prehead.next;
    }
}

环形链表

给你一个链表的头节点 head ,判断链表中是否有环。

//快慢指针
public class Solution {
    public boolean hasCycle(ListNode head) {
        if (head == null) return false;
        ListNode slow = head;
        ListNode fast = head;
        while(fast != null && fast.next != null) {
            slow = slow.next;
            fast = fast.next.next;
            if(slow == fast) return true;
        }
        return false;     
    }
}

环形链表II

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

//快慢指针
// fast = 2slow = slow + n*cirle
// slow = n*circle
//从head节点走到fast与slow的交点 需要走 a + n*circle(a为从头到交点的距离)
//slow已经走了n*circle 只需再走a步即可
//如何确定slow走了a步,从head开始,和slow一起走,相遇时刚好a步
public class Solution {
    public ListNode detectCycle(ListNode head) {
        ListNode fast = head;
        ListNode slow = head;
        while(true) {
            if(fast == null || fast.next == null) return null;
            fast = fast.next.next;
            slow = slow.next;
            if(fast == slow) break;
        }
        fast = head;
        while(slow != fast) {
            slow = slow.next;
            fast = fast.next;
        }
        return fast;
    }
}

相交链表

image.png

// 相交路程为c
// A  走   a-c     c
// B  走   b-c     c
// A走完自己的路再走B
// B走完自己的路再走A
// 则 a + b-c   与  b + a-c 正好相遇
public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        if(headA== null|| headB== null) return null;
            ListNode pa = headA;
            ListNode pb = headB;
            while(pa!= pb){
                pa = (pa==null? headB: pa.next);
                pb = (pb==null? headA: pb.next);
            }
        return pa
    }
}

回文链表

class Solution {
    public boolean isPalindrome(ListNode head) {
        if (head == null) {
            return true;
        }

        // 找到前半部分链表的尾节点并反转后半部分链表
        ListNode firstHalfEnd = endOfFirstHalf(head);
        ListNode secondHalfStart = reverseList(firstHalfEnd.next);

        // 判断是否回文
        ListNode p1 = head;
        ListNode p2 = secondHalfStart;
        boolean result = true;
        while (result && p2 != null) {
            if (p1.val != p2.val) {
                result = false;
            }
            p1 = p1.next;
            p2 = p2.next;
        }        

        // 还原链表并返回结果
        firstHalfEnd.next = reverseList(secondHalfStart);
        return result;
    }

    private ListNode reverseList(ListNode head) {
        ListNode prev = null;
        ListNode curr = head;
        while (curr != null) {
            ListNode nextTemp = curr.next;
            curr.next = prev;
            prev = curr;
            curr = nextTemp;
        }
        return prev;
    }

    private ListNode endOfFirstHalf(ListNode head) {
        ListNode fast = head;
        ListNode slow = head;
        while (fast.next != null && fast.next.next != null) {
            fast = fast.next.next;
            slow = slow.next;
        }
        return slow;
    }
}

重排链表

image.png

//寻找链表中点 + 链表逆序 + 合并链表
class Solution {
    public void reorderList(ListNode head) {
        if (head == null) {
            return;
        }
        ListNode mid = middleNode(head);
        ListNode l1 = head;
        ListNode l2 = mid.next;
        mid.next = null;
        l2 = reverseList(l2);
        mergeList(l1, l2);
    }

    public ListNode middleNode(ListNode head) {
        ListNode slow = head;
        ListNode fast = head;
        while (fast.next != null && fast.next.next != null) {
            slow = slow.next;
            fast = fast.next.next;
        }
        return slow;
    }

    public ListNode reverseList(ListNode head) {
        ListNode prev = null;
        ListNode curr = head;
        while (curr != null) {
            ListNode nextTemp = curr.next;
            curr.next = prev;
            prev = curr;
            curr = nextTemp;
        }
        return prev;
    }

    public void mergeList(ListNode l1, ListNode l2) {
        ListNode l1_tmp;
        ListNode l2_tmp;
        while (l1 != null && l2 != null) {
            l1_tmp = l1.next;
            l2_tmp = l2.next;

            l1.next = l2;
            l1 = l1_tmp;

            l2.next = l1;
            l2 = l2_tmp;
        }
    }
}

复杂链表复制

请实现 copyRandomList 函数,复制一个复杂链表。在复杂链表中,每个节点除了有一个 next 指针指向下一个节点,还有一个 random 指针指向链表中的任意节点或者 null。

class Solution {
    public Node copyRandomList(Node head) {
        if(head == null) return null;
        Node cur = head;
        // 1. 复制各节点,并构建拼接链表
        while(cur != null) {
           Node temp = new Node(cur.val);
           temp.next = cur.next;
           cur.next = temp;
           cur = temp.next;

        }
        // 2. 构建各新节点的 random 指向
        cur = head;
        while(cur != null) {
            if(cur.random != null) cur.next.random = cur.random.next;
            cur = cur.next.next;
        }
        // 3. 拆分两链表
        cur = head.next;
        Node pre = head, res = head.next;
        while(cur.next != null) {
            pre.next = pre.next.next;
            cur.next = cur.next.next;
            pre = pre.next;
            cur = cur.next;
        }
        pre.next = null; // 单独处理原链表尾节点
        return res;
    }
}

删除倒数第N节点

//快慢指针
class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        ListNode fast = head;
        ListNode slow = head;
        for(int i = 0; i< n; i++){
            fast = fast.next;
        }
        if(fast == null) return head.next;
        while(fast!= null && fast.next!= null){
            fast = fast.next;
            slow = slow.next;
        }
        slow.next = slow.next.next;
        return head;
    }
}

复杂链表的复制

class Solution {
    public Node copyRandomList(Node head) {
        if(head == null ) return null;
        Node cur = head;
        while(cur != null) {
            Node temp = new Node(cur.val);
            temp.next = cur.next;
            cur.next = temp;
            cur = temp.next;
        }
        cur = head;
        while(cur != null) {
            if(cur.random != null) cur.next.random = cur.random.next;
            cur = cur.next.next;
        }
        cur = head.next;
        Node pre = head;
        Node res = head.next;
        while(cur.next != null){
            pre.next = pre.next.next;
            cur.next = cur.next.next;
            pre = pre.next;
            cur = cur.next;
        }
        pre.next = null;
        return res;
    }
}

两数相加

非空链表相加
输入:l1 = [2,4,3], l2 = [5,6,4]
输出:[7,0,8]
解释:342 + 465 = 807.
class Solution {
    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        ListNode head = null;
        ListNode tail = null;
        int carry = 0;
        while(l1 != null || l2 != null) {
            int n1 = l1 != null ? l1.val : 0;
            int n2 = l2 != null ? l2.val : 0;
            int sum = n1 + n2 + carry;
            if (head == null) {
                head = tail = new ListNode(sum % 10);
            } else {
                tail.next = new ListNode(sum %10);
                tail = tail.next;
            }
            carry = sum /10;
            if(l1 != null) {
                l1 = l1.next;
            }
            if(l2 != null) {
                l2 = l2.next;
            }
        }
        if (carry > 0) {
            tail.next = new ListNode(carry);
        }
        return head;
    }
}

奇偶链表

输入: head = [2,1,3,5,6,4,7]
输出: [2,3,6,7,1,5,4]
class Solution {
    public ListNode oddEvenList(ListNode head) {
        if(head == null) return head;
        ListNode h1 = head;
        ListNode h2 = head.next;
        ListNode temp = head.next;
        while(h2 != null && h2.next != null) {
            h1.next = h2.next;
            h1 = h1.next;
            h2.next = h1.next;
            h2 = h2.next;
        }
        h1.next = temp;
        return head;
    }
}

排序链表

输入:head = [4,2,1,3]
输出:[1,2,3,4]
//归并排序
//先切分 再合并比较
class Solution {
    public ListNode sortList(ListNode head) {
        if (head == null || head.next == null) return head;
        ListNode fast = head.next;
        ListNode slow = head;
        while (fast != null && fast.next != null) {
            slow = slow.next;
            fast = fast.next.next;
        }
        ListNode temp = slow.next;
        slow.next = null;
        ListNode left = sortList(head);
        ListNode right = sortList(temp);
        ListNode h = new ListNode(0);
        ListNode res = h;
        while(left != null && right != null) {
            if(left.val < right.val) {
                h.next = left;
                left = left.next;
            } else {
                h.next = right;
                right = right.next;
            }
            h = h.next;
        }
        h.next = left != null ? left : right;
        return res.next;
    }
}

合并K个升序链表