算法总结 DAY_06

链表专题

删除链表中的节点

LeetCode 237. delete-node-in-a-linked-list

题目:

image-20220325165146862

题解

和下一个节点交换

/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
void deleteNode(ListNode* node) {
node->val = node->next->val;
node->next = node->next->next;
}
};

复杂度分析

  • 时间复杂度:O(1)
  • 空间复杂度:O(1)

删除链表的倒数第 N 个结点

LeetCode 19. remove-nth-node-from-end-of-list

题目:

image-20220325161729752

题解

计算链表长度

image-20220325162841006
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
int size = 0;
ListNode* head1 = head;
while(head1 != nullptr){
head1 = head1 -> next;
size++;
}
if(size == n){
head = head->next;
return head;
}
ListNode* head2 = head;
for(int i = 1; i < size - n; i++){
head2 = head2->next;
}
head2->next = head2->next->next;
ListNode* ans = head;
return ans;
}
};

官方题解

class Solution {
public:
int getLength(ListNode* head) {
int length = 0;
while (head) {
++length;
head = head->next;
}
return length;
}

ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode* dummy = new ListNode(0, head); // 知识点1: 新链表建立
int length = getLength(head);
ListNode* cur = dummy;
for (int i = 1; i < length - n + 1; ++i) {
cur = cur->next;
}
cur->next = cur->next->next;
ListNode* ans = dummy->next;
delete dummy;
return ans;
}
};

复杂度分析

  • 时间复杂度:O(L),其中 L 是链表的长度。
  • 空间复杂度:O(1)。

image-20220325163149926
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode* dummy = new ListNode(0, head);
stack<ListNode*> stk;
ListNode* cur = dummy;
while (cur) {
stk.push(cur);
cur = cur->next;
}
for (int i = 0; i < n; ++i) {
stk.pop();
}
ListNode* prev = stk.top();
prev->next = prev->next->next;
ListNode* ans = dummy->next;
delete dummy;
return ans;
}
};

复杂度分析

  • 时间复杂度:O(L),其中 L 是链表的长度。
  • 空间复杂度:O(L),其中 L 是链表的长度。主要为栈的开销。

双指针

image-20220325163350726
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode* dummy = new ListNode(0, head);
ListNode* first = head;
ListNode* second = dummy;
for (int i = 0; i < n; ++i) {
first = first->next;
}
while (first) {
first = first->next;
second = second->next;
}
second->next = second->next->next;
ListNode* ans = dummy->next;
delete dummy;
return ans;
}
};

复杂度分析

  • 时间复杂度:O(L),其中 L是链表的长度。
  • 空间复杂度:O(1)

知识点拓展

链表

定义一个新节点,val为0,next为head。这样做是因为head节点也可能被删除,避免增加更多代码处理边界情况。

ListNode* dummy = new ListNode(0, head);

定义一个新节点,并且节点指向head

ListNode* first = head;

删除排序链表中的重复元素

LeetCode 83. remove-duplicates-from-sorted-list

题目:

image-20220325170423070

题解

一次遍历

image-20220325170659822
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* deleteDuplicates(ListNode* head) {
ListNode* h = head;
if(head == nullptr){
return head;
}
while(h->next){
if(h->val == h->next->val){
h->next = h->next->next;
}
else
h = h->next;
}
return head;
}
};

复杂度分析

  • 时间复杂度:O(n),其中 n 是链表的长度。
  • 空间复杂度:O(1)

旋转链表

LeetCode 61. rotate-list

题目:

image-20220325170956971

题解

闭合为环

image-20220325182615940
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* rotateRight(ListNode* head, int k) {
int size = 0;
if(!head || head->next == nullptr)
return head;
ListNode* c = head;
while(c != nullptr){
c = c -> next;
size++;
}
if(k%size == 0)
return head;
ListNode* c1 = head;
for(int i = 1; i < size-(k%size); i++){
c1 = c1->next;
}
ListNode* c2 = c1;
ListNode* c3 = head;
ListNode* ans = c1->next;
for(int i = 0; i < k%size; i++){
c2 = c2->next;
}
c1->next = nullptr;
c2->next = c3;
return ans;
}
};

官方题解

class Solution {
public:
ListNode* rotateRight(ListNode* head, int k) {
if (k == 0 || head == nullptr || head->next == nullptr) {
return head;
}
int n = 1;
ListNode* iter = head;
while (iter->next != nullptr) {
iter = iter->next;
n++;
}
int add = n - k % n;
if (add == n) {
return head;
}
iter->next = head;
while (add--) {
iter = iter->next;
}
ListNode* ret = iter->next;
iter->next = nullptr;
return ret;
}
};

复杂度分析

  • 时间复杂度:O(n),最坏情况下,我们需要遍历该链表两次。
  • 空间复杂度:O(1),我们只需要常数的空间存储若干变量。

两两交换链表中的节点

LeetCode 24. swap-nodes-in-pairs

题目:

image-20220325183418965

题解

迭代

思路与算法

image-20220325183755155 image-20220325183644738
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* swapPairs(ListNode* head) {
if(!head || head->next == nullptr)
return head;
ListNode* cur1 = head;
ListNode* cur2 = head->next;
ListNode* ans = head->next; //交换后从第二个节点开始
while(cur1->next->next && cur2->next->next){ //交换节点
ListNode* temp1 = cur1->next->next;
ListNode* temp2 = cur2->next->next;
cur1->next = temp2;
cur2->next = cur1;
cur1 = temp1;
cur2 = cur2->next->next;
}
if(cur1->next->next) //处理最后两个节点
cur1->next = cur1->next->next; //节点为三个
else
cur1->next = nullptr; //节点大于三
cur2->next = cur1;
return ans;
}
};

官方题解

class Solution {
public:
ListNode* swapPairs(ListNode* head) {
ListNode* dummyHead = new ListNode(0); //创建值为0的
dummyHead->next = head;
ListNode* temp = dummyHead;
while (temp->next != nullptr && temp->next->next != nullptr) {
ListNode* node1 = temp->next;
ListNode* node2 = temp->next->next;
temp->next = node2;
node1->next = node2->next;
node2->next = node1;
temp = node1;
}
return dummyHead->next;
}
};

复杂度分析

  • 时间复杂度:O(n),其中 n 是链表的节点数量。需要对每个节点进行更新指针的操作。
  • 空间复杂度:O(1)

递归

思路与算法

image-20220325184332959 image-20220325185110423
class Solution {
public:
ListNode* swapPairs(ListNode* head) {
if (head == nullptr || head->next == nullptr) {
return head;
}
ListNode* newHead = head->next;
head->next = swapPairs(newHead->next);
newHead->next = head;
return newHead;
}
};

复杂度分析

  • 时间复杂度:O(n),其中 n 是链表的节点数量。需要对每个节点进行更新指针的操作。
  • 空间复杂度:O(n),其中 n 是链表的节点数量。空间复杂度主要取决于递归调用的栈空间。