(一).介绍
对于做链表的题目,具体有以下技巧
1.画图。可以更直观和形象
2.引入"虚拟头节点"。这要回可以少判断很多条件,并且头插的时候更方便
3.不要吝啬空间,直接去定义

4.使用快慢双指针的思想来解决链表问题
5.链表中的常用操作
①.创建新的节点
我们直接new就可以了
②.尾插

③.头插
这时候就体现出创建虚拟头节点的作用来了

适合用于"逆序链表"
(二).具体题目
1.环形链表Ⅱ

解法:快慢指针
可以看这个链接
2.两数相加

解法:模拟

java
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
ListNode cur1=l1;
ListNode cur2=l2;
ListNode newHead=new ListNode(0);
ListNode tail=newHead;
int sum=0;
while (cur1!=null||cur2!=null){
if (cur1!=null){
sum+= cur1.val;
cur1=cur1.next;
}
if (cur2!=null){
sum+= cur2.val;
cur2=cur2.next;
}
tail.next=new ListNode(sum%10);
tail=tail.next;
sum/=10;
}
if (sum!=0){ //处理边界情况
tail.next=new ListNode(sum%10);
}
return newHead.next;
}
3.两两交换链表中的节点

解法:循环,迭代

4.重排链表

解法:模拟

java
public void reorderList(ListNode head) {
//先找到中间节点
//将后面的链表进行逆置
//重新插入链表
ListNode fast=head;
ListNode slow=head;
while (fast!=null&&fast.next!=null){
fast=fast.next.next;
slow=slow.next;
}
//开始进行逆置 逆置slow后面的链表
ListNode cur=slow.next;
slow.next=null; //分开链表
ListNode ret=new ListNode(0);// 使用头插法进行逆序
while (cur!=null){
ListNode next=cur.next;
cur.next=ret.next;
ret.next=cur;
cur=next;
}
//进行重排序
ListNode newHead=new ListNode(0);
ListNode prev=newHead;
ListNode c1=head;
ListNode c2=ret.next;
while (c1!=null){ //这里不需要判断c2是否为空的情况,因为前面的链表是包含slow节点的,所以前面的链表长
prev.next=c1;
prev=prev.next;
c1=c1.next;
if (c2!=null){
prev.next=c2;
prev=prev.next;
c2=c2.next;
}
}
}
5.合并K个升序链表

解法1:模拟+优先级队列

java
public ListNode mergeKLists(ListNode[] lists) {
PriorityQueue<ListNode> priorityQueue=new PriorityQueue<>(new Comparator<ListNode>() {
@Override
public int compare(ListNode o1, ListNode o2) {
return o1.val-o2.val;
}
});
for (ListNode cur:lists) {
if (cur!=null){
priorityQueue.offer(cur);
}
}
ListNode newHead=new ListNode(0);
ListNode tail=newHead;
while (!priorityQueue.isEmpty()){
ListNode key=priorityQueue.peek();
tail.next=key;
tail=tail.next;
priorityQueue.poll();
if (key.next!=null){
priorityQueue.offer(key.next);
}
}
return newHead.next;
}
解法2:使用归并排序

java
public ListNode mergeKLists(ListNode[] lists){
return mergeKListsChild(lists,0,lists.length-1);
}
private ListNode mergeKListsChild(ListNode[] lists, int l, int r) {
if (l>r){ //没有链表
return null;
}
if (l==r){ //只有一个链表
return lists[l];
}
//平分数组
int mid=(l+r)/2;
ListNode listNode1=mergeKListsChild(lists,l,mid);
ListNode listNode2=mergeKListsChild(lists,mid+1,r);
//合并两个有序链表
return merge(listNode1,listNode2);
}
private ListNode merge(ListNode listNode1, ListNode listNode2) {
if (listNode1==null){
return listNode2;
}
if (listNode2==null){
return listNode1;
}
ListNode cur1=listNode1;
ListNode cur2=listNode2;
ListNode ret=new ListNode(0);
ListNode cur=ret;
while (cur1!=null&&cur2!=null){
if (cur1.val<cur2.val){
cur.next=cur1;
cur1=cur1.next;
}else{
cur.next=cur2;
cur2=cur2.next;
}
cur=cur.next;
}
if (cur1!=null){
cur.next=cur1;
}
if (cur2!=null){
cur.next=cur2;
}
return ret.next;
}
6.K个一组翻转链表

解法:模拟

java
public ListNode reverseKGroup(ListNode head, int k) {
int n=0;
ListNode cur=head;
while (cur!=null){
n++;
cur=cur.next;
}
int count=n/k;
ListNode newHead=new ListNode(0);
ListNode prev=newHead;
cur=head;
for (int i = 0; i < count; i++) {
ListNode temp=cur;
for (int j = 0; j < k; j++) {
ListNode next=cur.next;
cur.next=prev.next;
prev.next=cur;
cur=next;
}
prev=temp;
}
prev.next=cur;
return newHead.next;
}