
反转链表
206. 反转链表 - 力扣(LeetCode)
思路解透

 本题就是通过不停地将最先的 head 节点位置的后一位插到最前面,完成链表的反转
 本题需要两个节点变量
- cur:其任务就是定位到原- head节点位置的前一位,然后将自己插入到当前- head节点的前面- 因为链表的最后一个节点都是指向一个 null值,所以需要将最先的head节点的next置为空
- 但在将 head.next置为null之前,需要先将cur节点实例化出来,不然cur就无法找到原先的head节点的位置了
 
- 因为链表的最后一个节点都是指向一个 
- curN:其任务就是定位到- cur的后一个节点,方便让- cur进行循环插入- 其在循环中进行实例化,因为每一次插入完成之后,curN的位置都是需要随着cur的改变而改变
- curN实例化为- cur的下一个节点。在- cur插入完成后,- cur就会定位到- curN的位置,若此为止不为- null,则继续进行前插
 
- 其在循环中进行实例化,因为每一次插入完成之后,
代码解析
class Solution {
    public ListNode reverseList(ListNode head) {
        //1. 防止空指针异常  
		if(head == null){  
    		return head;  	
		}  
		  
		//2. 将head.next置为空  
		//注意先把 cur 节点给先弄出来  
		ListNode cur = head.next;  
		head.next = null;  
		  
		//3. 进行循环头插  
		while (cur != null) {  
		    ListNode curN = cur.next;  
		    cur.next = head;  
		    head = cur;  
		    cur = curN;  
		}  
		return head;
	}
}
寻找中间节点
876. 链表的中间结点 - 力扣(LeetCode)
思路解透
解法 1:定义一个 cur 节点,从 head 节点的地方,向后走 size()/2 步,就到了中间位置
 解法 2:定义一个 slow 节点,一次走一步,在定义一个 fast 节点,一次走两步,当 fast 走完的时候,slow 就刚好在中间位置(快慢指针)
- 当有偶数个节点时,循环判断条件为:fast != null
- 当有奇数个节点时,循环判断条件为:fast.next != null
- 这里的两个条件判断顺序不能换,否则会报空指针异常错误
快慢指针原理:
路程一样的情况下,速度是两倍,那么当走完的时候,路程也是两倍
代码解析(法 1)
public ListNode middleNode(){  
    int count = 0;  
    ListNode node = head;  
    while(node != null){  
        count++;  
        node = node.next;  
    }    
    ListNode cur = head;  
    for (int i = 0; i < count/2; i++) {  
        cur = cur.next;  
    }    
    return cur;  
}
代码解析(法 2)
public ListNode middleNode(){  
    ListNode slow = head;  
    ListNode fast = head;  
    while(fast != null && fast.next != null){  
    	//slow走一步,fast走两步
        slow = slow.next;  
        fast = fast.next.next;  
    }    
    return slow;  
}
返回链表中倒数第 k 个节点
面试题 02.02. 返回倒数第 k 个节点 - 力扣(LeetCode)
思路解透
- 首先判断 k 是否合法,链表是否为为 null 
  - k <= 0,返回- -1
- (下面的第二点看完再回来)因为如果 k大于链表长度的话,当fast走k - 1步的时候就会走出链表,所以在fast走k-1步的过程中如果出现fast == null,则返回-1
 
- 定义两个节点,fast先走k - 1步,随后fast和slow一起走,当fast走到最后了,slow所在的地方就是倒数第k个节点
代码解析
public int kthToLast(int k) {  
	//判断k是否合法,链表是否为null
    if(k <= 0 || head == null) {  
        return -1;  
    }    
    ListNode fast = head;  
    ListNode slow = head;  
    int count = 0;  
    while (count != k - 1) {  
        //fast先向后走k-1步        
        fast = fast.next;  
        if(fast == null){
        //判断k是否合法
            return -1;  
        }
        count++;  
    }    
    while (fast.next != null){
    	//两个节点一起向后走,直到fast走到最后一个  
        fast = fast.next;  
        slow = slow.next;  
    }    
    return slow.val;  
}
合并两个有序链表
21. 合并两个有序链表 - 力扣(LeetCode)
思路解透
创建一个新的链表,为虚拟节点(傀儡节点),然后对需要合并的两个链表中的值进行比较,谁小谁就接在虚拟节点后面
- 创建一个新的节点 newH,在这个链表上进行合并,再创建一个tmp节点,用来指向newH链表中的最后一个节点
- 当 headA != null && headB != null的时候,进行比较- 若 headA. val < headB. val,则将headA这个节点接在newH后面,即接在tmp节点后面,最后tmp和headB节点均向后移一位
- 若 headA. val > headB. val,则将headB这个节点接在newH后面,即接在tmp节点后面,最后tmp和headB节点均向后移一位
 
