【剑指offer2】 chap4 链表

1、基础知识

ListNode

哨兵节点

2、基本题型

(1)双指针

前后双指针

剑指 Offer II 021. 删除链表的倒数第 n 个结点

法一:快慢双指针

class Solution0211 {
    //前后双指针
    public ListNode removeNthFromEnd(ListNode head, int n) {
        ListNode dummy = new ListNode(0);
        dummy.next = head;

        ListNode front = head, back = dummy;
        for (int i = 0; i < n; i++) {
            front = front.next;
        }
        while (front != null) {
            front = front.next;
            back = back.next;
        }
        back.next = back.next.next;
        return dummy.next;
    }
}

法二:计算链表长度

//计算链表长度
class Solution0213 {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        ListNode dummy = new ListNode(0, head);
        int length = getLength(head);
        ListNode cur = dummy;
        for (int i = 1; i < length - n + 1; ++i) {
            cur = cur.next;
        }
        cur.next = cur.next.next;
        ListNode ans = dummy.next;
        return ans;
    }

    public int getLength(ListNode head) {
        int length = 0;
        while (head != null) {
            ++length;
            head = head.next;
        }
        return length;
    }
}

法三:栈(实现倒序)【双端队列】

//栈 双向队列
class Solution0212 {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        ListNode dummy = new ListNode(0, head);
        Deque<ListNode> stack = new LinkedList<ListNode>();
        ListNode cur = dummy;
        while (cur != null) {
            stack.push(cur);
            cur = cur.next;
        }
        for (int i = 0; i < n; ++i) {
            stack.pop();
        }
        ListNode prev = stack.peek();
        prev.next = prev.next.next;
        ListNode ans = dummy.next;
        return ans;
    }
}
Deque<ListNode> stack = new LinkedList<ListNode>();

快慢双指针

剑指 Offer II 022. 链表中环的入口节点

快慢双指针找环内节点(相同)+再次相同

/**
 * Definition for singly-linked list.
 * class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
public class Solution {
    //快慢双指针
    private ListNode getNodeInLoop(ListNode head) {
        if (head == null || head.next == null) {
            return null;
        }

        ListNode slow = head.next;
        ListNode fast = slow.next;

        while (slow != null && fast != null) {
            if (slow == fast) return slow;
            slow = slow.next;
            fast = fast.next;
            if (fast != null) fast = fast.next;
        }
        return null;
    }

    public ListNode detectCycle(ListNode head) {
        ListNode inLoop = getNodeInLoop(head);
        if (inLoop == null) return null;
        ListNode node = head;
        while (node != inLoop) {
            node = node.next;
            inLoop = inLoop.next;
        }
        return node;
    }
}

交叉双指针

剑指 Offer II 023. 两个链表的第一个重合节点

public class Solution {
    //双指针法
    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;
    }
}

(2)反转链表

剑指 Offer II 024. 反转链表

迭代(不需要哑结点)prev, curr, next

//迭代法
public ListNode reverseList(ListNode head) {
    ListNode prev = null;
    ListNode curr = head;
    while (curr!= null){
        ListNode next = curr.next;
        curr.next = prev;
        prev = curr;
        curr = next;
    }
    return prev;
}

递归(边界条件)

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

    ListNode newHead = reverseList(head.next);
    head.next.next = head;
    head.next = null;
    return newHead;
}

剑指 Offer II 025. 链表中的两数相加

先各自翻转

再按位相加和进位(哑结点)

再翻转

class Solution {

    //迭代法反转
    public ListNode reverseList(ListNode head) {
        ListNode prev = null;
        ListNode curr = head;
        while (curr != null) {
            ListNode next = curr.next;
            curr.next = prev;
            prev = curr;
            curr = next;
        }
        return prev;
    }

    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        //翻转
        ListNode node1 = reverseList(l1);
        ListNode node2 = reverseList(l2);

        //结果
        ListNode dummy = new ListNode(0);
        ListNode sumNode = dummy;
        int carry = 0;

        //相加
        while (node1 != null || node2 != null) {
            int num1 = (node1 == null) ? 0 : node1.val;
            int num2 = (node2 == null) ? 0 : node2.val;
            int sum = num1 + num2 + carry;
            carry = sum > 9 ? 1 : 0;
            sum = sum > 9 ? sum - 10 : sum;

            ListNode node = new ListNode(sum);
            sumNode.next = node;
            sumNode = node;
            
            node1 = node1 == null ? null : node1.next;
            node2 = node2 == null ? null : node2.next;
        }

        if (carry > 0) {
            sumNode.next = new ListNode(1);
        }
        
        ListNode head = reverseList(dummy.next);
        //再翻转
//        dummy.next = null;
        return head;
    }
}

剑指 Offer II 026. 重排链表

法一:

对半分开(快慢双指针)

反转第二个

交叉合并

//对半分,快慢双指针
ListNode slow = head;
ListNode fast = slow.next;

while (fast != null && fast.next != null) {
    slow = slow.next;
    fast = fast.next;
    if (fast != null) {
        fast = fast.next;
    }
}

法二:线性表

剑指 Offer II 027. 回文链表

法一:

对半分开

反转第二个

一一比较

法二:线性表

(3)双向链表和循环链表

剑指 Offer II 028. 展平多级双向链表

剑指 Offer II 029. 排序的循环链表

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值