19. 删除链表的倒数第 N 个结点
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode dummy = new ListNode(-1);
dummy.next = head;
ListNode slow = dummy,fast = dummy.next;
while(n > 0){
fast = fast.next;
n--;
}
while(fast != null){
slow = slow.next;
fast = fast.next;
}
slow.next = slow.next.next;
return dummy.next;
}
}
21. 合并两个有序链表
递归实现:
class Solution {
//递归法:每次返回较小的节点
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
if(l1 == null) return l2;
if(l2 == null) return l1;
if(l1.val < l2.val){
l1.next = mergeTwoLists(l1.next,l2);
return l1;
}else{
l2.next = mergeTwoLists(l1,l2.next);
return l2;
}
}
}
迭代实现:
class Solution {
//迭代实现
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
ListNode dummy = new ListNode(-1);
ListNode cur = dummy;
while(l1 != null && l2 != null){
if(l1.val < l2.val){
cur.next = l1;
l1 = l1.next;
}else{
cur.next = l2;
l2 = l2.next;
}
cur = cur.next;
}
cur.next = l1 == null ? l2 : l1;
return dummy.next;
}
}
23. 合并K个升序链表
方法一:借助优先队列实现
class Solution {
//1.方法一:借助优先队列
public ListNode mergeKLists(ListNode[] lists) {
if(lists.length < 1) return null;
ListNode dummy = new ListNode(-1);
ListNode cur = dummy;
PriorityQueue<ListNode> queue = new PriorityQueue<>((o1,o2) ->{
return o1.val - o2.val;
});
//将每个链表的头节点加入到优先队列中
for(ListNode node : lists){
if(node == null) continue;
queue.add(node);
}
//开始从优先队列中取出元素
while(!queue.isEmpty()){
//取出链表中头节点最小的节点
ListNode minHead = queue.poll();
cur.next = minHead;
//接着将 minHead 的下一个节点继续添加到 queue中
if(minHead.next != null) queue.add(minHead.next);
cur = cur.next;
}
return dummy.next;
}
}
方法二:分治法,采用合并两个有序链表的思路:
class Solution {
//方法二:分治法
public ListNode mergeKLists(ListNode[] lists) {
if(lists == null || lists.length == 0) return null;
return mergeKLists(lists,0, lists.length - 1);
}
public ListNode mergeKLists(ListNode[] lists,int l, int r){
if(l >= r){
return lists[l];
}
int mid = (l + r) / 2;
ListNode l1 = mergeKLists(lists,l,mid);
ListNode l2 = mergeKLists(lists,mid + 1,r);
return mergeTwoLists(l1,l2);
}
public ListNode mergeTwoLists(ListNode l1, ListNode l2){
if(l1 == null) return l2;
if(l2 == null) return l1;
if(l1.val < l2.val){
l1.next = mergeTwoLists(l1.next, l2);
return l1;
}else{
l2.next = mergeTwoLists(l1, l2.next);
return l2;
}
}
}
24. 两两交换链表中的节点
递归代码:
class Solution {
//1.递归
public ListNode swapPairs(ListNode head) {
if(head == null || head.next == null) return head;
ListNode next = head.next;
head.next = swapPairs(next.next);
next.next = head;
return next;
}
}
迭代版本:
class Solution {
//2.迭代
public ListNode swapPairs(ListNode head) {
ListNode dummy = new ListNode(-1);
ListNode cur = head,pre = dummy;
dummy.next = cur;
while(cur != null && cur.next != null){
ListNode next = cur.next;
pre.next = next;
cur.next = next.next;
next.next = cur;
pre = cur;
cur = cur.next;
}
return dummy.next;
}
}
25. K 个一组翻转链表
方法一:通过Stack来做链表翻转
class Solution {
/**
* 方法二:⽤用栈 每k个节点压⼊入栈中 弹出的就是翻转的链表
* 注意问题:
* 问题⼀:剩下的链表个数不不够k个
* 问题⼆:已经反转的链表与剩下的链表连接起来
*/
public ListNode reverseKGroup(ListNode head, int k) {
ListNode dummy = new ListNode(-1);
Stack<ListNode> stack = new Stack<>();
ListNode p = dummy;
while(true){
int count = 0;
ListNode cur = head;
while(cur != null && count < k){
stack.push(cur);
cur = cur.next;
count++;
}
if(count != k){
p.next = head;
break;
}
//在把stack中的链表连起来
while(!stack.isEmpty()){
p.next = stack.pop();
p = p.next;
}
p.next = cur;
head = cur;
}
return dummy.next;
}
}
方法二:进阶版本-》不使用额外的控件
翻转链表时候采用尾插法:
-1 --> 1 --> 2 --> 3 --> 4 --> node
dummy
pre
tail
1.找到 tail 节点
-1 --> 1 --> 2 --> 3 --> 4 --> node
dummy tail
pre
2.执行尾部插法
-1 --> 2 --> 3 --> 4 --> 1 --> node (1)
pre tail
-1 --> 3 --> 4 --> 2 --> 1 --> node (1)
pre tail
-1 --> 4 --> 3 --> 2 --> 1 --> node (1)
pre tail
//终止条件: pre.next != tail 说明当前 k 个节点遍历完成
class Solution {
//找到需要翻转链表的 pre 节点 和 tail 节点,翻转 pre -- > tail 这一部分
//尾插法:每次将 pre.next 节点插入到 tail 的后面
public ListNode reverseKGroup(ListNode head, int k) {
ListNode dummy = new ListNode(-1);
dummy.next = head;
ListNode pre = dummy,tail = dummy;
while(true){
int count = 0;
//1.找 tail 节点
while(count < k && tail != null){
tail = tail.next;
count++;
}
//2.如果不满足k个,直接结束最后小于 k 个节点的翻转
if(tail == null) break;
//3.尾插法翻转链表
ListNode newPre = pre.next;
while(pre.next != tail){
ListNode cur = pre.next;
pre.next = cur.next;
cur.next = tail.next;
tail.next = cur;
}
pre = newPre;
tail = newPre;
}
return dummy.next;
}
}
83. 删除排序链表中的重复元素
递归代码:
class Solution {
//递归版本
public ListNode deleteDuplicates(ListNode head) {
if(head == null || head.next == null) return head;
head.next = deleteDuplicates(head.next);
//如果head和next相等,直接返回head的next节点
return head.val == head.next.val ? head.next : head;
}
}
迭代版本:
class Solution {
//迭代版本
public ListNode deleteDuplicates(ListNode head) {
ListNode dummy = new ListNode(-1);
dummy.next = head;
while(head != null && head.next != null){
if(head.val == head.next.val){
head.next = head.next.next;
}else{
head = head.next;
}
}
return dummy.next;
}
}
160. 相交链表
方法:
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
ListNode p1 = headA,p2 = headB;
while(p1 != p2){
p1 = p1 == null ? headB : p1.next;
p2 = p2 == null ? headA : p2.next;
}
return p1;
}
}
206. 反转链表
递归版本:
class Solution {
//递归版本
public ListNode reverseList(ListNode head) {
if(head == null || head.next == null) return head;
ListNode tail = reverseList(head.next);
head.next.next = head;
head.next = null;
return tail;
}
}
迭代版本:
class Solution {
//迭代版本
public ListNode reverseList(ListNode head) {
ListNode dummy = new ListNode(-1);
dummy.next = head;
ListNode pre = head;
while(head != null && head.next != null){
ListNode next = head.next;
pre.next = next.next;
next.next = dummy.next;
dummy.next = next;
}
return dummy.next;
}
}
class Solution {
//迭代,头插入法
public ListNode reverseList(ListNode head) {
ListNode dummy = new ListNode(-1);
while(head != null){
ListNode next = head.next;
head.next = dummy.next;
dummy.next = head;
head = next;
}
return dummy.next;
}
}
445. 两数相加 II
方法:借助栈实现倒序相加
class Solution {
//借助栈实现倒序相加,需要注意进位 问题
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
Stack<ListNode> stack1 = buildStack(l1);
Stack<ListNode> stack2 = buildStack(l2);
int ca = 0;
ListNode dummy = new ListNode(-1);
while(!stack1.isEmpty() || !stack2.isEmpty() || ca != 0){
int a = stack1.isEmpty() ? 0 : stack1.pop().val;
int b = stack2.isEmpty() ? 0 : stack2.pop().val;
int sum = a + b + ca;
ListNode node = new ListNode(sum % 10);
node.next = dummy.next;
dummy.next = node;
ca = sum / 10;
}
return dummy.next;
}
public Stack<ListNode> buildStack(ListNode head){
Stack<ListNode> stack = new Stack<>();
while(head != null){
stack.add(head);
head = head.next;
}
return stack;
}
}