合并两个有序链表
思路:
这道题有很多解法,可以分为两类,一类是递归,另一类是非递归,具体实现不难,看代码也可以看得明白。
代码:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
if(l1==NULL) return l2;
if(l2==NULL) return l1;
ListNode* phead = NULL;
if(l1->val < l2->val){
phead = l1;
phead->next = mergeTwoLists(l1->next,l2);
}else{
phead = l2;
phead->next = mergeTwoLists(l1,l2->next);
}
return phead;
}
};
//非递归版本
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
ListNode* phead= new ListNode(-1,NULL);
ListNode* op = phead;
while(l1!=NULL && l2!=NULL){
if(l1->val < l2->val){
op->next = l1;
l1=l1->next;
}else{
op->next = l2;
l2=l2->next;
}
op = op->next;
}
if(l1!=NULL) op->next = l1;
if(l2!=NULL) op->next = l2;
op = phead->next;
delete(phead);
return op;
}
};
反转链表
思路:
这道题很简单,具体看代码即可;或者看看我画的一张图。
代码:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* reverseList(ListNode* head) {
if(head==NULL || head->next==NULL) return head;
ListNode *t,*p,*q;
t = NULL;
p = q = head;
while(q!=NULL){
q=q->next;
p->next = t;
t = p;
p = q;
}
return t;
}
};
//dfs
/**
* 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* dfs(ListNode* head){
if(head->next==NULL) return head;
ListNode* cur = dfs(head->next); //好好领悟一下
head->next->next = head; //实际上回溯的时候就处理倒数第一个和第二个节点反转
head->next = NULL;
return cur;
}
ListNode* reverseList(ListNode* head) {
if(head==NULL) return head;
return dfs(head);
}
};
//我子节点下的所有节点都已经反转好了,现在就剩我和我的子节点 没有完成最后的反转了,所以反转一下我和我的子节点。
链表中倒数第k个节点
题目链接!
思路:
这道题是快慢指针的问题,也可以说是双指针问题,两个变量,一快一慢,让快指针先走k步即可;然后同时走,当快指针到尾后即可。
代码:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* getKthFromEnd(ListNode* head, int k) {
if(head==NULL || k==0) return NULL;
ListNode *p,*q;
p = q = head;
for(int i=1;i<=k-1;++i){
q = q->next;
}
while(q->next!=NULL){
p=p->next;
q = q->next;
}
return p;
}
};
环路检测
思路:
这道题确实应该好好学学,先抛出解决步骤:
- 先判断是不是环?
- 求出环的长度x;
- 让快指针先走x步;
- 然后快慢指针同时走,他们相遇的节点就是环的入点。
(注:这道题也解决了一种特殊情况,如上图的第二种情况,刚好一条链表是环)
判断环的理由大家都是明白的,只有成环才有后面的解题步骤;为什么要求出环的长度呢?其实有道题就可以说明这个理由,那就是倒数第k个节点这道题,求出环的长度就是为了让快指针先走这么多步,也是为了能让快指针和慢指针相遇的更快。因为让快指针先走,可以简单理解为让快指针能把环走完一圈,而慢指针就不用去走那个环。
代码:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* check_huan(ListNode* head){
if(head==NULL) return NULL;
ListNode* slow = head;
ListNode* fast = slow->next;
while( fast!=NULL){
if(slow==fast) return slow; //这里也能处理特殊情况,比如只有一个节点的环
slow = slow->next;
fast = fast->next;
if(fast!=NULL) fast = fast->next;
}
return NULL;
}
ListNode *detectCycle(ListNode *head) {
ListNode* st = check_huan(head);
if(st==NULL) return NULL;
ListNode* t = st;
int num = 1;
while(st->next!=t){
st = st->next;
++num;
}
ListNode* fast = head;
for(int i=0;i<num;++i){
fast = fast->next;
}
while(fast!=head){
fast = fast->next;
head = head->next;
}
return fast;
}
};
K 个一组翻转链表
思路:
这道题确实有点东西,首先我们对翻转链表应该很熟悉了,那就好办的多了;我们先用一个for循环读取k个长度的子链表(注意是有可能读取失败的,具体代码),然后把这段子链表传入函数进行处理,然后函数的值返回翻转子链表后的头尾指针即可,这时进行拼接一下即可,重复以上步骤,直到遍历链表完成。
代码:
class Solution {
public:
// 翻转一个子链表,并且返回新的头与尾
pair<ListNode*, ListNode*> myReverse(ListNode* head, ListNode* tail) {
ListNode* prev = tail->next;
ListNode* p = head;
while (prev != tail) {
ListNode* nex = p->next;
p->next = prev;
prev = p;
p = nex;
}
return {tail, head};
}
ListNode* reverseKGroup(ListNode* head, int k) {
ListNode* hair = new ListNode(0);
hair->next = head;
ListNode* pre = hair;
while (head) {
ListNode* tail = pre;
// 查看剩余部分长度是否大于等于 k
for (int i = 0; i < k; ++i) {
tail = tail->next;
if (!tail) {
return hair->next;
}
}
ListNode* nex = tail->next;
pair<ListNode*, ListNode*> result = myReverse(head, tail);
head = result.first;
tail = result.second;
//tie(head, tail) = myReverse(head, tail);
pre->next = head;
tail->next = nex;
pre = tail;
head = tail->next;
}
return hair->next;
}
};
复制带随机指针的链表
这道题也要看看。