将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
/**
* 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* mergeTwoLists(ListNode* list1, ListNode* list2) {
if(list1 == nullptr){
return list2;
}else if(list2 == nullptr){
return list1;
}else if(list1->val > list2->val){
list2->next = mergeTwoLists(list1,list2->next);
return list2;
}else{
list1->next = mergeTwoLists(list1->next,list2);
return list1;
}
}
};
使用递归的方法,确定下一个返回的节点。
链表本来就具有递归的属性。
题目2 力扣
给你一个链表数组,每个链表都已经按升序排列。
请你将所有链表合并到一个升序链表中,返回合并后的链表。
/**
* 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 {
ListNode* mergeTwoLists(ListNode* list1, ListNode* list2) {
if(list1 == nullptr){
return list2;
}else if(list2 == nullptr){
return list1;
}else if(list1->val > list2->val){
list2->next = mergeTwoLists(list1,list2->next);
return list2;
}else{
list1->next = mergeTwoLists(list1->next,list2);
return list1;
}
}
public:
ListNode* mergeKLists(vector<ListNode*>& lists) {
ListNode* ans = nullptr;
for(int i = 0;i<lists.size();++i){
ans = mergeTwoLists(ans,lists[i]);
}
return ans;
}
};
新建一个结果链表,然后逐一与list中的链表顺序合并。
第二种做法是两两匹配合并,使用递归的方法实现了两两分类再合并。
/**
* 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 {
ListNode* mergeTwoLists(ListNode* list1, ListNode* list2) {
if(list1 == nullptr){
return list2;
}else if(list2 == nullptr){
return list1;
}else if(list1->val > list2->val){
list2->next = mergeTwoLists(list1,list2->next);
return list2;
}else{
list1->next = mergeTwoLists(list1->next,list2);
return list1;
}
}
ListNode* merge(vector<ListNode*>& lists,int L,int R){
if(L==R){
return lists[L];
}
if(L>R){
return nullptr;
}
int mid =((R-L)>>1)+L;
return mergeTwoLists(merge(lists,L,mid),merge(lists,mid+1,R));
}
public:
ListNode* mergeKLists(vector<ListNode*>& lists) {
int n = lists.size();
return merge (lists,0,n-1);
}
};
题目3 力扣
给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。
/**
* 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 == nullptr || head->next == nullptr ){
return head;
}
ListNode* newHead = head->next;
ListNode* rest = newHead->next;
newHead->next = head;
head->next = swapPairs(rest);
return newHead;
}
};
标记head,newhead,rest三个位置,将head 和 newhead反转之后继续向下进行。
题目3 力扣
给你一个链表,删除链表的倒数第
n
个结点,并且返回链表的头结点。
/**
* 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) {
ListNode* dummynode = new ListNode(0);
dummynode->next = head;
ListNode* p= dummynode;
ListNode* q= dummynode;
for(int i = 0;i<n+1;++i){
p = p->next;
}
while(p){
p=p->next;
q=q->next;
}
ListNode* delNode = q->next;
q->next = delNode->next;
ListNode* res = dummynode->next;
delete dummynode;
return res;
}
};
先设立一个虚拟的节点dummynode,再设定两个指针p与q,让p预先跑n次,再让q和p一起跑,当p指向nullptr时,q指向要删除节点的前一位,最后标记要删除结点后一个位置,用指针把前后位置链接。最后标记dummynode的下一位,把dummynode删除,返回标记好的dummynode的下一位即可(防止头节点是空节点)
题目4 力扣
给你一个链表的头节点
head
,旋转链表,将链表每个节点向右移动k
个位置。
/**
* 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) {
if(head == nullptr||head->next == nullptr || k == 0){
return head;
}
ListNode* cur = head;
int size = 0;
while(cur != nullptr){
size++;
cur = cur->next;
}
k%=size;
if(k == 0){
return head;
}
ListNode* p=head;
ListNode* q=head;
while(k>0){
q=q->next;
k--;
}
while(q->next != nullptr){
p = p->next;
q = q->next;
}
ListNode* newHead = p->next;
p->next = nullptr;
q->next = head;
return newHead;
}
};
首先获得数组长度,对k处理,如果刚好是长度的倍数,直接返回原数组。之后使用双指针,确定链表的新头部,然后处理成正常的链表返回新头部即可。
题目 5 力扣
给定一个已排序的链表的头
head
, 删除所有重复的元素,使每个元素只出现一次 。返回 已排序的链表 。
/**
* 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* cur = head;
if(!head){
return head;
}
while(cur->next){
if(cur->val == cur->next->val){
cur->next = cur->next->next;
}else{
cur = cur->next;
}
}
return head;
}
};
因为是有序链表所以简单判断即可。
题目6 力扣
给定一个已排序的链表的头
head
, 删除原始链表中所有重复数字的节点,只留下不同的数字 。返回 已排序的链表 。
/**
* 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) {
if(!head){
return head;
}
ListNode* dummyNode =new ListNode(0,head);
ListNode* cur = dummyNode;
while(cur->next&&cur->next->next){
if(cur->next->val == cur->next->next->val){
int x = cur->next->val;
while(cur->next&&cur->next->val == x){
cur->next = cur->next->next;
}
}else{
cur = cur->next;
}
}
return dummyNode->next;
}
};
先创建一个虚拟节点dummynode,然后遍历,如果遇到前后相同的情况,就记录这个值,删除之后所有相同的值 。
这里虚拟节点new之后没有删除
也可以采用下面的方法
/**
* 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) {
if(!head){
return head;
}
ListNode dummyNode =ListNode(0,head);
ListNode* cur = &dummyNode;
while(cur->next&&cur->next->next){
if(cur->next->val == cur->next->next->val){
int x = cur->next->val;
while(cur->next&&cur->next->val == x){
cur->next = cur->next->next;
}
}else{
cur = cur->next;
}
}
return dummyNode.next;
}
};
直接用ListNode类型,使用时&dummy,最后返回dummy.next即可。
题目7 力扣
给你单链表的头指针 head 和两个整数 left 和 right ,其中 left <= right 。请你反转从位置 left 到位置 right 的链表节点,返回 反转后的链表 。
class Solution {
private:
void reverse(ListNode *head) {
ListNode* pre = nullptr;
ListNode* cur = head;
while(cur!=nullptr){
ListNode* next= cur->next;
cur->next = pre;
pre = cur;
cur = next;
}
}
public:
ListNode *reverseBetween(ListNode *head, int left, int right) {
ListNode* dummyNode = new ListNode(-1,head);
ListNode* pre = dummyNode;
for(int i=0;i<left-1;++i){
pre =pre->next;
}
ListNode* rightNode = pre;
for(int i=0;i<right-left+1;++i){
rightNode = rightNode->next;
}
ListNode* leftNode = pre->next;
ListNode* cur = rightNode->next;
pre->next = nullptr;
rightNode->next = nullptr;
reverse(leftNode);
pre->next = rightNode;
leftNode->next = cur;
return dummyNode->next;
}
};
画图厘清节点关系即可。交换可使用上面的技巧。
题目8 力扣
给你一个链表的头节点 head ,判断链表中是否有环。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。注意:pos 不作为参数进行传递 。仅仅是为了标识链表的实际情况。
如果链表中存在环 ,则返回 true 。 否则,返回 false
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
bool hasCycle(ListNode *head) {
unordered_set<ListNode*>seen;
while(head!=nullptr){
if(seen.count(head)){
return true;
}
seen.insert(head);
head=head->next;
}
return false;
}
};
使用哈希表检测是否有重复值。
题目9 力扣
给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。
不允许修改 链表。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
unordered_set<ListNode*>seen;
while(head!=nullptr){
if(seen.count(head)){
return head;
}
seen.insert(head);
head = head->next;
}
return nullptr;
}
};
与上一题一致,这一题只需要返回那个位置即可。
题目10力扣
给定一个头结点为
head
的非空单链表,返回链表的中间结点。如果有两个中间结点,则返回第二个中间结点。
/**
* 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* middleNode(ListNode* head) {
ListNode* cur = head;
int n=0;
while(cur!=nullptr){
++n;
cur = cur->next;
}
cur = head;
for(int i = 0;i<n/2;++i){
cur = cur->next;
}
return cur;
}
};
进行两次遍历,第一次查到链表的大小,第二次查到中间节点。