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>();
快慢双指针
快慢双指针找环内节点(相同)+再次相同
/**
* 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;
}
}
交叉双指针
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)反转链表
迭代(不需要哑结点)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;
}
先各自翻转
再按位相加和进位(哑结点)
再翻转
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;
}
}
法一:
对半分开(快慢双指针)
反转第二个
交叉合并
//对半分,快慢双指针
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;
}
}
法二:线性表
法一:
对半分开
反转第二个
一一比较
法二:线性表