链表类问题通常比较简单,面试中应该不会出现这么简单的题型,需要注意的地方只有两个:
- 使用虚拟头节点增加便捷性
- 判断链表是否有环
使用虚拟头节点
力扣题目链接:
203. 移除链表元素
这道题目比较简单,但是使用虚拟头节点会更加便捷,统一操作。
class Solution {
public ListNode removeElements(ListNode head, int val) {
// 单独处理开头while(head!=null && head.val== val){
// head = head.next;
// }
if(head == null){
return null;
}
// 设置头节点 来统一操作, 这样就不用专门处理head了
ListNode preHead = new ListNode(-1,head);
ListNode fast = preHead.next;
ListNode slow = preHead;
while(fast !=null){
if(fast.val == val){
slow.next = fast.next;
fast = fast.next;
} else{
slow = slow.next;
fast = fast.next;
}
}
return preHead.next;
}
}
力扣题目链接:
24. 两两交换链表中的节点
两两交换链表中的结点,使用虚拟头节点也是更方便的。这个题之前老想着一次处理四个结点,但是用了虚拟头节点后,发现处理两个就好。代码随想录的步骤如下:
class Solution {
public ListNode swapPairs(ListNode head) {
ListNode dumyhead = new ListNode(-1); // 设置一个虚拟头结点
dumyhead.next = head; // 将虚拟头结点指向head,这样方面后面做删除操作
ListNode cur = dumyhead;
ListNode temp; // 临时节点,保存两个节点后面的节点
ListNode firstnode; // 临时节点,保存两个节点之中的第一个节点
ListNode secondnode; // 临时节点,保存两个节点之中的第二个节点
while (cur.next != null && cur.next.next != null) {
temp = cur.next.next.next;
firstnode = cur.next;
secondnode = cur.next.next;
cur.next = secondnode; // 步骤一
secondnode.next = firstnode; // 步骤二
firstnode.next = temp; // 步骤三
cur = firstnode; // cur移动,准备下一轮交换
}
return dumyhead.next;
}
}
双指针法
链表题目中的双指针,既有速度相同的指针法,也有快慢指针法,依据情况而定。
普通双指针题目: 比较简单不再多说
206. 反转链表
// 双指针
class Solution {
public ListNode reverseList(ListNode head) {
ListNode prev = null;
ListNode cur = head;
ListNode temp = null;
while (cur != null) {
temp = cur.next;// 保存下一个节点
cur.next = prev;
prev = cur;
cur = temp;
}
return prev;
}
}
快慢指针:有速度不一样的指针,也有先走和后走的指针。
比如:
19. 删除链表的倒数第 N 个结点
这个题如果想要一趟就完成,就要先走n步,然后让快慢指针齐头并进就可以一趟遍历完。
面试题 02.07. 链表相交
这道题需要先计算两个链表的长度,然后让长的先走出长度差,再齐头并进即可。
判断链表是否有环
力扣题目:
142. 环形链表 II
判断链表是否有环需要一定的技巧性,可以使用快慢指针法,分别定义 fast 和 slow 指针,从头结点出发,fast指针每次移动两个节点,slow指针每次移动一个节点,如果 fast 和 slow指针在途中相遇 ,说明这个链表有环。因为fast走的更快,如果进入环以后一定能追上slow指针,如果fast先遇到了null的情况,则是一定没有环的。
根据上面的推导,得出 x = (n-1)(y+z)+z 这一结论
说明什么呢,y+z即是完整的走完环一圈,那么让两个指针从头节点和第一次的相遇点一起出发,那么他们再次相遇的点就一定是环的入口:
public class Solution {
public ListNode detectCycle(ListNode head) {
ListNode fast = head;
ListNode slow = head;
if(head == null){
return null;
}
while( fast.next!=null&& fast.next.next!=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;
}
}