1.在O(1)时间下删除节点
题目:给定链表的头指针和一个节点指针,在O(1)时间删除该节点。
分析:用要删除节点的下一个节点的数据覆盖要删除节点的数据,然后删除下一个节点。此方法不能用来删除尾节点。
代码:
class Solution{
public static void deleteNode(ListNode head, ListNode deleteNode){
//传入的两个节点不能为null
if(head == null || deleteNode == null){
return;
}
//要删除的节点是头节点
if(head == deleteNode){
head = head.next;//更新头部
deleteNode.next == null;//删除
}else if(deleteNode.next != null){//要删除的节点不是尾节点
deleteNode.data = deleteNode.next.data;//修改数据
deleteNode.next = deleteNode.next.next;//删除节点
}else{//要删除的节点是尾节点
ListNode cur = head;
while(cur.next != deleteNode){
cur = cur.next;
}
cur.next = null; //删除
}
}
}
2.单链表的反转
题目:反转一个单链表。
2.1 循环法:
分析:三个临时变量pre、head、next,循环一遍链表,改变链表每个节点的指向。如下所示:
class Solution {
public static ListNode reverseByLoop(ListNode head) {
if (head == null || head.next == null) {
return head;
}
ListNode pre = null;
ListNode next = null;
while(head != null){
next = head.next;
head.next = pre;
pre = head;
head = next;
}
return pre;
}
}
2.2 递归法:
用1->2->3->4->null分析如下图所示:
代码:
class Solution {
public static ListNode reverseByRecursion(ListNode head) {
if (head == null || head.next == null) {
return head;
}
ListNode newhead = reverseByRecursion(head.next);
head.next.next = head;
head.next = null;
return newhead;
}
}
2.3 头插法逆置
https://blog.csdn.net/qq_43109561/article/details/88981480
3.求倒数第K个节点(要求只扫描一遍)
题目:求单链表的倒数第K个节点
分析:设置快、慢指针,快指针先走K步,接着快、慢指针同时走,当快指针走到末尾时,慢指针刚好走到了倒数第K个节点。
代码:
class Solution {
public static ListNode searchKNode(ListNode head,int K) {
if(k<0){
return null;
}
ListNode slowNode = head;
ListNode fastNode = head;
//快指针先走K步
int i=0;
for(; i<K && fastNode != null; i++){
fastNode = fastNode.next;
}
//长度问题
if(i != K){
return null;
}
//快、慢指针同时走
while(fastNode != null){
slowNode = slowNode.next;
fastNode = fastNode.next;
}
return slowNode;
}
}
4.求链表的中间节点(只扫描一遍)
题目:返回链表的中间结点。如果有两个中间结点,则返回第二个中间结点。
分析:设置快、慢指针,慢指针每次走一步,快指针每次走两步,当快指针为null或者快指针的下一个节点为null时停止,返回慢指针的节点。
代码:
class Solution {
public ListNode middleNode(ListNode head) {
ListNode slowNode = head;
ListNode fastNode = head;
while(fastNode != null && fastNode.next != null){
slowNode = slowNode.next;
fastNode = fastNode.next.next;
}
return slowNode;
}
}
5.判断单链表中是否存在环
https://blog.csdn.net/qq_43109561/article/details/89072424
6.找出链表入环的第一个节点
https://blog.csdn.net/qq_43109561/article/details/89072424
7.判断两个链表是否相交
题目:判断两个单链表是否相交(链表无环)。
分析:相交链表的最后节点一定是公共的,只需要找到两个链表的最后一个节点比较即可。
代码:
class Solution {
public static boolean isIntersect(ListNode headA, ListNode headB) {
if(headA == null || headB == null){
return false;
}
ListNode curA = headA;
ListNode curB = headB;
while(curA.next != null){
curA = curA.next;
}
while(curB.next != null){
curB = curB.next;
}
return curA == curB;
}
}
8.找到两个链表相交的第一个节点
题目:找到两个链表相交的第一个节点。(链表无环)
分析:采用对齐思想,先计算出两个链表的长度,指针cur1、cur2分别指向较长的链表头部、短的链表头部,cur1先走Math.abs(lenA-lenB)步,此时抹掉了两个链表的长度差,再同时遍历两个链表,遇到相同的节点返回。
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
if(headA == null || headB == null){
return null;
}
int lenA = getLength(headA);
int lenB = getLength(headB);
int d = Math.abs(lenA-lenB);
ListNode cur1;//长的链表
ListNode cur2;
if(lenA >= lenB){
cur1 = headA;
cur2 = headB;
}else{
cur1 = headB;
cur2 = headA;
}
for(int i=0; i<d; i++){
cur1 = cur1.next;
}
while(cur1 != cur2){
cur1 = cur1.next;
cur2 = cur2.next;
}
return cur1;
}
private int getLength(ListNode head){
ListNode cur = head;
int count = 0;
while(cur != null){
count++;
cur = cur.next;
}
return count;
}
}