由于刚接触链表,用起来感觉怪怪的,所以在LeetCode上集中找几个题目集训一下。
一、LeetCode 206-反转链表
题目:
反转一个单链表。
示例:
输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL
进阶:
你可以迭代或递归地反转链表。你能否用两种方法解决这道题?
1.迭代方法
思路:将旧链表从第一个开始,依次取出,并将其以头结点插入的方式插到新链表中。
要点:
- 新链表 newHead 要初始化为 NULL
- 由于每次循环都需要将 旧链表的第一个结点 插入到新链表中,所以要使用 t 将旧链表头节点的next存下来。以便进行 oldHead->next = newHead操作。
/**
* 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) {
ListNode* oldHead = head,*newHead = NULL,*p;
while(oldHead){
p = oldHead->next;
oldHead->next = newHead;
newHead = oldHead;
oldHead = p;
}
return newHead;
}
};
2.递归方法
思路:递归用起来还是不太熟练,自己瞎总结的三个要素:本层递归完成的功能、返回的内容及代入内容、终止条件。
在本题中
- 本层递归需要完成的功能:
有链表n1 → … → nk-1 → nk → nk+1 → … → nm → Ø,假设其余部分已经反转( nk+1 到 nm 已经被反转),我们现在在nk,本层递归我们想让nk+1的下一个结点指向nk,所以就有 nk->next->next = nk;
- 代入内容及返回内容
一层一层递归,假如要当前是head,则希望当前层能够获得从head->next到NULL的反转,所以代入内容为head->next
同理,每层需要返回将当前结点反转后的新链表。
- 终止递归的条件:
递归是一层套一层的思想,所以终止条件:找到最后一个元素,head->next == NULL;
此外还要考虑特殊情况,如旧链表是空链表,即 head==NULL, 这两种情况,都会导致递归的结束,都返回head就好,所以可以合并一起来写。
要点:
- 要写明终止条件和例外情况的返回值
- 每层递归结束后,都要在尾结点后接入NULL
- 每次递归只反转一个,多次套用以后,实现多个反转,即由原来的 node2->node3->...->noden->NULL 变为 NULL<-node2<-node3<-...<-noden;但是需要注意的是,并没有改变 node1->node2
node0--->node1--->node2<---node3<---...<---noden
↓
NULL
所以有 node1->next = node2,假如当前获得head为node1,那么当前层需要完成
node->next->next = node;
node->next = NULL;
完整代码如下:
/**
* 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* newHead = reverseList(head->next);
head->next->next = head;
head->next = NULL;
return newHead;
}
};
二、LeetCode 25-k个一组翻转链表
题目:
给出一个链表,每 k 个节点一组进行翻转,并返回翻转后的链表。
k 是一个正整数,它的值小于或等于链表的长度。如果节点总数不是 k 的整数倍,那么将最后剩余节点保持原有顺序。
示例 :
给定这个链表:1->2->3->4->5
当 k = 2 时,应当返回: 2->1->4->3->5
当 k = 3 时,应当返回: 3->2->1->4->5
说明 :
- 你的算法只能使用常数的额外空间。
- 你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。
题解:
1.迭代方法
这个题目就有点难了,先简化问题:
k为变量,实现k个一组翻转 ---> 如果k为常数,实现k个一组翻转 ---> 如果k为结点总量,翻转链表
例外情况:k为1,不翻转。
可以看到,经过三次简化,可以用到上一个题目的思路。在此基础上,那么如果k为常数,则需要:
- 在传入参数里加一个尾结点,实现子链表反转。
- 加入计数,如果子链表结点数量达到k,就送去反转,如果不够,就保持原样。
- 将反转后的链表的尾结点,指向原尾结点的下一个结点(实现部分反转,且链表不中断)
在k为常数的基础上,如果k为变量,那么考虑k=1不反转,k为1以外的正整数,那就进行反转。
注意:在使用t进行遍历链表的同时,进行反转子链表会将t->next修改,所以加入tt暂存。
代码如下:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* reverseKGroup(ListNode* head, int k) {
ListNode* dummy = new ListNode(0);
dummy->next = head;//虚拟表头
ListNode* cur = dummy;//每一段需要反转的链表的表头结点
ListNode* t = head;//t从开始逐一指向每一个结点,实现遍历
int count = 0;
if(k==1 && head==NULL) return head;//k=1或链表为空,不反转
while(t){//当没有遍历完,继续遍历
count++;
if(count == k){//每K个进行反转,此时t的指向为需要反转的子链表的尾结点
count = 0;
//头结点插入方式:依次把旧链表中的结点以头结点插入的方式插入到新链表中。
ListNode* oldHead = cur->next;
ListNode* newHead = NULL;
ListNode* wspy = cur->next;//子链表反转之前的头结点,也是反转完成后的尾结点
ListNode* tt = t->next;//由于反转链表中,会将t->next改变,用tt先记录下来
ListNode* p;
while(oldHead!=tt){
p = oldHead->next;
oldHead->next = newHead;
newHead = oldHead;
oldHead = p;
}
cur->next = newHead;//将反转之后子链表的接入原链表
wspy->next = tt; //反转之后的尾结点接上后续链表
cur = wspy;//更新待反转的链表表头结点
t = tt;//将t指向原来的t->next,继续遍历
}
else t = t->next;
}
return dummy->next;
}
};
2.递归方法
先挖个坑,改日再写递归方法,在这题上花费了不少时间。。
三、LeetCode 92-反转链表II
题目大致相同,但是要求只遍历一次
题目:
反转从位置 m 到 n 的链表。请使用一趟扫描完成反转。
说明:
1 ≤ m ≤ n ≤ 链表长度。
示例:
输入: 1->2->3->4->5->NULL, m = 2, n = 4 输出: 1->4->3->2->5->NULL
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* reverseBetween(ListNode* head, int m, int n) {
ListNode* dummy = new ListNode(0);
ListNode* p = dummy;
ListNode* tmp,*sta,*tail;
ListNode* newhead = NULL;
dummy->next = head;
int count = 0;
if(m==n) return head;
while(count < m-1){
p = p->next;
count++;
}
tmp = p;
sta = p->next;
while(count < n){
p = sta->next;
sta->next = newhead;
newhead = sta;
sta = p;
count++;
}
tail = tmp->next;
tmp->next = newhead;
tail->next = sta;
return dummy->next;
}
};