https://leetcode-cn.com/problems/reverse-linked-list-ii/
反转链表的中间一段。
法一:先拆后转,然后链接起来
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* reverseBetween(ListNode* head, int left, int right) {
// 拆出需要反转的部分
ListNode* phead = new ListNode(0, head); // 设一个最头的结点
ListNode* lh = head; // 设一个最左的结点,需要遍历找到left的位置
ListNode* lpre = phead; // 最左结点再往左边的结点
ListNode* rnext = head; //
ListNode* rl = phead; // 同理
// 寻找
for(int i = 0; i < left - 1; i++) {
lh = lh->next;
lpre = lpre->next;
}
for(int i = 0; i < right; i++) {
rnext = rnext->next;
rl = rl->next;
}
// 拆出来
rl->next = nullptr;
lpre->next = nullptr;
// 部分反转
ListNode* p = lh, *last = nullptr, *nxt = nullptr;
while(p) {
nxt = p->next;
p->next = last;
last = p;
p = nxt;
}
// 重新拼接
lpre->next = last;
lh->next = rnext;
return phead->next;
}
};
还有个更简单的方法:
删后面的结点再插入到前面的left位置上。
遍历一遍就行,比法一少遍历一次 ,效率更高点。
代码:
class Solution {
private:
public:
void _delet(ListNode* p) {
p->next = p->next->next;
}
void _insert(ListNode* beg, ListNode* nod) {
ListNode* nxt = beg->next;
beg->next = nod;
nod->next = nxt;
}
ListNode* reverseBetween(ListNode* head, int left, int right) {
ListNode* phead = new ListNode(0, head);
ListNode* beg = phead;
for(int i = 0; i < left - 1; i++) beg = beg->next;
ListNode* cur = beg->next, *nxt = nullptr, *tmp = nullptr;
for(int i = 0; i < right - left; i++) {
tmp = cur->next; // 记录cur下一个的地址
_delet(cur); // 删除cur下一个的元素
_insert(beg, tmp); // 在beg后面插入cur后删除的元素
//print(head); cout << "----" << endl;
}
/ [1,4,3,2,5]
return phead->next;
}
};