?
一、删除链表
1、递归
public ListNode removeElements(ListNode head, int val) {
if (head == null) return head;
head.next = removeElements(head,val);
return head.val == val ? head.next : head;
}
时间复杂度:O(n),因为每次递归只遍历头节点,有n个节点所以相当于遍历了一遍链表,所以是O(n)。
空间复杂度:O(n),每次递归不开辟新的空间但是递归会开辟栈空间,需要开辟n个栈空间用于递归,所以空间复杂度也是O(n)。
2、迭代
public ListNode removeElements(ListNode head, int val) {
ListNode newHead = new ListNode();
newHead.next = head;
ListNode cur = newHead;
while (cur.next != null) {
if (cur.next.val == val) {
cur.next = cur.next.next;
}else {
cur = cur.next;
}
}
return newHead.next;
}
时间复杂度:O(n),其中 nn 是链表的长度。需要遍历链表一次。
空间复杂度:O(1)。
二、定义链表节点和链表
class ListNode{
int val;
ListNode next;
public ListNode() {
}
public ListNode(int val) {
this.val = val;
}
public ListNode(int val, ListNode next) {
this.val = val;
this.next = next;
}
}
class MyLinkedList {
int size;
ListNode head;
public MyLinkedList() {
size = 0;
head = new ListNode();
}
public int get(int index) {
if (index < 0 || index >= size) return -1;
ListNode cur = head;
for (int i = 0; i <= index; i++) {
cur = cur.next;
}
return cur.val;
}
public void addAtHead(int val) {
addAtIndex(0, val);
}
public void addAtTail(int val) {
addAtIndex(size, val);
}
public void addAtIndex(int index, int val) {
if (index > size) return;
size++;
if (index < 0) index = 0;
ListNode cur = head;
for (int i = 0; i < index; i++) {
cur = cur.next;
}
ListNode tmp = cur.next;
cur.next = new ListNode(val);
cur.next.next = tmp;
}
public void deleteAtIndex(int index) {
if (index < 0 || index >= size) return;
ListNode cur = head;
for (int i = 0; i < index; i++) {
cur = cur.next;
}
cur.next = cur.next.next;
size--;
}
}
三、反转链表
1、迭代
public ListNode reverseList(ListNode head) {
ListNode cur = head;
ListNode pre = null;
while (cur != null) {
ListNode tmp = cur.next;
cur.next = pre;
pre = cur;
cur = tmp;
}
return pre;
}
2、递归
public ListNode reverseList(ListNode head) {
return reverse(null, head);
}
private ListNode reverse(ListNode prev, ListNode cur) {
if (cur == null) return prev;
ListNode tmp = cur.next;
cur.next = prev;
return reverse(cur, tmp);
}
四、交换链表
1、迭代
public ListNode swapPairs(ListNode head) {
if (head == null || head.next == null) return head;
ListNode newHead = new ListNode();
newHead.next = head;
ListNode cur = newHead;
while (cur.next != null && cur.next.next != null){
ListNode first = cur.next;
ListNode second = first.next;
ListNode tmp = second.next;
cur.next = second;
second.next = first;
first.next = tmp;
cur = first;
}
return newHead.next;
}
复杂度分析
时间复杂度:O(n),其中 n 是链表的节点数量。需要对每个节点进行更新指针的操作。 空间复杂度:O(1)。
2、递归
public ListNode swapPairs(ListNode head) {
if (head == null || head.next == null) return head;
ListNode node = head.next;
ListNode tmp = node.next;
node.next = head;
head.next = swapPairs(tmp);
return node;
}
复杂度分析
时间复杂度:O(n),其中 n是链表的节点数量。需要对每个节点进行更新指针的操作。 空间复杂度:O(n),其中 n是链表的节点数量。空间复杂度主要取决于递归调用的栈空间。
五、删除倒数第n个节点
1、快慢指针
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode newHead = new ListNode();
newHead.next = head;
ListNode fast = newHead;
ListNode slow = newHead;
while (fast != null) {
if (n >= 0) {
n--;
}else {
slow = slow.next;
}
fast = fast.next;
}
slow.next = slow.next.next;
return newHead.next;
}
时间复杂度:O(L),其中 L是链表的节点数量。需要对每个节点进行更新指针的操作。 空间复杂度:O(1)。
2、栈
时间复杂度和空间复杂度都是O(L)
六、链表的交点
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
ListNode preA = headA;
ListNode preB = headB;
while (preA != preB) {
if (preA == null) preA = headB;
else preA = preA.next;
if (preB == null) preB = headA;
else preB = preB.next;
}
return preA;
}
时间复杂度:O(n)
空间复杂度:O(1)
七、环形链表入环口
假如从head到入环口为x,入环口到相遇点为y,相遇点再到入环口为z,那么第一次相遇时,快指针走了x+n (y+z) + y,慢指针走了x+y,所以就是2(x+y) = x+y + n(y+z)
x = (n-1)(y+z) + z
如果n为1,那么x=z,说明从head到入环口的长度为相遇点再到入环口的长度。
n不为1时,从head到入环口的长度x就为从相遇点在环内绕了(n-1)圈之后回到相遇点再走了z的长度。
所以再让两个指针一个从head一个从相遇点开始,再次相遇时,就是入环口了。
public ListNode detectCycle(ListNode head) {
ListNode first = head;
ListNode second = head;
while (first != null && first.next != null) {
first = first.next.next;
second = second.next;
if (first == second) {
second = head;
while (first != second) {
first = first.next;
second = second.next;
}
return first;
}
}
return null;
}
|