Reverse Linked List II
1.题目描述:
给定一个链表以及起止点m和n,反转从m开始到n的链表,其他保持不变。
2.思路:
首先描述反转链表的思路。反转链表,可以利用栈来实现。从链表头开始遍历节点,将节点压入栈中直到链表尾,接着定义一个新的链表头,将节点从栈中顶出,重新链接到新链表上。这里需要特别注意的地方是,栈中的节点是由next的,指向的是正向的下一个节点;现在我们要反向,所以每次pop出来的节点都要先把它的next置为NULL,然后再接到新链表上。
有了反转链表的思路后,我们考虑从m到n反转。在链表中找到起点是第m个节点,记m前面的节点为指针pPre,使用计数器将第m个节点开始到第n个节点压入栈中,剩下后面尾部节点用指针pTail来表示。也就是说,新的链表是有pPre - reverse - pTail组成。
考虑m是第一个节点的情况,此时pPre是NULL;新的链表由reverse - pTail组成;
考虑n是最后一个节点的情况,此时pTail是NULL,那么新的链表由pPre - reverse组成,实际上与pPre - reverse - pTail结构是一样的。所以算法的步骤是:
1).首先确定pPre的位置;
2).循环链表,将第m到第n个节点压入栈中;
3).定义一个新链表头res,将栈中的节点顶出并接到新链表上;
4).将pTail接到res之后;
5).如果pPre是NULL,则返回res;
6).如果pPre不是NULL,则将pPre的next是res,然后返回head。
3.代码展示
ListNode* reverseList(ListNode* head, int start, int end) {
stack<ListNode*> nodes;
ListNode* pTail= head;
ListNode* pPre = head;
int i = 1;
if (start == 0)
pPre = NULL;
else {
while (i < start) {
pPre = pPre->next;
i++;
}
}
i = 0;
while (pTail!= NULL) {
if (i < start)
{
pTail= pTail->next;
}
else if (i >= end)
{
break;
}
else {
nodes.push(pTail);
pTail= pTail->next;
}
i++;
}
ListNode* res = new ListNode(0);
ListNode* temp = res;
ListNode* pp;
while (!nodes.empty()) {
pp = nodes.top();
pp->next = NULL;
nodes.pop();
temp->next = pp;
temp = temp->next;
}
temp->next = pTail;
if (pPre == NULL)
return res->next;
pPre->next = res->next;
res->next = NULL;
return head;
}
ListNode* reverseBetween(ListNode* head, int m, int n) {
if (head == NULL || head->next == NULL || m == n)
return head;
ListNode* begin = head;
ListNode* cur = head;
ListNode *pmid = reverseList(cur, m - 1, n);
return pmid;
}
Reverse Nodes in k-Group
1.题目描述:
给定一个链表,每k个节点反转一次链表,返回改变后的链表。其中k是正整数且小于链表的长度,如果链表的长度不是k的倍数,则链表结尾不足k个的部分保持不变。举个例子:给定链表 1->2->3->4->5,如果k = 2,则返回 2->1->4->3->5;如果k = 3,则返回 3->2->1->4->5。
2.思路:
这道题跟上面的题目可以使用同样的方法来实现。上面代码中实现的reverseList函数是反转start到end部分,其他部分保持不变,所以在本题中,循环反转,每次反转k个节点,第1次是0到k,第二次是k到2k,....,依次直到nk大于节点个数时,则最后一部分不需要进行反转。举个例子,链表 1->2->3->4->5,k = 2,则有:循环变量i = 0,i + k = 2小于链表长度,所以反转后得到2->1->3->4->5;
循环变量i = 2,i + k = 4小于链表长度,所以反转后得到2->1->4->3->5;
循环变量i = 4,i + k = 6大于链表长度,不需要反转,返回2->1->4->3->5;
3.代码展示
ListNode* reverseKGroup(ListNode* head, int k) {
if (head == NULL || head->next == NULL)
return head;
ListNode* pNode = head;
//计算节点总个数
int num = 0;
while (pNode != NULL) {
pNode = pNode->next;
num ++;
}
if (k > num)
return head;
ListNode* cur = head;
ListNode* temp;
for (int i = 0; i < num; i += k) {
//当i+k>num的话,说明最后一部分不够k个数,break即可。
if (i + k > num)
break;
temp = reverseList(cur, i, i + k);
cur = temp;
}
return cur;
}
总结
链表的题目特别要注意指针的处理,容易出现野指针或者空指针的问题。