今日鸡汤:“遗憾谁没有呢?人往往都是快死的时候,才发现人生最大的遗憾就是一直在遗憾过去的遗憾。”
1. 两两交换链表中的结点LeetCode24
题目:
给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。
示例:
输入:head = [1,2,3,4]
输出:[2,1,4,3]
思路:
1.一开始有想到用虚拟结点dummy以及cur去遍历,但是发现是死循环…可恶,然后发现自己想得很复杂,用了pre,cur,next三个指针,导致自己又被绕进去了…
(不过鼓励鼓励自己就是,今天还有一点进步就是已经想到了Dummy结点这个东西!每天进步一点点nice!)
2.本题需要注意事项:
操作链表结点时一定要注意,你需要找的是需要操作结点的前一个结点,才能操作结点。
while循环中的判断顺序不能改变,不然可能会出现操作空指针的报错。
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode swapPairs(ListNode head) {
ListNode dummy=new ListNode(-1,head);
ListNode cur=dummy;
//注意操作指针要指向反转结点的前一个结点。
while(cur.next!=null && cur.next.next!=null){
//注意两个判断顺序不能出错,不然当cur.next为空时,会出现操作空指针的现象
ListNode temp=cur.next;
ListNode temp1=cur.next.next.next;
cur.next=cur.next.next;
cur.next.next=temp;
temp.next=temp1;
//cur.next.next.next=temp1;
cur=cur.next.next;
//temp.next=temp1;
//cur=temp1;操作结点时需要指向结点前面一个结点的元素才可以
}
return dummy.next;
}
}
2.删除链表倒数第n个结点Leetcode19
题目:
给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。
示例:
输入:head = [1,2,3,4,5], n = 2
输出:[1,2,3,5]
思路:
1.对于自己而言,一开始思考还是只会用暴力思维(或者更像数组的思维方式)就是希望先找到最后一个元素,再往回走,但是这里需要注意的是,这样做时,我自己也不知道该怎么弄指针
2.正确思路:快慢指针法
首先,如果先让快指针走n步,之后快慢指针同时前进的话,其实最后当快指针到尾结点的时候,慢指针走到的是第n个结点。但是操作某结点时,需要的是找到它的前一个结点,通过前一个结点的指针进行操作,因此快指针需要提前走n+1步。
(发现理解原理之后,写代码快多了)
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode dummy=new ListNode(-1,head);
ListNode fast=dummy;
ListNode slow=dummy;
for(int i=1;i<=n+1;i++){
fast=fast.next;
}//快指针需要先走n+1步,从而让慢指针停在倒数第n个元素的前一个元素
while(fast!=null){
slow=slow.next;
fast=fast.next;
}
slow.next=slow.next.next;
return dummy.next;
}
}
3.链表相交面试题02.07
题目:
给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回 null 。
示例:
输入:intersectVal = 8, listA = [4,1,8,4,5], listB = [5,0,1,8,4,5], skipA = 2, skipB = 3
输出:Intersected at ‘8’
解释:相交节点的值为 8 (注意,如果两个链表相交则不能为 0)。
从各自的表头开始算起,链表 A 为 [4,1,8,4,5],链表 B 为 [5,0,1,8,4,5]。
在 A 中,相交节点前有 2 个节点;在 B 中,相交节点前有 3 个节点。思路:
可以利用快慢指针的思路解决。(假设长链的为A,短链为B)
其实从上面的图就可以看到,如何两条链相交的话,长链指针一定要比短链先移动lenA-lenB,这样再去比较之后的元素指针是否相同即可。
这里需要注意的是,为了方便起见,可以认为将长短链进行调整。
调整两者的长度以及头结点的指针即可。
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
int lenA=0;
int lenB=0;
ListNode curA=headA;
ListNode curB=headB;
while(curA!=null){
lenA+=1;
curA=curA.next;
}
while(curB!=null){
lenB+=1;
curB=curB.next;
}
curA = headA;
curB = headB;
// 让curA为最长链表的头,lenA为其长度
if (lenB > lenA) {
//1. swap (lenA, lenB);
int tmpLen = lenA;
lenA = lenB;
lenB = tmpLen;
//2. swap (curA, curB);
ListNode tmpNode = curA;
curA = curB;
curB = tmpNode;
}
int gap=lenA-lenB;
for(int i=gap;i>0;i--){
curA=curA.next;
}
while(curA!=null){
if(curA==curB){
return curB;
}
curA=curA.next;
curB=curB.next;
}
return null;
}
}
环形链表Leetcode142
题目:
给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。
不允许修改 链表。
示例:
输入:head = [3,2,0,-4], pos = 1
输出:返回索引为 1 的链表节点
解释:链表中有一个环,其尾部连接到第二个节点。
思路:
该题思路建议参考卡哥的讲解,真的很妙!!(菜鸡能做的只有理解然后复现代码罢了)环形链表
/**
* Definition for singly-linked list.
* class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public ListNode detectCycle(ListNode head) {
ListNode slow = head;
ListNode fast = head;
while (fast != null && fast.next != null) {
//快指针的步长是2,慢指针的步长是1,所以如果有环,那么在环中,快指针一定会追上慢指针。
slow = slow.next;
fast = fast.next.next;
if (slow == fast) {// 有环
ListNode index1 = fast;
ListNode index2 = head;
// 两个指针,从头结点和相遇结点,各走一步,直到相遇,相遇点即为环入口
while (index1 != index2) {
index1 = index1.next;
index2 = index2.next;
}
return index1;
}
}
return null;
}
}
PS:
怎么说呢,感觉最近充实了很多,毕竟写代码真的挺耗时间的哈哈哈,算是消磨时间的好去处了,尤其是当你遇到一个非常非常非常无语的bug的时候hhh。
希望自己能够坚持下去!!!加油!!