链表(一)

目录

19.给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。

237.删除链表中的结点

83.删除排序链表中的重复元素

61.旋转链表

24. 两两交换链表中的节点

206. 反转链表

92. 反转链表 II(反转m-n之间的链表)

160. 相交链表

142. 环形链表 II


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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值