目录
24.两两交换链表中的节点
本题主要是模拟指针交换的过程,重点还是之前说的,模拟指针next作新指向的时候,模拟之前一定要先把原先的链断开,断开之后就知道在此之前需不需要保存备份。
再者还有一个point就是空指针,我经常会遇到空指针的异常,所以如何避免是很重要的
本题中的while循环条件:中间为什么是&&一击为什么cur.next在前面很有考究
class Solution {
/**
* 将数组里面的元素两两交换
* @param head
* @return
*/
public ListNode swapPairs(ListNode head) {
ListNode dh=new ListNode(0);
dh.next=head;
ListNode cur=dh;
while (cur.next!=null&&cur.next.next!=null){
//考虑奇偶的情况,并且用&&以及先后顺序的原因为了防止空指针异常
ListNode temp=cur.next;
cur.next=cur.next.next;
ListNode tempjump=cur.next.next;
cur.next.next=temp;
temp.next=tempjump;
cur=cur.next.next;
}
return dh.next;
}
}
*9.删除链表的倒数第N个结点
第一反应就是暴力做法,先遍历一下知道他有多少个结点,然后正向删除
class Solution {
/**
* 删除倒数第n个结点,给的n是从后往前数的
*
* @param head
* @param n
* @return
*/
public ListNode removeNthFromEnd(ListNode head, int n) {
int sum = getLinkSize(head);//链表长度
int index = sum - n + 1;//处理一下如果删除最后一个值
ListNode ans=deleteReveIndex(head, index, sum);
return ans;
}
public int getLinkSize(ListNode head) {//得到link的长度
ListNode cur = head;
int sum = 1;
while (cur.next != null) {
cur = cur.next;
sum++;
}
return sum;
}
public ListNode deleteReveIndex(ListNode head, int index, int sum) {//正向去找第index值并且删除
if (index == 1) {
head = head.next;
return head;
}
ListNode cur = head;
for (int i = 1; i < index - 1; i++) {//找到它前面的那个
cur = cur.next;
}
cur.next = cur.next.next;
return head;
}
}
然后看了讲解才发现可以用双指针,快指针先走n步,然后慢指针和快指针同时移动,最后快指针暂停的位置,慢指针便是要移除的数。
*之前听过不少算法课,感觉在链表这边用快慢指针还是特别频繁的,包括判环,判相交。这个思路还是要多练才能运用。
class Solution {
/**
* 移除最后的第n个元素
*
* @param head
* @param n
* @return
*/
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode dh=new ListNode(0);
dh.next=head;
ListNode fast=dh,slow=dh;
for (int i = 0; i < n; i++) {
fast=fast.next;
}
while (fast.next!=null){
slow=slow.next;
fast=fast.next;
}
slow.next=slow.next.next;
return dh.next;
}
}
我这里用虚拟头结点之后其实i跳了n步,跳到最后一个结点停。
142.环形链表II
快慢指针,fast走两步,slow走一步,然后fast和slow如果走不到头的话,就是有环,有环返回相交的第一个结点。快指针回到开头,然后快慢指针同时移动一步,相遇的时候就是那个结点
point:空指针异常,循环条件的判定
当然也可以用hashmap判断这个ListNode是否被包含
卡哥快慢指针思路的证明:环找到了,入口呢?
public class Solution {
/**
* 判断链表是否有环----->利用快慢指针去找第一个成环的结点
* @param head
* @return
*/
public ListNode detectCycle(ListNode head) {
ListNode fast=head,slow=head;//快指针一次走两步,慢指针一次走一步
if(head==null||head.next == null){
return null;
}
//如果没环的话fast会走到头
while (fast!=null&&fast.next!=null&&slow!=null){
fast=fast.next.next;
slow=slow.next;
if(fast==slow){
fast=head;
while (fast!=slow){
fast=fast.next;
slow=slow.next;
}
return fast;
}
}
return null;
}
}
*面试题0207.链表相交
这道题的前提是判断两个链表是否有环,然后对相交来进行分类讨论
class Solution {
/**
* 判断两个链表是否相交---->返回相交的第一个结点
*
* @param headA
* @param headB
* @return
*/
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
if (headA == null || headB == null) {
return null;
}
ListNode huanA = detectCycle(headA);
ListNode huanB = detectCycle(headB);//判断AB是否有环
//情况1:AB都没有环
if (huanA == null && huanB == null) {
ListNode endA = searchLastNode(headA);
ListNode endB = searchLastNode(headB);//找AB最后的结点
if (endA != endB) {
//两链表不可能相交
return null;
}
//两链表相交,且AB无环---->找链表的差值,长的那个先走差值步,然后每个都开始走一步----->直到相交
return sectionA(headA, headB);
}
//都有环
else if (huanA != null && huanB != null) {
if (huanA == huanB) {//出现环的第一个结点相等--->看作A情况
return sectionA(headA, headB);
} else {//出现环的第一个结点不相交------->可能能绕出来环,也有可能绕不出来
ListNode cur = huanA;
while (true) {
cur = cur.next;
if (cur == huanB) {//可以绕道环B上
return huanA;//此时return环A和环B都可以
}
if (cur == huanA) {//绕回环A
return null;
}
}
}
}
return null;//一个有环一个没环,不可能相交
}
/**
* 判断链表是否有环----->利用快慢指针去找第一个成环的结点
*
* @param head
* @return
*/
public ListNode detectCycle(ListNode head) {
ListNode fast = head, slow = head;//快指针一次走两步,慢指针一次走一步
if (head == null || head.next == null) {
return null;
}
//如果没环的话fast会走到头
while (fast != null && fast.next != null && slow != null) {
fast = fast.next.next;
slow = slow.next;
if (fast == slow) {
fast = head;
while (fast != slow) {
fast = fast.next;
slow = slow.next;
}
return fast;
}
}
return null;
}
/**
* 找这个链表最后一个结点
*
* @param head
* @return
*/
public ListNode searchLastNode(ListNode head) {
ListNode cur = head;
while (cur.next != null) {
cur = cur.next;
}
return cur;
}
/**
* 找这个链表的长度
*
* @param head
* @return
*/
public int listLength(ListNode head) {
int sum = 0;
ListNode cur = head;
while (cur != null) {
sum++;
cur = cur.next;
}
return sum;
}
/**
* 找链表的差值,长的那个先走差值步,然后每个都开始走一步----->直到相交
*
* @return 第一个相交的结点
*/
public ListNode sectionA(ListNode headA, ListNode headB) {
int sumA = listLength(headA);
int sumB = listLength(headB);
ListNode fast = new ListNode(0);
ListNode slow = new ListNode(0);
if (sumA >= sumB) {
fast = headA;
slow = headB;
for (int i = 0; i < sumA - sumB; i++) {
fast = fast.next;
}
} else {//B的长度比较长
fast = headB;
slow = headA;
for (int i = 0; i < sumB - sumA; i++) {
fast = fast.next;
}
}//先走差值步--->然后一起走
while (fast != slow) {
fast = fast.next;
slow = slow.next;
}
return fast;
}
}