- 若 
- 当 headA == null || headB == null的时候,剩下的一个链表里面的节点直接接到newH后面就行了
- 最后返回 newH. next,因为newH是一个虚拟节点,不存在于要合并的链表中,它只是一个引子
代码解析
public ListNode mergeTwoLists(ListNode headA, ListNode headB) {  
    ListNode newH = new ListNode(0);  
    ListNode tmp = newH;  
    while(headA != null && headB != null){  
        if(headA.val < headB.val){  
        	//将headA接到newH上面,随后后移
            tmp.next = headA;  
            headA = headA.next;  
            tmp = tmp.next;  
        }else if{  
        	//将headB接到newH上面,随后后移
            tmp.next = headB;  
            headB = headB.next;  
            tmp = tmp.next;  
        }    
    }    
    if(headA == null){  
    	//headA空了,将headB直接接到newH后面
        tmp.next = headB;  
    }    
    //headB空了,将headA直接接到newH后面
    if (headB == null) {  
        tmp.next = headA;  
    }    
    return newH.next;  
}
分割链表
链表分割_牛客题霸_牛客网 (nowcoder.com)
思路解透
构建两个区间,一个里面接上小于 x 的节点,一个里面接上大于 x 的节点,最后将这两个区间连接起来
- 若链表为空
- 遍历链表 
  - 创建一个 cur节点,用来遍历链表
 
- 创建一个 
- 把对应的节点放到指定区间 
  - 在小区间里 
    - 创建 bs(before start) 节点指向区间里面最前面的一个节点,创建be(before end) 节点指向区间里面最后一个节点
- 在小区间里面插入第一个节点的时候,bs和be都指向这个节点,随后cur向后移
- 之后插入的节点均为尾插,bs位置不变,be始终指向新插入的节点
 
- 创建 
- 在大区间里 
    - 创建 as(after start) 节点指向区间里面最前面的一个节点,创建ae(after end) 节点指向区间里面最后一个节点
- 在小区间里面插入第一个节点的时候,as和ae都指向这个节点,随后cur向后移
- 之后插入的节点均为尾插,as位置不变,ae始终指向新插入的节点
 
- 创建 
 
- 在小区间里 
    
- 把两个区间连接起来 
  - 将 be节点和as节点连接起来,并且将ae节点的next置为null,作为新链表的尾巴,并且返回bs节点
- 若所有节点全在小区间里,就将 be节点的next置为null,作为新链表的尾巴,并且返回bs节点
- 若全在大区间里,则返回 ae节点
 
