文章目录
前言
本篇博客继续来看链表的笔试题
一、Leetcode–206反转链表
1.题目描述
2.思路讲解
本题一共有三种解法
1.边遍历原链表边新建一个新链表头插入新链表,头插的顺序刚好和原链表的顺序相反,这是在没有要求空间复杂度的情况下,若要求空间复杂度为O(1),那么此时就不能用这个解法
2.原地移动原链表,所谓的反转链表就是原来1指向2,现在2指向1
最后反转的链表1指向null
那么就让prev从null开始走,然后cur = prev.next ,此时还需一个next引用暂存一下下一个节点的地址,然后不断的让三指针后移,并且不断的让cur指向prev,直到cur走到空,整个链表遍历结束,而prev恰好留在反转后的链表的头结点
3.递归写法,我们把头结点之后的子链表交给子函数处理,然后把头结点拼接在反转后的链表后,然后要让head.next = null,因为此时head还指向的是第二个节点的地址,如果不断引用,就会形成一个环
3.代码实现
3.1头插
public ListNode reverseList(ListNode head) {
ListNode dummyHead = new ListNode();
while (head != null){
ListNode note = new ListNode(head.val);
note.next = dummyHead.next;
dummyHead.next = note;
head = head.next;
}
return dummyHead.next;
}
3.2迭代
/**
* 迭代
* @param head
* @return
*/
public ListNode reverseList(ListNode head) {
if (head == null || head.next == null){
return head;
}
ListNode prev = null;
ListNode cur = head;
while (cur != null){
ListNode note = cur.next;
cur.next = prev;
prev = cur;
cur = note;
}
return prev;
}
3.3递归写法
/**
* 传入一个链表头结点,就能把这个链表反转,并且返回反转后的头结点
* @param head
* @return
*/
public ListNode reverseList(ListNode head) {
if (head == null || head.next == null){
return head;
}
ListNode newHead = new ListNode();
ListNode note = head.next;
newHead = reverseList(head.next);
note.next = head;
head.next = null;
return newHead;
}
二、Leetcode–876链表的中间节点
1.题目描述
2.思路讲解
1.如果此时我们知道链表的长度,那么这个题就非常的简单,所以第一种思路就是遍历链表加计数,知道链表的长度后,我们让链表的长度为n,我们让middle这个引用从头开始走n / 2步就到了中间节点
奇数:1 -> 2 -> 3 -> 4 -> 5
此时长度为5 ==>5 / 2 = 2,从头开始走2步就到了中间节点
偶数:1 -> 2 -> 3 -> 4 -> 5 -> 6
此时长度为6–>6 / 2 = 3,从头开始走3步就到了中间结点
2.快慢指针,引入两个引用,让一个引用多走几步或者先走
那么对于这道题,我们引入两个指针,fast,low,让fast和low都从链表头开始走,fast一次走两步,low一次走一步,当fast走到null或者fast走到最后一个节点时,那么此时的low引用刚好指向链表的中间结点
3.代码实现
3.1遍历链表
public ListNode middleNode(ListNode head) {
int count = 0;
for (ListNode x = head;x != null;x = x.next){
count++;
}
ListNode middle = head;
int middleIndex = count / 2;
for (int i = 0; i < middleIndex; i++) {
middle = middle.next;
}
return middle;
}
3.2快慢指针
public ListNode middleNode(ListNode head) {
if (head == null || head.next == null){
return head;
}
ListNode fast = head;
ListNode low = head;
while (fast != null && fast.next != null){
fast = fast.next.next;
low = low.next;
}
return low;
}
三、Leetcode–剑指offer22
1.题目描述
2.思路讲解
1.如果拿到一个链表的长度,本题一样会变得很简单,拿到一个链表的长度n,我们只需要让一个引用从头结点开始走n - k步就走到了当前链表的倒数第k 个节点,但此时要注意k的合法性,此时k有可能大于size
1 -> 2 -> 3 -> 4 -> 5 , k = 2, n = 5 , n - k = 3
此时只需要从头结点向后走三步就到了倒数第二个节点
2.本题也可以用快慢指针的解法,同样引入fast和low两个引用,让fast和low都从头结点开始走,让fast先走k步,然后让双指针同时后移,当fast走到null时,low指针刚好指向倒数第k个节点
3.代码实现
1.遍历链表
public ListNode getKthFromEnd(ListNode head, int k) {
if (head == null || k <= 0){
return null;
}
int count = 0;
for (ListNode x = head;x != null;x = x.next){
count ++;
}
ListNode cur = head;
for (int i = 0; i < count - k; i++) {
cur = cur.next;
}
return cur;
}
2.快慢指针
/**
* 快慢指针的派生问题
* @param head
* @param k
* @return
*/
public ListNode getKthFromEnd(ListNode head, int k) {
if (head == null || k <= 0){
return null;
}
ListNode fir = head;
ListNode sec = head;
int count = 0;
while (fir != null){
fir = fir.next;
count ++;
if (count >= k + 1){
sec = sec.next;
}
}
if (k > count){
return null;
}
return sec;
}