算法基础_LeetCode反转链表I 和 II的迭代解法
反转链表 I
反转一个单链表。
示例:
输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL
进阶:
你可以迭代或递归地反转链表。你能否用两种方法解决这道题?
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/reverse-linked-list
下面来看看迭代解法:
/**
* 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) return NULL;
ListNode* pPre = head, *pCur = pPre->next;
while(pCur)
{
ListNode* pNext = pCur->next;
pCur->next = pPre;
pPre = pCur;//pPre始终指向新链表的头
//移动pCur、pNext,指向原链表的第一个和第二个位置
pCur = pNext;
}
head->next = NULL;
return pPre;
}
};
主要思想就是利用迭代的方式,不断地让pCur指向的节点的next指针指向pPre,来达到反转链表的目的。下图清楚地表示了这个过程。
其中需要注意的是对于边界情况的处理,也就是head为NULL的情况,以及当pCur为NULL的时候就不能建pNext了,否则会出问题。所以这里的pNext是在pCur为真的情况下才建立。
复杂度:时间复杂度O(N),空间复杂度O(1)。
提交结果为:
反转链表 II
反转从位置 m 到 n 的链表。请使用一趟扫描完成反转。
说明:
1 ≤ m ≤ n ≤ 链表长度。
示例:
输入: 1->2->3->4->5->NULL, m = 2, n = 4
输出: 1->4->3->2->5->NULL
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/reverse-linked-list-ii
迭代解法为:
/**
* 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) {
if(head == NULL || m == n) return head;
ListNode* pm = head, *pn = head;
ListNode* dummy = new ListNode(-1);
dummy->next = head;
ListNode* pm0 = dummy;
while(m-->1) pm = pm->next,pm0 = pm0->next;
while(n-->1) pn = pn->next;
ListNode* pPre = pm,*pCur = pPre->next,*pn2 = pn->next;
while(pCur != pn2)
{
if(pCur)
{
ListNode* pNext = pCur->next;
pCur->next = pPre;
pPre = pCur;
pCur = pNext;
}
}
pm0->next = pn;
pm->next = pn2;
return dummy->next;
}
};
这道题的思想就是利用前面提到的迭代的方法去反转m到n的链表,但是这里要注意的是要提前保存m到n段前后的链表节点,(千万不要想着节省一点空间用pn->next代替,实际上反转完了之后pn->next已经不指向pn2的那个位置了)后边反转完了之后要接上去,还有就是注意对边界条件的处理,如当m == n
的时候就不用反转了。
另外返回值也要注意,不要返回head,而应该是dummy->next,因为m == 1的时候,反转完head已经不再指向第一个节点了,这点需要注意。
复杂度:时间复杂度O(N),空间复杂度O(1)。
下面是图解:
提交结果为: