题目是在LeetCode上遇到的,自己在做的时候坑点一大堆,请先认真审题!!!
反转从位置 m 到 n 的链表。请使用一趟扫描完成反转。
说明:1 ≤ m ≤ n ≤ 链表长度。
示例:
输入: 1->2->3->4->5->NULL, m = 2, n = 4 输出: 1->4->3->2->5->NULL
关键词:一趟扫描 1 ≤ m ≤ n ≤ 链表长度
一趟扫描 意味着在遍历这个链表节点的过程中保留一些关键节点的指针,
比如假如存在的话,m位置前一个节点和n位置之后的节点
1 <=m<=n<=链表长度: 提醒我们在做这道题时考虑好所有的特殊情况
1=m, m=n, n=链表长度
算法思想:
1. 预处理特殊情况,把单节点链表和m=n的情况直接返回链表头,因为这两种情况下链表和原来一样
2.此时处理2个节点以上(包括两个节点)同时n>m的情况
(1) 将指针p转移到链表的第m个节点,pre保存m前一个节点
(2)接下来是反转操作,reverse_head,reverse_tail,reverse_tail_after分别存储反转链表的头部,尾部节点,尾部节点后一个节点(可能为NULL)
(3)建立头部和反转部分的连接
(4)接下来建立反转部分和尾部的连接
具体代码:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* reverseBetween(struct ListNode* head, int m, int n) {
//预处理特殊情况
if (!head || !head->next || n == m) return head;
//将p转移到链表的第m个节点,pre保存m前一个节点
struct ListNode* pre = NULL;
struct ListNode* p = head;
int temp_m = m;
while (temp_m-- > 1) {
pre = p;
p = p->next;
}
//接下来是反转操作,reverse_head,reverse_tail,reverse_tail_after分别存储反转链表的头部,尾部节点,尾部节点后一个节点(可能为NULL),为了之后的连接
struct ListNode* reverse_head = NULL;
struct ListNode* reverse_tail = p;
struct ListNode* reverse_tail_after = NULL;
struct ListNode* q = NULL;
int temp_n = n;
while (temp_n - m > 0) {
q = p->next;
reverse_tail_after = q->next;
p->next = reverse_head;
reverse_head = p;
p = q;
temp_n--;
}
p->next = reverse_head;
reverse_head = p;
//接下来建立头部和反转部分的连接
if (m == 1) {
//反转链表的head就是链表的head
head = reverse_head;
}
else {
//用pre将正序头部和反转链表连接
pre->next = reverse_head;
}
//接下来建立反转部分和尾部的连接
if (reverse_tail_after) {
reverse_tail->next = reverse_tail_after;
}
return head;
}
感觉关键就是考虑好很多特殊情况。
写的比较粗糙,欢迎各位评论并提出意见,大家分享一下自己的idea总是好的~