目录
19.给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。
19.给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。
找出倒数第n+1个结点
1.有可能删除头结点,所以创建一个虚拟结点指向头结点
2.创建一个指针p从前往后走n步
3.创建一个新的指针q指向头结点
4.p、q同时向后走,当p指向最后一个结点的时候,q指向倒数第n+1个结点
删除第n个结点 q->next = q->next->next;
delete虚拟结点
#include<iostream>
using namespace std;
struct ListNode
{
int val;
ListNode *next;
ListNode(int x) : val(x), next(NULL) {}
};
class Solution
{
public:
ListNode* removeNthFromEnd(ListNode* head, int n)
{
auto dummy = new ListNode(-1);
dummy->next = head;
ListNode* xuni = new ListNode(-1); //创建一个虚拟结点
xuni->next = head; //将虚拟结点的下一个结点指向真实的头结点
ListNode* p = xuni;
for(int i = 0;i<n;i++)
{
p = p->next;
}
ListNode* q = xuni;
while(p->next)
{
p = p->next;
q = q->next;
}
q->next = q->next->next;
return xuni->next;
delete xuni;
}
};
237.删除链表中的结点
/*编写一个函数,使其可以删除某个链表中给定的(非末尾)节点,你将只被给定要求被删除的节点。现有一个链表 -- head = [4,5,1,9]
输入: head = [4,5,1,9], node = 5
输出: [4,1,9]
解释: 给定你链表中值为 5 的第二个节点,那么在调用了你的函数之后,该链表应变为 4 -> 1 -> 9.
*/
//(1)
//用下一个结点的值把当前结点的值覆盖掉
node->val= node->next->val;
//删除下一个结点
node->next = node->next->next;
//(2)
*(node) = (*node->next);
83.删除排序链表中的重复元素
给定一个排序链表,删除所有重复的元素,使得每个元素只出现一次。
示例 1:
输入: 1->1->2->3->3
输出: 1->2->3
//情况1:如果下一个点和当前点相同,删除下一个点
//情况2:如果下一个点和当前点不同,则指针移到下一个点
ListNode *p = head;
while(p)
{
if(p->next && p->next->val == p->val)
{
p->next = p->next->next;
}
else
{
p=p->next;
}
}
return head;
61.旋转链表
旋转1个就是将最后一个移到前面去
选装k个就是将k个移到最前面去
有可能k超过链表长度
1.k%=n
2.找到倒数第k+1个结点和尾结点
first指针从头往后走k步
first和second同时往后走,当first走到尾部的时候,停止
if(!head)
return NULL;
int n = 0;
for(auto p = head;p;p=p->next)
n++;
k %= n;
auto first = head,second = head;
while(k--)
first = first->next;
while(first->next)
{
first = first->next;
second = second->next;
}
first->next =head;
head = second->next;
second->next = NULL;
return head;
24. 两两交换链表中的节点
头结点会变,弄一个虚拟结点
1.交换要修改的两个位置
先将虚拟结点指向第二个位置
将第一个结点指向第三个位置
然后将第二个结点指向第一个位置
auto dummy = new ListNode(-1);
dummy->next = head;
for(auto p = dummy;p->next && p->next->next;)
{
auto a = p->next,b=a->next;
p->next = b;
a->next = b->next;
b->next = a;
p = a;
}
return dummy->next;
206. 反转链表
将中间的链表指向一个一个的反转
最后将头结点指向空
返回最后一个结点
if(!head)
return NULL;
auto a = head,b= head->next;
while(b)
{
auto c = b->next; //c先把b后面的结点保存起来
b->next = a; //反转指向,将b指向a
a = b,b=c; //a,b分别向后移一位
}
head->next = NULL; //此时头结点为最后一个结点,将头结点的next置为空
return a; //a为最后一个结点,也就是现在的新的头结点,返回即可
92. 反转链表 II(反转m-n之间的链表)
1.先将m到n之间的指针翻转(不包含第m个结点)
2.将m的指针指向n后面那个结点,m前面的指针pre指向n
auto dummy = new ListNode(-1),pre = dummy; //创建一个虚拟结点
dummy->next = head;
for(int i = 0;i< m-1 ;i++)
pre = pre->next; //将pre指向遍历到m的前一个结点处
auto cur = pre->next; //cur为m结点处
//反转m到n之间的结点
for(int i = m;i<n;i++)
{
auto t = cur->next; //定义一个t保存当前结点的下一个结点
cur->next = t->next; //将当前结点指向t的下一个结点
t->next = pre->next; //将t的下一个结点指向pre的下一个结点
pre->next = t; //将pre的下一个结点指向t
}
return dummy->next;
160. 相交链表
两个链表不相交的话,返回null
两个链表相交
1.定义两个指针p,q分别走a,b两条链表
当p走完a链表时,走b链表;当q走完b链表时,走a链表
即p,q会在a+b+c处相遇.所以时间复杂度为O(n)
auto p = headA,q = headB;
while(p != q)
{
if(p)
p=p->next;
else
p = headB;
if(q)
q=q->next;
else
q = headA;
}
return p;
142. 环形链表 II
下次相遇的位置就是入环的第一个结点。
因为快指针每次走两步,慢指针每次走一步,快指针每次走的步数是慢指针的二倍。第一次相遇的时候,快指针就至少比慢指针多走了一圈。所以从head到环的起点+环的起点到它们相遇的点的距离与 环一圈的距离相等。
现在重新开始,head运行到环起点 和 相遇点到环起点的距离也是相等的,相当于它们同时减掉了 环的起点到它们相遇的点的距离
auto fast = head,slow = head; //定义两个快慢指针,快指针每次走两步,慢指针每次走一步
while(slow)
{
fast = fast->next;
slow = slow->next;
if(slow)
slow=slow->next;
else
break;
if(fast == slow) //当快慢指针相遇的时候
{
slow = head; //将慢指针从头开始重新走
while(slow!=fast) //下次快慢指针相遇的位置就是入环的第一个结点
{
fast=fast->next;
slow = slow->next;
}
return slow;
}
return NULL;
}