链表

链表题的分类

1. 链表题中很多需要靠快慢指针去定位,快指针先走,慢指针负责后勤,万一快指针执行了某种节点删除工作,慢指针还是能够弥补回来的:比如jz18_删除链表的节点,慢指针越过快指针将其删除;
2. 快慢指针还可以用于定位,jz22_链表中倒数第k个节点,先让快指针走k步,慢指针和快指针再同时出发隔了k个位置,当快指针到达最后一个有val节点时,这时慢指针就到达倒数第k个指针了,这时对其进行操作;
3. 
160.相交链表(中智行)
// 题解: 先遍历自己再遍历对方
// 时间复杂度O(m + n)  空间复杂度O(1)
ListNOde* getIntersectionNode(ListNode* headA, ListNode* headB){
    ListNode* p = headA, *q = headB;
    while(p!=q){
        // p=q 包含空指针的情况,也可以返回
        // if用if(p)而不是if(p->next),当面临两个/// 链表不相交时,也可以返回相交节点
        if(p) p=p->next;
        else p=headB;
        if(q) q=q->next;
        else q=headA;
        
    }
    return p;

}

// hashset方法
// 使用一个hashset,遍历一个链表,hashset中存放其所有指针  
// 遍历另一个链表,去hashset中找相同指针
// 时间复杂度O(m + n)    空间复杂度O(m) 或 O(n)


  ListNode* getIntersectionNode(ListNode* headA, ListNode* headB)
  {
    std::unordered_set<ListNode*> set;

    ListNode* cur_a = headA;
    // 先建立A链表的hash_set
    while (cur_a)
    {
      set.insert(cur_a);
      cur_a = cur_A->next;
    }

    ListNode* cur_b = headB;
    // 再在A链表中去搜索
    while (cur_b)
    {
      if (set.find(cur_b) != set.end())  // 找到了
      {
        return cur_b;
      }
      cur_b = cur_b->next;
    }

    return nullptr;
  }
142.环形链表2

在这里插入图片描述

// 思路主要是快慢指针
// 快指针速度为2,慢指针为1,当在环中相遇时,快指针是慢指针路程的两倍
// 表示为:2(x+y)=x+y+z+y,x=z
ListNode* detectCycle(ListNode* head)
{
    ListNode* fast = head, *slow = head;
    while(fast)
    {
        fast = fast->next;
        slow = slow->next;
        if(fast) fast = fast->next;
        else break; // 第一次fast->next为null的情况
        
        // 第一次相遇,slow回到原点
        if(fast == slow)
        {
            slow = head;
            while(fast!=slow)
            {
                fast = fast->next;
                slow = slow->next;
            }
            return slow;
        }
    }
    return NULL;
}
21.合并两个有序链表

在这里插入图片描述

ListNode* mergeTwoLists(ListNode* l1, ListNode* l2)
{
	ListNode* pHead = new ListNode*(-1);
	ListNode* prev = pHead;
	while(l1!=nullptr && l2!=nullptr)
	{
		if(l1->val<l2->val)
		{
			prev->next=l1;
			l1=l1->next;
		}
		else
		{
			prev->next=l2;
			l2=l2->next;
		}
		prev=prev->next;
	}
	prev->next= l1==nullptr?l2:l1;
	return pHead->next;
}
61.旋转链表

在这里插入图片描述

ListNode* rotateRight(ListNode* head, int k)
{
	ListNode* pHead = head;
	List
	int n = 0;
	while(pHead)
	{
		n++;
		pHead =pHead->next;
	}
	//for(auto p=head;p;p=p->next) n++;
    k%=n;
	ListNode* first, *second = head;
	while(k--) first=first->next;
	while(first)
	{
		first = first->next;
		second = second->next;
	}
	first->next=Head;
	Head=second->next;
	second->next = null;
	
	return Head;	
}
jz35.复制复杂链表

在这里插入图片描述

class Solution
{
	public:
		Node* copyRandomList(Nodes* head)
		{
			if(!head) return nullptr;
			unordered_map<Node*, Node*> mp;
			Node* t = head;
			while(t)
			{
				//刚开始的深拷贝,将原先的节点深拷贝后的儿子放入map与其父亲一一对应
				mp[t] = t;
				t = t->next;
			}
			t = head;
			while(t)
			{
				 // next与random指针的复制对应关系
				if(t->next) mp[t]->next = mp[t->next];
				if(t->random) mp[t]->random = mp[t->random];
				t = t->next;
			}
			return mp[head];
		}
}
// 参考:https://leetcode-cn.com/problems/fu-za-lian-biao-de-fu-zhi-lcof/solution/unordered_mapha-xi-biao-shi-xian-fu-za-lian-biao-s/
反转链表

涉及到链表的操作,一定要在纸上把过程先画出来,再写程序
在这里插入图片描述
主要思路:
定义一个cur和pre指针,随着遍历而反转
纸上画图!!!
双指针的方法,cur找一个前驱节点pre,每一次cur与前驱节点交换值的时候,要临时记录cur的next

ListNode* ReverseList(ListNode* pHead){
	// 找到前驱节点
	ListNode* pre=nullptr;
	ListNode* cur = pHead;
	while(cur){
		// 1. cur指向后驱节点
		ListNode* tmp = cur->next; // 提前保存
		cur->next=pre;
		// 2. 位置往前移动
		pre=cur;
		cur=tmp;
		#cur = cur->next; // 因为cur->next已经指向了指向了前向节点
	}
	return pre;
}
反转链表二

在这里插入图片描述
主要思路:
参考官方题解迭代法
链表的题先画图,然后结合图去理解程序
在这里插入图片描述

class Solution{
	ListNode reverseBetween(ListNode head, int m, int n){
		// Empth list
		if(head == null){
			return null;
		}
		// 1. move the two pointers until they reach the proper starting point in the List
		// 已到要反转的子链位置上(第二段)
		ListNode cur=head, prev=null; // 初始化节点cur,head
		while(m>1){
			prev = cur;
			cur=cur.next;
			m--;
			n--;
		}
		
		// 2.the two pointers that will fix the final connections
		// 初始化con tail 用于中间段与首段与第三段的连接
		ListNode con = perv, tail=cur;
		
		// 3.Iteratively reverse the nodes until n becones 0.
		// 反转中间段
		ListNode tmp = null; // 初始化tmp
		while(n>0){
			//tmp;
			tmp = cur.next;
			cur.next=prev;
			prev=cur; // 前进
			cur=tmp; // 前进
			n--
		}
		
		// 4. Adjust the final connections as explained in the algorithm
		// 完成中间段与首尾两段的连接,靠con,tail指针完成
		if(con != null){
			con.next=prev;
		}
		else{
			head=prev; // 只有一个节点的情况
		}
		tail.next=cur;
		return head;
	}
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值