- 将 
代码解析
public ListNode partition(ListNode pHead, int x) {  
    //判断空链表
    if(pHead == null){  
        return null;  
    }      
    //小区间的两个节点
    ListNode bs = null;  
    ListNode be = null;  
    //大区间的两个节点
    ListNode as = null;  
    ListNode ae = null;  
	
	//遍历链表的节点
    ListNode cur = pHead;  
    while(cur != null){  
    	//插入小区间
        if(cur.val < x){  
        	//第一次插入
            if(bs == null){  
                bs = be = cur;  
            }else{  
                be.next = cur;  
                be = be.next;  
            } 
        //插入大区间       
        }else{  
        	//第一次插入
            if(as == null){  
                as = ae = cur;  
            }else{  
                ae.next = cur;  
                ae = ae.next;  
            }        
        }        
    cur = cur.next;  
    }    
    //当节点全部都在小区间时,直接返回大区间
    if(bs == null){  
        return as;  
    }    
    
    //进行大小区间的拼接
    be.next = as;  
    //大区间不为空,把最后一个节点置空,作为尾巴
    if(as != null){  
        ae.next = null;  
    }  
    return bs;  
}
回文链表
链表的回文结构_牛客题霸_牛客网 (nowcoder.com)
思路解透
- 首先用快慢指针找到中间的节点(上面第二题有讲解)
- 再对后半部分进行反转(上面第一题有讲解)
- 最后让首尾两个节点往中间走,直到相遇,返回 true;若是偶数个节点,则只需要前面节点的next与后面节点的值相等即可返回true
代码解析
public boolean chkPalindrome(ListNode head) {  
    // write code here  
    if (head == null) {  
        return true;  
    }  
    //1. 找到链表的中间节点  
    ListNode fast = head;  
    ListNode slow = head;  
  
    while (fast != null && fast.next != null) {  
        slow = slow.next;  
        fast = fast.next.next;  
    }  
    //2. 反转后半节点  
    ListNode cur = slow.next;  
    slow.next = null;  
    while (cur != null) {  
        ListNode curN = cur.next;  
        cur.next = slow;  
        slow = cur;  
        cur = curN;  
    }  
    //3. slow从后往前,head从前往后,直到相遇  
    while (head != slow) {  
        if (head.val != slow.val) {  
            return false;  
        }        
        //当节点个数为偶数
        if (head.next == slow)  
            return true;  
        head = head.next;  
        slow = slow.next;  
    }    
    return true;  
}
相交链表
160. 相交链表 - 力扣(LeetCode)
思路解透
- 首先计算两个链表的长度,并计算他们的差值
- 随后让长的链表的头节点先走“差值“步,让他们站在同一起跑线
- 最后让他们携手同行,直到相遇,返回任意一个链表;若最终零个引用都为空,证明不相交,返回 null
代码解析
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {  
    //1. 计算两个链表的长度,并计算差值  
    int lenA = 0;  
    int lenB = 0;  
    ListNode curA = headA;  
    ListNode curB = headB;  
    while (curA != null) {  
        curA = curA.next;  
        lenA++;  
    }    
    while (curB != null) {  
        curB = curB.next;  
        lenB++;  
    }    
    int len = lenA - lenB;  
  
    curA = headA;  
    curB = headB;  
  
    //2. 根据差值,长的链表头节点先走len步,  
    // 让两个链表在同一起跑线  
    if (len > 0) {  
        int count = 0;  
        while (count != len) {  
            curA = curA.next;  
            count++;  
        }    
    } else {  
        int count = 0;  
        while (count != -len) {  
            curB = curB.next;  
            count++;  
        }    
    }  
    //3. 两个链表的节点携手同行,直到相等  
    while (curA != curB) {  
        curA = curA.next;  
        curB = curB.next;  
    }    
    if (curA == null) {  
        //若两个引用都为空,证明不相交  
        return null;  
    }    
    return curA;  
}
环形链表
141. 环形链表 - 力扣(LeetCode)
思路解透
- 定义两个节点,一个一次走一步,一个一次走两步
- 当走得快的节点不为空,并且走得快的节点的 next 不为空,循环就一直继续
- 当两个节点相等,则返回 true
假设链表带环,两个指针最后都会进入环,快指针先进环,慢指针后进环。当慢指针刚进环时,可能就和快指针相遇了,最差情况下两个指针之间的距离刚好就是环的长度。此时,两个指针每移动一次,之间的距离就缩小一步,不会出现每次刚好是套圈的情况
因此:在慢指针走到一圈之前,快指针肯定是可以追上慢指针的,即相遇。
代码解析
public boolean hasCycle(ListNode head) {  
    ListNode fast = head;  
    ListNode slow = head;  
    while(fast != null && fast.next != null){  
        fast = fast.next.next;  
        slow = slow.next;  
        if(fast == slow)  
            return true;  
    }    
    return false;  
}
环形链表Ⅱ
142. 环形链表 II - 力扣(LeetCode)
思路解透

代码解析
public ListNode detectCycle(ListNode head) {  
    //1. 判断是否有环  
    ListNode fast = head;  
    ListNode slow = head;  
    while (fast != null && fast.next != null) {  
        fast = fast.next.next;  
        slow = slow.next;  
        //有环,跳出循环  
        if (fast == slow) {  
            break;  
        }    
    }    
    //若是因为没有环而跳出循环的话,返回null  
    if (fast == null || fast.next == null) {  
        return null;  
    }    
    //此时slow在相遇点,将fast拿到起始点  
    //让他们相向而行,相遇点即为入口点  
    fast = head;  
    while(fast != slow) {  
        fast = fast.next;  
        slow = slow.next;  
    }    
    return fast;  
}




























