1. 删除链表中倒数第n个节点(leetcode19)
思路:两指针法,前一个指针先走n步,然后两个指针一起走,当前一个指针走到链尾时,后一个指针正好位于待删除节点的上一个节点
复杂度分析:时间复杂度o(n),空间复杂度o(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 flag_head = new ListNode(0, head); //生成一个节点,该节点的下一个节点指向链表的头结点
ListNode fast = head; //生成一个快指针,指向头结点
ListNode slow = flag_head; //慢节点指向一开始生成的节点
int i = 0;
while(i < n){ //快指针先走n步
fast = fast.next;
i++;
}
while (fast != null) { //两个指针同步伐走
fast = fast.next;
slow = slow.next;
}
slow.next = slow.next.next; //删除倒数第n个节点
ListNode ans = flag_head.next; //将标记的head的值返回
return ans;
}
}
2. 两个有序链表合并(leetcode21)
思路:可以使用链表的特性将两个链表合并,使用pre节点作为合并链表的标记指针
复杂度分析:时间复杂度o(n+m),其中n和m分别为两条链表的长度,空间复杂度为o(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 mergeTwoLists(ListNode l1, ListNode l2) {
ListNode forHead = new ListNode();
ListNode pre = forHead;
while(l1 != null && l2 != null){
if(l1.val<=l2.val){
pre.next = l1;
l1 = l1.next;
}else{
pre.next = l2;
l2 = l2.next;
}
pre = pre.next;
}
pre.next = l1==null? l2:l1; //将其中一条有剩余元素的链表直接加到合并链表末端
return forHead.next;
}
}
3. 链表中环的检测(leetcode141)
思路分析:两指针法,分为快慢两个指针,慢的指针每次走一步,快的指针每次走两步,如果两个指针最后相遇这说明有环,如果直到快指针走到了链表尾两个指针还没相遇,这说明无环。
复杂度分析:时间复杂度o(n),空间复杂度o(1)
注:思考开始时赋初值的方法,快指针为什么不和慢指针同步出发(即fast=slow=head)?
/**
* Definition for singly-linked list.
* class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public boolean hasCycle(ListNode head) {
if(head == null){
return false;
}
ListNode slow = head;
ListNode fast = head.next;
while(slow != fast){
if(fast == null || fast.next == null){
return false;
}
slow = slow.next;
fast = fast.next.next;
}
return true;
}
}
4. 单链表反转(leetcode206)
思路:单链表反转的关键是为了防止链断,我们需要使用一个temp节点将标记指针的next节点记住
复杂度分析:时间复杂度o(n),空间复杂度o(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 reverseList(ListNode head) {
ListNode pre = null;
ListNode cur = head;
while(cur != null){
ListNode tempNode = cur.next; //防止链断裂
cur.next = pre;
pre = cur;
cur = tempNode;
}
return pre;
}
}
5. 求链表的中间节点(leetcode876)
思路:与回文串属于同一题型,用两指针法
复杂度分析:时间复杂度o(n),空间复杂度o(1)
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode middleNode(ListNode head) {
ListNode slow = head;
ListNode fast = head;
while(fast !=null && fast.next != null){
slow = slow.next;
fast = fast.next.next;
}
return slow;
}
}