以下是链表结构体:
/**
* 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) {}
* };
*/
链表排序 与 合并k个升序链表
- 首先要搞定怎么合并两个升序链表,即下面的 mergetwolist函数,这个函数在后面的两个题解中都用的到
// 将两个有序链表合成一个
ListNode* mergeTwoLists(ListNode* h1, ListNode* h2) {
if(!h1) return h2;
if(!h2) return h1;
ListNode *prehead = new ListNode(-1);
ListNode *p = prehead;
while(h1 && h2) {
if (h1->val < h2->val) {
p->next = h1;
h1 = h1->next;
} else {
p->next = h2;
h2 = h2->next;
}
p = p->next;
}
if(h1) p->next = h1;
else p->next = h2;
return prehead->next;
}
- Leetcode 题 : 给你链表的头结点 head ,请将其按 升序 排列并返回 排序后的链表 。
// 归并排序,快慢指针找中点,
ListNode* sortList(ListNode* head) {
if (!head || !head->next) return head;
ListNode *slow = head, *fast = head;
ListNode *prev;
while (fast && fast->next) {
prev = slow; // 记得记住慢指针的上一步, 用于在中点切分链表
slow = slow->next;
fast = fast->next->next;
}
prev->next = NULL; /// 从中点slow前 将链表切断
return mergeTwoLists(sortList(head), sortList(slow)); 归并的重点!!!
}
//merge :将 lists 中下标为l 到 下标为 r 之间[l,r]的链表合并
ListNode* merge(vector<ListNode*>& lists, int l, int r) {
if(l==r) return lists[l];
int mid = l + (r-l)/2;
return mergeTwoLists(merge(lists, l, mid), merge(lists, mid+1, r));
}
ListNode* mergeKLists(vector<ListNode*>& lists) {
if(lists.empty()) return NULL;
return merge(lists, 0, lists.size()-1);
}
链表反转 — K 个一组翻转链表
通过此题可会做 链表翻转,链表部分翻转
Leetcode 题: 给你一个链表,每 k 个节点一组进行翻转,请你返回翻转后的链表。k 是一个正整数,它的值小于或等于链表的长度。如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。
class Solution {
public:
// 每次反转一段,然后将反转后这一段的末尾连到下一段反转后链表的头上
ListNode* reverseKGroup(ListNode* head, int k) {
if(!head) return NULL;
ListNode *a = head, *b = head;
int i = k;
while (i > 0) {
if(b == NULL) return head; // 不满 k 个就不反转
b = b->next;
i--;
}
// 反转 [a, b)之间的链表
ListNode *newnode = revese(a, b);
// 将b节点以后的链表也分段反转,并连在前一个反转链表的末尾。
a->next = reverseKGroup(b, k); // 注意是将 a 连到 后面的节点
return newnode; // 注意不是返回 head, 而是 newnode
}
// 反转 [a, b) 之间的链表节点。2->3->4, 输出 4->3->2。
ListNode *revese(ListNode *a, ListNode *b) {
ListNode *prev, *cur, *nxt;
prev = b, cur = a, nxt = a;
while(cur != b) {
nxt = cur->next;
cur->next = prev;
prev = cur;
cur = nxt;
}
return prev;
}
};
删除排序链表中的重复元素(去重 和 重复的元素全删)
- Leetcode 题目: 给定一个排序链表,删除所有重复的元素,使得每个元素只出现一次,例如输入: 1->1->2->3->3,输出: 1->2->3 。
ListNode* deleteDuplicates(ListNode* head) {
if(!head || !head->next) return head;
ListNode *p = head;
while(p && p->next) {
if(p->val == p->next->val) {
p->next = p->next->next;
} else {
p = p->next;
}
}
return head;
}
- 牛客网题目 : 请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。 例如,链表1->2->3->3->4->4->5 处理后为 1->2->5 。
ListNode* deleteDuplication(ListNode* pHead) {
if(!pHead || !pHead->next) return pHead;
ListNode *preh = new ListNode(-1);
preh->next = pHead;
ListNode *pre = preh, *cur = pHead;
while(cur) {
if (cur->next && cur->val == cur->next->val) {
while (cur->next && cur->val == cur->next->val) {
cur = cur->next;
}
cur = cur->next;
pre->next = cur;
} else {
pre = cur;
cur = cur->next;
}
}
return preh->next;
}
奇偶链表
Leetcode题目 : 给定一个单链表,把所有的奇数节点和偶数节点分别排在一起。请注意,这里的奇数节点和偶数节点指的是节点编号的奇偶性,而不是节点的值的奇偶性。
// 把奇数编号的链表节点挂到Head后(odd遍历);
// 把偶数链表节点挂到evenHead后(even遍历)
// 最后把evenHead 挂到 odd后面。
ListNode* oddEvenList(ListNode* head) {
if (!head || !head->next) return head;
ListNode *odd = head;
ListNode *evenHead = head->next;
ListNode *even = evenHead;
while (even && even->next) {
odd->next = even->next;
odd = odd->next;
even->next = odd->next;
even = even->next;
}
odd->next = evenHead;
return head;
}