链表面试笔试题目总结

本文总结了多种链表相关的面试题目,包括在单链表上插入元素、判断链表是否有环、找到链表中间节点、逆置链表、用链表实现栈和队列、寻找链表交点、并集与交集操作、删除链表中间元素、链表去重、链表求和、环链表问题、判断链表回文、从尾到头打印链表、链表排序算法以及复杂链表的复制等。每个题目都提供了详细的解答和实现思路。
摘要由CSDN通过智能技术生成

链表是最基本的数据结构,凡是学计算机的必须的掌握的,在面试的时候经常被问到,关于链表的实现,百度一下就知道了。在此可以讨论一下与链表相关的练习题。


1在单链表上插入一个元素,要求时间复杂度为O(1)

解答:一般情况在链表中插入一元素是在末尾插入的,这样需要从头遍历一次链表,找到末尾,时间为O(n)。要在O(1)时间插入一个新节点,可以考虑每次在头节点后面插入,即每次插入的节点成为链表的第一个节点。


2、给定一个链表,判断是否有环。

解答:这个是一个经典的问题了,思路也很简单,我们首先设置两个指针p1,p2同时指向链表的头部,然后p1每次向后走1步,p2每次向后走2步。如果有环,那么有一步会出现p1=p2,如果p2已经到达了尾结点,则无环。复杂度:时间:O(n),空间:O(1)

扩展:给定一个链表,找出环的入口位置。思路也是一样,用p1,p2指针。只是需要多做一步,那就是当p1=p2的时候,将p1重新指向链表的头结点,然后p1和p2都每次向后走一步,下一次p1=p2的结点就是环的入口。复杂度:时间:O(n),空间:O(1)


3遍历单链表一次,找出链表中间节点

解答:定义两个指针p和q,初始都指向链表头节点。然后开始向后遍历,p每次移动2步,q移动一步,当p到达末尾的时候,p正好到达了中间位置。


4、单链表逆置,不允许额外分配存储空间,不允许递归,可以使用临时变量,执行时间为O(n)

解答:这个题目在面试笔试中经常碰到,基本思想上将指针逆置。如下图所示:


实现:

Node* reverse_list(Node *head){
  Node *cur=head;
  Node *pre = NULL;
  Node *post = cur->next;
//    Node *reverse_head = cur;
  while(post){
      cur->next = pre;
      pre = cur;
      cur = post;
        post = post->next;
  }
  cur->next = pre;
//    reverse_head = cur;
  return cur;
}


扩展:链表翻转。给出一个链表和一个数k,比如,链表为1→2→3→4→5→6k=2,则翻转后2→1→6→5→4→3,若k=3,翻转后3→2→1→6→5→4,若k=4,翻转后4→3→2→1→6→5,用程序实现。

实质是也是逆置,只不过是两个链表逆置后再串联起来。实现如下:

bool rotate_list(Node *head,int k,Node* &newhead){
	if(k < 0)
		return false;
	else if(0 == k)
		return true;
	int len = 0;
	Node *node=head;
	while(node){
		++len;
		node = node->next;
	}
	if(k > len)
		return false;
	Node *one_end,*two_start;
	node = head;
	Node *post = node->next;
	int n=k;
	if(1 == n){
	}else{
		while(n > 1){// rotate sublist one
			node->next = post->next;
			post->next = head;
			head = post;
			post = node->next;
			--n;
		}
	}

	if(len-k <= 1){ // rotate sublist two
	}else{
        one_end = node;
        node = post;
        post = post->next;
        two_start = node;
        n = len-k;
        while(n>1){
            one_end->next = post;
            node->next = post->next;
            post->next = two_start;
            two_start = post;
            post = node->next;
            --n;
        }
	}
    newhead = head;
	return true;
}

5、用一个单链表L实现一个栈,要求pushpop的操作时间为O(1)

解答:根据栈中元素先进后出的特点,可以在链表的头部进行插入和删除操作


6、用一个单链表L实现一个队列,要求enqueuedequeue的操作时间为O(1)

解答:队列中的元素是先进先出,在单链表结构中增加一个尾指针,数据从尾部入队,从头

部入队。


7、给定两个链表(无环),判断是否有相交。

解答:首先明确一点,如果两个链表相交,那么从第一个交点开始到尾结点结束,所有的结点都是公共结点。所以,两个有公共结点而部分重合的链表,拓扑形状看起来像一个Y,而不可能像X。

这也就是说,如果两个链表相交,那么这两个链表的尾结点肯定是公共结点,如果尾结点不是公共结点,那么这两个链表肯定不相交。

所以我们可以如下操作:依次遍历两个链表,最后判断尾结点是否相同,如果相同,则相交,如果不相同,则不相交。复杂度:时间:O(m+n),空间:O(1)

或者一个链表的头结点指向另一个链表的尾节点,判断是否有环。


8、给定两个链表(无环),找到第一个公共节点。

解答:我们最容易想到的是从尾结点开始挨个向前比较,最后一个相同的就是第一个公共结点。(从后往前遍历)

但是单链表只能从前往后进行遍历,如果想要从后往前的话则需要先从前向后遍历一次,同时用来记录每一个结点,最后出栈,然后挨个对比,这样的确可行,但是却要额外付出O(m+n)的空间,时间复杂度O(mn)。(单链表+栈)

仔细想想,我们可以先分别遍历两个单链表,记录长度m和n(无妨假设m>n),然后先让长度为m的链表向后走(m-n)步,接着两个链表同时向后遍历,第一个相同的结点就是要求的第一个公共结点。复杂度:O(m+n)m,n分别为两个链表的长度;空间:O(1)

PS:另外还有一种巧妙的方法是把在一个链表尾部插入另一个链表,然后判断合成的新链表是否有环。环入口即为第一个公共点

可参考:

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值