反转链表
Leetcode 206:https://leetcode-cn.com/problems/reverse-linked-list/
Nowcoder NC76:https://www.nowcoder.com/practice/75e878df47f24fdc9dc3e400ec6058ca?tpId=188&&tqId=38547
1.问题描述
给定单链表的头节点head,反转链表。
2.输入输出
- Input:head = [1, 2, 3, 4, 5]
- Output:[5, 4, 3, 2, 1]
3.算法分析
- 迭代法:1)实现存储前一个节点;2)通过当前指针遍历链表;3)存储后一个节点;4)将当前节点的next指针改为指向前一个节点。5)最后返回新的头引用——前一个节点。
- 时间复杂度:O(n)
- 空间复杂度:O(1)
- 递归法:
- 递归终止条件:链表只剩最后一个节点或者已经为空(最后一个节点就是反转后的头节点)
- 处理:让当前节点的下一格节点的next指针指向当前节点,且当前节点的next指向NULL,实现链表尾部开始的局部反转
- 时间复杂度:O(n)
- 空间复杂度:O(n)
4.编程实现
#include <iostream>
using namespace std;
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* reverseList1(ListNode* head) {
// 迭代法 1->2->3->Ø变成Ø->3->2-1
ListNode* prev = nullptr;
ListNode* curr = head;
while (curr) {
ListNode* nxt = curr->next;
curr->next = prev;
prev = curr;
curr = nxt;
}
return prev;
}
ListNode* reverseList2(ListNode* head){
// 递归法 1->2->3->Ø变成Ø->3->2-1
if (!head || !head->next) return head;
ListNode *newHead = reverseList2(head->next);
head->next->next = head;
head->next = nullptr;
return newHead;
}
};
int main() {
Solution sol;
ListNode* head = new ListNode(), *now = head;
int val;
getchar();
while (cin >> val) {
now->next = new ListNode(val);
now = now->next;
if (cin.get() == ']') break;
}
now = sol.reverseList1(head->next);
cout << "[";
while (now) {
cout << now->val;
if (now->next) {
cout << ",";
} else {
cout << "]";
}
now = now->next;
}
return 0;
}
k个一组翻转链表
Leetcode:https://leetcode-cn.com/problems/reverse-nodes-in-k-group/
1.问题描述
给定一个链表,每k个节点一组进行翻转,返回翻转后的链表。(k是一个正整数,它的值小于或等于链表的长度,如果节点总数不是k的整数倍,将最后剩余的节点保持原有顺序)
2.输入输出
- Input:head=[1, 2, 3, 4, 5],k=2
- Output:[2,1,4,3,5]
3.算法分析
先计算以下长度,再根据需要翻转的段数进行遍历。
4.编程实现
// #include <bits/stdc++.h>
#include <iostream>
using namespace std;
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* reverseKGroup(ListNode *head, int k) {
ListNode *dummy = new ListNode(0), *prev = dummy, *curr = head, *nextNode;
dummy->next = head;
int length = 0;
while (head) {
length++;
head = head->next;
}
for (int i = 0; i < length / k; i++) {
for (int j = 0; j < k-1; j++) {
nextNode = curr->next;
curr->next = nextNode->next;
nextNode->next = prev->next;
prev->next = nextNode;
}
prev = curr;
curr = prev->next;
}
return dummy->next;
}
};
int main(){
Solution sol;
ListNode *head = new ListNode(0), *fake = head;
int val, k;
char ch;
getchar();
while (cin >> val) {
fake->next = new ListNode(val);
fake = fake->next;
if (cin.get() == ']') break;
}
cin >> k;
ListNode *newNode = sol.reverseKGroup(head->next, k);
while (newNode) {
cout << newNode->val;
if (newNode->next) {
cout << ",";
} else {
cout << "";
}
newNode = newNode->next;
}
return 0;
}
合并两个有序链表
Leetcode:https://leetcode-cn.com/problems/merge-two-sorted-lists/
1.问题描述
将两个升序链表合并成一个新的升序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
2.输入输出
- Input:l1=[1, 2, 4],l2=[1, 3, 4]
- Output:[1, 1, 2, 3, 4, 4]
3.算法分析
迭代法:当l1和l2都不是空链表时,判断l1和l2哪一个链表的头节点的值更小,将较小值得节点添加到结果里,当一个节点被添加到结果里之后,将对应链表的节点后移一位。
- 时间复杂度:O(n+m)
- 空间复杂度:O(1)
4.编程实现
#include <iostream>
using namespace std;
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:
// 1->2->3->Ø变成Ø->3->2-1
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
ListNode* preHead = new ListNode(-1);
ListNode* prev = preHead;
while (l1 && l2 ) {
if (l1->val < l2->val) {
prev->next = l1;
l1 = l1->next;
} else {
prev->next = l2;
l2 = l2->next;
}
prev = prev->next;
}
// 合并后l1和l2最多还有一个还未被合并完,直接将链表末尾指向未合并完的链表即可。
prev->next = l1 == nullptr? l2 : l1;
return preHead->next;
}
};
int main() {
Solution sol;
ListNode* l1 = new ListNode(1);
l1->next = new ListNode(2);
l1->next->next = new ListNode(4);
ListNode* l2 = new ListNode(1);
l2->next = new ListNode(3);
l2->next->next = new ListNode(4);
ListNode* newHead = sol.mergeTwoLists(l1, l2);
while (newHead) {
cout << newHead->val << " ";
newHead = newHead->next;
}
return 0;
}
相交节点
Leetcode:https://leetcode-cn.com/problems/intersection-of-two-linked-lists/
1.问题描述
给定两个单链表,判断它们是否相交于一点,并求这个相交节点。
2.输入输出
- Input:A=[4, 1, 8, 4, 5],B=[5, 0, 1, 8, 4, 5]
- Output:Intersected at '8'
3.算法分析
使用两个指针,分别指向两个链表的头节点,并以相同的速度前进,若到达链表结尾,则移动到另一条链表的头结点继续前进,两个指针会在a+b+c次前进后同时到达相交节点。
- 时间复杂度:O(m+n)
- 空间复杂度:O(1)
4.编程实现
#include <iostream>
using namespace std;
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 *getIntersectionNode(ListNode *headA, ListNode *headB) {
ListNode *you = headA, *she = headB;
while (you != she) {
you = you? you->next: headB;
she = she? she->next: headA;
}
return you;
}
};
int main() {
Solution sol;
ListNode* l1 = new ListNode(4);
l1->next = new ListNode(1);
l1->next->next = new ListNode(8);
l1->next->next->next = new ListNode(4);
l1->next->next->next->next = new ListNode(5);
ListNode* l2 = new ListNode(5);
l2->next = new ListNode(0);
l2->next->next = l1->next->next;
cout << sol.getIntersectionNode(l1, l2)->val << endl;
return 0;
}