1.链表中倒数第k个结点_牛客网
思路:快慢指针
快指针先走k步,慢指针再和快指针一块走,当快指针走到null时慢指针就刚好走到倒数第k个结点位置
public ListNode FindKthToTail(ListNode head,int k) {
if(k<=0||head==null){
return null;
}
ListNode fast=head;
ListNode slow=head;
// for(int i=0;i<k;i++){
// fast=fast.next;
//}
while(k>0&&fast!=null){
fast=fast.next;
k--;
}
//理论上这里应判断一次k值是否满足条件,但此处直接先判断fast了
//这里要注意k>0且fast==null情况:eg:1->2->3,求倒数第5个结点,此时fast遍历到最后为空但k仍旧大于0
//进入下面循环时k一定是等于0的,如果k>0但是fast为空就无法进入循环
//慢指针在头部,快慢指针之间相差k,让他们一块走
while(fast!=null){
fast=fast.next;
slow=slow.next;
}
return k>0?null:slow;
}
这里注意要时刻注意k的正确性,当k<0时不满足条件,无效,返回null,当k超过链表长度也是不满足条件的,k超过长度时的判断可以加到到快指针前移处一起判断,当k>0&&fast!=null时移动指针,出循环时指针要么是k==0了,此时属于正常情况走了k步,直接移动快慢指针找对应位置即可,另一种情况就是k仍旧大于0但是fast走到null了,此时说明k的次数比链表元素个数多,也是无效的,直接返回null即可。
2.反转链表_牛客网
3.删除链表中的结点
/**
* 给定单向链表的头指针和一个要删除的节点的值,定义一个函数删除该节点。
* 返回删除后的链表的头节点
**/
/**
* 双指针:找到链表的前驱节点和后继节点,前驱.next指向后继
*/
public class Num_18删除链表的结点 {
private class ListNode {
int val;
ListNode next;
ListNode(int x) { val = x; }
}
public ListNode deleteNode(ListNode head, int val) {
if (head.val==val){
return head.next;
}
ListNode prev=head;
ListNode cur=head.next;
while (cur!=null&&cur.val!=val){
prev=cur;
cur=cur.next;
}
//若不是因为cur为null出来,则此时cur.val一定是和val相等了
if(cur!=null){
prev.next=cur.next;
}
return head;
}
// public ListNode deleteNode(ListNode head, int val) {
// if (head.val==val){
// return head.next;
// }
// ListNode prev=head;
// while (prev.next!=null){
// if(prev.next.val==val){
// ListNode cur=prev.next;
// prev.next=cur.next;
// cur.next=null;
// }else{
// prev=prev.next;
// }
// }
// return head;
// }
}
4.力扣_合并连个排序的链表
/**
* 输入两个递增排序的链表,合并这两个链表并使新链表中的节点仍然是递增排序的
**/
public class Num25_合并两个排序链表 {
private static class ListNode {
int val;
ListNode next;
ListNode(int x) { val = x; }
}
public static ListNode mergeTwoLists(ListNode l1, ListNode l2) {
if(l1==null){
return l2;
}
if(l2==null){
return l1;
}
//l1l2都不为空
ListNode dummyHead=new ListNode(-1);
ListNode last=dummyHead;
//对链表进行尾插
while (l1!=null&&l2!=null){
if(l1.val<= l2.val){
last.next=l1;
last=l1;
l1=l1.next;
}else{
last.next=l2;
last=l2;
l2=l2.next;
}
//判断l1l2是否为空
if(l1==null){
last.next=l2;
}
if(l2==null){
last.next=l1;
}
}
return dummyHead.next;
}
public static void main(String[] args) {
ListNode listNode=new ListNode(1);
ListNode listNode1=new ListNode(2);
ListNode listNode2=new ListNode(4);
listNode.next=listNode1;
listNode1.next=listNode2;
ListNode list=new ListNode(1);
ListNode list1=new ListNode(3);
ListNode list2=new ListNode(4);
list.next=list1;
list1.next=list2;
mergeTwoLists(listNode,list);
}
// //递归写法
// public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
// if(l1==null){
// return l2;
// }
// if(l2==null){
// return l1;
// }
// //判断l1l2中val谁小,小的先拼接
// if(l1.val<=l2.val){
// l1.next=mergeTwoLists(l1.next,l2);
// return l1;
// }else{
// l2.next=mergeTwoLists(l1,l2.next);
// return l2;
// }
// }
}
5.相交链表_两个链表的第一个公共结点
思路:
a链表不相交的部分长a,b链表不相交的部分长b,c是相交部分长度
若两个链表有焦点,两个链表同时向后遍历,若某个链表到达终点,让它从对方链表的表头出发,继续后移,最后两个链表一定会在交点回合,如果没有交点,便是两个同时走到null
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
ListNode nodeA=headA;
ListNode nodeB=headB;
while (nodeA!=nodeB){
//遍历nodeA,nodeB
//当nodeA走到空让nodeA继续走headB对应的路
//当nodeB走到空让nodeB继续走headA对应的路
nodeA=nodeA==null?headB:nodeA.next;
nodeB=nodeB==null?headA:nodeB.next;
}
//先遍历完自己再遍历对方,此时他们长度一定同步,走到空便同时走到空,不为空则一定交在某点
//nodeA==nodeB,两种情况
//1.同时空,return nodeA就是return null了
//2.或者同时到达交点,return node1就是return交点,即第一个公共节点
return nodeA;
}