链表面试题总结----(可能带环相交问题+复杂链表的复制)

1.顺序表和链表的优缺点以及适应场景

顺序表支持随机访问,而单链表不支持随机访问;

顺序表插入/删除数据效率很低,时间复杂度为O(N)(除尾插尾删),单链表插入/删除效率更高,时间复杂度为O(1)。

  • 顺序表的CPU高速缓存效率更高,单链表CPU高速缓存效率低。

  • 适用场景:

  • 频繁的查找却很少的插入和删除操作可以用顺序表存储,如果频繁的插入和删除操作很少的查询就可以使用链表存储。

2.逆置单链表

/*
struct ListNode {
	int val;
	struct ListNode *next;
	ListNode(int x) :
			val(x), next(NULL) {
	}
};*/
class Solution {
public:
    ListNode* ReverseList(ListNode* pHead)
    {
		if(pHead==NULL||pHead->next==NULL)
               return pHead;
        ListNode* newpHead=pHead;
        pHead=pHead->next;
        newpHead->next=NULL;
        ListNode* cur=NULL;
        while(pHead!=NULL)
        {
            cur=pHead;
            pHead=pHead->next;
            cur->next=newpHead;
            newpHead=cur;
        }
        pHead=newpHead;
        return pHead;
    }
};

3.从尾到头打印单链表

/**
*  struct ListNode {
*        int val;
*        struct ListNode *next;
*        ListNode(int x) :
*              val(x), next(NULL) {
*        }
*  };
*/
class Solution {
public:
    vector<int> printListFromTailToHead(ListNode* head) {
        vector<ListNode*> v;
        ListNode* cur=head;
        while(cur!=NULL){
            v.push_back(cur);
            cur=cur->next;
       }
        int countNode=v.size();
        vector<int>  rList;
        for(int i=countNode-1;i>=0;i--){
            rList.push_back(v[i]->val);
        }
			return rList;    
    }
};

递归版(一般从尾到头都可以转化为递归和非递归两个版本)

/**
*  struct ListNode {
*        int val;
*        struct ListNode *next;
*        ListNode(int x) :
*              val(x), next(NULL) {
*        }
*  };
*/
class Solution {
public:
    vector<int> printListFromTailToHead(ListNode* head) 
    {
        vector<int> v;
        _printListFromTailToHead(head,v);
        return v;
    }
    void _printListFromTailToHead(ListNode* head,vector<int>& v)
    {
        if(head==NULL)
            return ;
        _printListFromTailToHead(head->next,v);
        v.push_back(head->val);
        return ;
    }
};



4.删除无头单链表的非尾结点

//采用的替换值的方法去删除它的下一个结点(找个替身)
	void RemoveNodeWired(Node* node)
	{
		if (node->_next == NULL || node == NULL)
			return;  //证明为尾结点或者当前结点为空
		Node* del = node->_next;
		swap(del->_value, node->_value); //将当前结点的值和要删除结点的值交换
		node->_next = del->_next;
		del->_next = NULL;
		delete del;
	}


5.判断两个链表是否相交(不带环)

Node* ListIntersect(Node* pHead1, Node* pHead2)
	{
		if (pHead1 == pHead2)  //头结点一样
			return pHead1;
		if (pHead1 == NULL || pHead2 == NULL) 
			return NULL;
		stack<Node*> s1; //保存链表1的结点
		stack<Node*> s2; //保存链表2的结点
		Node* cur = pHead1;
		while (cur != NULL)
		{
			s1.push(cur);
			cur = cur->_next;
		}
		cur = pHead2;
		while (cur != NULL)
		{
			s2.push(cur);
			cur = cur->_next;
		}
		if (s1.top() != s2.top()) //尾结点不一样
		{
			return NULL;
		}
		//链表一定有相交结点,且不为头结点
		Node* prev = NULL;
		while (s1.top()==s2.top())
		{
			prev = s1.top();
			s1.pop();
			s2.pop();
		}
		return prev;
	}


