链表相关题目整理

求链表的倒数第k个节点
思路:两个指针同时指向head,第一个指针先走k-1步,然后两个指针同时移动,当第一个指针走到尾节点时,第二个指针指向的就是倒数第k个节点(这里使两个指针的距离和倒数第一个与倒数第k个节点距离相同即可),当然也需要考虑边界问题,如小于等于0,倒数第k个节点大于链表节点

Node* FindKthToTail(Node *head,int k)
{
	if(head == NULL || k <= 0)
		return;
	Node *pFirst = head;
	Node *pSecond = head;
	for(auto i = 0;i < k - 1;++i)
	{
		//倒数第k个大于链表节点
		if(pFirst == NULL)
			return NULL;
		pFirst = pFirst ->next;
	}
	while(pFirst->next != NULL)
	{
		pFirst = pFirst ->next;
		pSecond = pSecond ->next;
	}
	return pSecond ;
}

两个有序链表的合并
思路:刷题看到题解说了一种伪头结点的方法,这思路确实让题目变得简单易懂,仅仅是使用了一个辅助节点

class Solution {
public:
    ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
        ListNode *res = new ListNode(0), *p = res;
        while(l1 && l2 ){
            l1->val < l2->val ? (p->next = l1,l1 = l1->next) : (p->next = l2, l2 = l2->next);
            p = p->next;              
        }
        //判断哪条链表先遍历到了尾节点
        p->next = l1 ? l1 : l2;
        return res->next;
    }
};

递归

class Solution {
public:
    ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
        if(l1 == nullptr)
            return l2;
        if(l2 == nullptr)
            return l1;
        if(l1->val < l2->val)
        {
            l1->next = mergeTwoLists(l1->next,l2);
            return l1;
        }
        else
        {
            l2->next = mergeTwoLists(l1,l2->next);
            return l2;
        }
    }
};

两条单链表是否相交以及交点(不考虑单链表有环)
思路:1.暴力双循环遍历,当然效率也是最低。时间复杂度O(n²)
2.遍历两条链表分别求出长度为len1,len2,然后求出两者之差,较长的链表先移动|len1 - len2|。接着两条链表同时遍历
3.两条链表分别入栈,判断栈顶元素是否相同,相同则分别出栈直到栈顶元素不同为止

思路2:
Node *Intersect(Node *list1,Node *list2)
{
	if(list1 == NULL || list2 == NULL)
		return NULL;
	
	Node *pTemp1 = list1;
	Node *pTemp2 = list2;	
	int len1 = 1,len2 = 1;
	
	while(pTemp1 ->next != NULL)
	{
		pTemp1 = pTemp1->next;
		len1++;
	}
	while(pTemp2 ->next != NULL)
	{
		pTemp2 = pTemp2->next;
		len2++;
	}	
	
	if(pTemp1 != pTemp2)
		return NULL;
	
	pTemp1 = list1;
	pTemp2 = list2;		
	if(len1 > len2)
	{
		int diff = len1 - len2;
		for(auto i = 0;i < diff;++i)
		{
			pTemp1 = pTemp1->next;
		}
	}
	else if (len1 < len2)
	{
		int diff = len2 - len1;
		for(auto i = 0;i < diff;++i)
		{
			pTemp2 = pTemp2->next;
		}
	}
	
	while(pTemp1 != pTemp2)
	{
		pTemp1 = pTemp1->next;
		pTemp2 = pTemp2->next;
	}
	return pTemp1;
}
思路3:
Node *Intersect(Node *list1,Node *list2)
{
	if(list1 == NULL || list2 == NULL)
		return;
		
	stack<Node> s1;
	stack<Node> s2;
	while(list1 != NULL)
	{
		s1.push(list1);
		list1 = list1->next;
	}
	while(list2 != NULL)
	{
		s2.push(list2);
		list2 = list2->next;
	}
	
	if(s1.top() != s2.top())
		return NULL;
	
	Node *temp = NULL;
	while(!s1.empty() && !s2.empty())
	{
		temp = s1.top();
		s1.pop();
		s2.pop();
		if(s1.top() != s2.top())
			break;
	}
	return temp;	
}

请实现 copyRandomList 函数,复制一个复杂链表。在复杂链表中,每个节点除了有一个 next 指针指向下一个节点,还有一个 random 指针指向链表中的任意节点或者 null。
在这里插入图片描述

方法一

class Solution {
public:
    Node* copyRandomList(Node* head) {
        if(head == nullptr) return nullptr;
        Node* cur = head;
        unordered_map<Node*, Node*> map;
        // 3. 复制各节点,并建立 “原节点 -> 新节点” 的 Map 映射
        while(cur != nullptr) {
            map[cur] = new Node(cur->val);
            cur = cur->next;
        }
        cur = head;
        // 4. 构建新链表的 next 和 random 指向
        while(cur != nullptr) {
            map[cur]->next = map[cur->next];
            map[cur]->random = map[cur->random];
            cur = cur->next;
        }
        // 5. 返回新链表的头节点
        return map[head];
    }
};

方法二

class Solution {
public:
    Node* copyRandomList(Node* head) {
        if(head == nullptr) 
            return nullptr;
        Node* cur = head;
        // //将拷贝节点放到原节点后面,例如1->2->3这样的链表就变成了这样1->1'->2->2'->3->3'
        while(cur != nullptr) {
            Node* tmp = new Node(cur->val);
            tmp->next = cur->next;
            cur->next = tmp;
            cur = tmp->next;
        }
        // 2. 把拷贝节点的random指针安排上
        cur = head;
        while(cur != nullptr) {
            if(cur->random != nullptr)
                cur->next->random = cur->random->next;
            cur = cur->next->next;
        }
        // 3. 分离拷贝节点和原节点,变成1->2->3和1'->2'->3'
        cur = head;
        Node* res = head->next, *temp = nullptr;
        while(cur != nullptr && cur->next != nullptr) 
        {
            temp = cur->next;
            cur->next = temp->next;
            cur = temp;
        }
        return res;      // 返回新链表头节点
    }
};
posted @   J1nu  阅读(14)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
点击右上角即可分享
微信分享提示