完全反转链表
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
/*
迭代法
//O(n),O(1)
*/
class Solution
{
public:
ListNode* reverseList(ListNode* head)
{
if(head == nullptr) return nullptr;
ListNode *pre = nullptr, *cur = head,*next; //三个指针分别保存之前,当前,下一个结点
while(cur)
{
next = cur->next; //保存原链表该结点的下一个结点,以免变换指向之后无法遍历到下一个结点
cur->next = pre; //变换指向
//更新指针
pre = cur; //更新指针
cur = next; //更新指针
}
return pre; //最后pre指向最后一个结点,cur指向null
}
};
/*
递归法(不太好理解)
*/
class Solution
{
public:
ListNode* reverseList(ListNode* head)
{
if(head == nullptr || head->next == nullptr) return head;
//递归之后为从后往前开始转向
ListNode* p = reverseList(head->next); //直接递归到最后一个列表元素开始从后往前翻转
head->next->next = head; //让当前结点的下一个结点的 next 指针指向当前节点
head->next = nullptr; //让当前结点的 nextnext 指针指向 NULLNULL ,从而实现从链表尾部开始的局部反转
return p;
}
};
/*
妖魔化指针
*/
class Solution {
public:
ListNode* reverseList(ListNode* head) {
if (head == NULL) { return NULL; }
ListNode* cur = head;
while (head->next != NULL) {
ListNode* t = head->next->next; //迭代的下一个指针
head->next->next = cur; //当前节点的下一节点指向当前节点,从而改变了两个节点的前后顺序
//更新节点
cur = head->next; //当前节点向后移动,是每次迭代的头结点
head->next = t; //是下一次迭代的头结点,翻转指向CUR
}
return cur;
}
};
反转列表2
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
/*
问题:翻转链表2(位置m~n翻转)
方法:对m~n位置处的链表进行翻转,然后连接m-1位置与n位置,m位置与n+1位置
例:
Input: 1 -> 2 -> 3 -> 4 -> 5 -> NULL, m = 2, n = 4
翻转得,1 <-> 2(m) <- 3 <- 4(n) 5 -> NULL
连接得,1 -> 4 -> 3 -> 2 -> 5 -> NULL
*/
class Solution
{
public:
ListNode* reverseBetween(ListNode* head, int m, int n)
{
//异常情况处理(严格来说,还需判断m,n值是否超出链表长度,题目已经有此条件)
if(!head || !head->next || m<0 || n<0 || m>=n) return head;
//prehead的应用:头结点前的结点,方便索引,方便分析(链表用1开头+prehead分析较好,序号可以与步数对应起来)
//且指向了链表的头结点,当m=1时,原头结点被换到后面,若返回head会出错,
//而用prehead会指向新头结点,故返回prehead.next不会出错
ListNode prehead(0);
prehead.next = head;
ListNode* cur = &prehead;
for(int i = 1; i <= m-1; i++)
cur = cur->next; //最后cur处在m-1位置
ListNode* pre = cur;
ListNode* next;
cur = cur->next; //让cur处在m位置
ListNode* prefirst = pre, *first = cur; //保存m-1位置和m位置处的结点
for(int i = m; i<=n; i++) //翻转位置m~n处的链表
{
next = cur->next;
cur->next = pre;
pre = cur; //更新指针
cur = next; //更新指针
}//退出时,pre在n处,cur在n+1处
prefirst->next = pre; //连接m-1与n位置
first->next = cur; //连接m与n+1位置
return prehead.next;
}
};