6.判断一个链表是否带环,并且返回环的长度

	//返回环的长度和环的入口结点
	pair<ListNode*,int> EntryNodeOfLoop(ListNode* pHead)
	{
		Node* slow = pHead;
		Node* fast = pHead;
		Node* None = NULL;
		int count = 0;
		while (slow != NULL && fast->_next != NULL)
		{
			//利用快慢指针判环
			slow = slow->_next;
			fast = fast->_next->_next;
			if (fast == slow) //证明有环
			{
				//将快慢指针任意一个从头结点开始走,二者按一步一节点的速度相遇就是环的入口点
				slow = pHead;
				while (slow != fast)
				{
					slow = slow->_next;
					fast = fast->_next;
				}
				while (slow->_next != fast)
				{
					count++;
					slow = slow->_next;
				}
				return make_pair(fast, count + 1);
			}
		}
		return make_pair(None,0);
	}







7.判断两个链表是否相交?相交求交点(可能带环)

	Node* ListIntersectHasRing(Node* pHead1, Node* pHead2)
	{
		if (pHead1 == pHead2)  //头结点一样
			return pHead1;
		if (pHead1 == NULL || pHead2 == NULL)
			return NULL;
		pair<Node*, int>	RingNode1 = EntryNodeOfLoop(pHead1);  //entryNodeOfLoop用来判环的入口点
		pair<Node*, int> RingNode2 = EntryNodeOfLoop(pHead2);
		if (RingNode1.first == NULL&&RingNode2.first == NULL) //证明两个链表不带环
			return  ListIntersect(pHead1, pHead2);
		if ((RingNode1.first == NULL&&RingNode2.first != NULL) || 
			(RingNode1.first != NULL&&RingNode2.first == NULL))  //一个带环一个不带环
			return NULL;
		//两个都带环
		Node* cur = pHead1;
		//是同一个环环的入口点一样但是交点可能在到环的入口点的路上
		if (RingNode1.first == RingNode2.first)  //环的入口点一样的
		{
			stack<Node*>  s1;
			stack<Node*>  s2;
			while (cur != RingNode1.first->_next)  //可能交点就为环入口,所以要到下一个结点
			{
				s1.push(cur);
				cur = cur->_next;
			}
			cur = pHead2;
			while (cur != RingNode2.first->_next)
			{
				s2.push(cur);
				cur = cur->_next;
			}
			Node* prev = NULL;
			while (!s1.empty() && !s2.empty() && s1.top() == s2.top())
			{
				prev = s1.top();
				s1.pop();
				s2.pop();
			}
			return prev;
		}
		//判断是不是同一个环
		int count = 0; //count用来记录cur经过RingNode环入口点的次数
		cur = pHead1;
		while (count!= 2) //经过自身的环入口点超过两次,证明两个在不同的环上
		{
			if (cur==RingNode1.first)  //证明经过自身的环入口点
			{
				count++;
			}
			if (cur == RingNode2.first)  //证明在同一个环上,随便返回环的哪一个入口点都可
			{
				return RingNode2.first;
			}
			cur = cur->_next;
		}
		return NULL;
	}


 

8.复杂链表的复制

struct RandomListNode 
{
	int label;
	struct RandomListNode *next, *random;
	RandomListNode(int x)
	:label(x)
	, next(NULL)
	, random(NULL) 
	{}
};

class Solution {
public:
	typedef RandomListNode Node;
	RandomListNode* Clone(RandomListNode* pHead)
	{
		if (pHead == NULL)
			return NULL;
		Node* cur = pHead->next;
		Node* newHead = new Node(pHead->label);
		Node* newCur = newHead;
		vector<Node*> Random;
		vector<Node*> NewList;
		NewList.push_back(newHead);
		Random.push_back(pHead->random);
		while (cur != NULL)
		{
			Random.push_back(cur->random);
			Node* newNode = new Node(cur->label);
			newCur->next = newNode;
			newCur = newNode;
			NewList.push_back(newNode);
			cur = cur->next;
		}
		vector<int> RandomPosition;
		int count = 0;
		for (size_t i = 0; i < Random.size(); i++)
		{
			cur = pHead;
			count = 0;
			if (Random[i] == NULL)
			{
				RandomPosition.push_back(-1);
			}
			else
			{
				while (cur != NULL)
				{
					if (cur == Random[i])
					{
						RandomPosition.push_back(count);
						break;
					}
					cur = cur->next;
					count++;
				}
			}
		}
		for (size_t i = 0; i < NewList.size(); i++)
		{
			if (RandomPosition[i] == -1)
			{
				NewList[i]->random = NULL;
			}
			else
			{
				NewList[i]->random = NewList[RandomPosition[i]];
			}
		}
		return newHead;
	}
};




  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值