Chapter 2 | Linked Lists Cracking

Linked list questions are extremely common These can range from simple (delete a node ina linked list) to much more challenging Either way, we advise you to be extremely comfortable with the easiest questions Being able to easily manipulate a linked list in the simplestways will make the tougher linked list questions much less tricky With that said, we present some “must know” code about linked list manipulation You should be able to easily writethis code yourself prior to your interview

链表是面试中非常常见的问题。问题难度有难有易。无论题目如何,我们都建议你先练熟简单题目。掌握了简单链表题,面对那些难题的时就会轻松一点。所以下面列出了一些链表题中必备的代码。

2.1 

Write code to remove duplicates from an unsorted linked list.
FOLLOW UP
How would you solve this problem if a temporary buffer is not allowed?

译文:

从一个未排序的链表中移除重复的项

进一步地,

如果不允许使用临时的缓存,你如何解决这个问题?

解答

如果不能额外使用空间的话,我们就需要两个指针来遍历数组:current用来正常的遍历;runner则用来检查元素是否重复。runner只为一个元素检查一次是否重复,因为每一次runner会删除和元素的所有重复元素。

#include <iostream>

using namespace std;

class Node 
{
public:
	int data;
	Node *next;
};

Node* CreateLinkedlist(int *a,int n)//头插法建链表
{
	Node *head = new Node();
	head->data = a[0];

	for(int i=1; i < n; i++){
		Node *nd = new Node();
		nd->data = a[i];
		
		nd->next = head;
		head = nd;
	}
	return head;
}

void removeDuplicates(Node *head)
{
	if(head == NULL) return;
	Node *p, *q, *c=head;
	while(c){
		p=c; q=c->next;
		int d = c->data;
		while(q){
			if(q->data==d){
				Node *t = q;
				p->next = q->next;
				q = p->next;
				delete t;
			}
			else{
				p = q; q = q->next;
			}
		}
		c = c->next;
	}
}
int main()
{
	int a[] = {1,2,3,4,55,2,3,6};
	Node *head = CreateLinkedlist(a,6);
	removeDuplicates(head);
	while(head)
	{
		cout<<head->data<<" ";
		head = head->next;
	}
	delete head;
	return 0;
}


2.2 

Implement an algorithm to find the nth to last element of a singly linked list.

译文:

实现一个算法从一个单链表中返回倒数第n个元素。

解答


直接上,同时维护两个指针s 和 p,同时指向头结点,然后 s不动,p走n步;然后同时移动直到p到达链表尾部。此时s所指即倒数第n个元素

Node* findLastN(Node *head,int n)
{
	Node *s,*p;
	s = p = head;
	for (int i = 0; i < n; i++)
	{
		p = p->next;
	}
    while(p)
	{
		s = s->next;
		p = p->next;
	}
	return s;
}


2.3 

Implement an algorithm to delete a node in the middle of a single linked list, given only access to that node.
EXAMPLE
Input: the node ‘c’ from the linked list a->b->c->d->e
Result: nothing is returned, but the new linked list looks like a->b->d->e

译文:

实现一个算法来删除单链表中间的一个结点,只给出指向那个结点的指针。

例子:

输入:指向链表a->b->c->d->e中结点c的指针

结果:不需要返回什么,得到一个新链表:a->b->d->e

解答

The solution to this is to simply copy the data from the next node into this node and then delete the next node.
NOTE: This problem can not be solved if the node to be deleted is the last node in the linked list. That’s ok—your interviewer wants to see you point that out. You could consider marking it as dummy in that case. This is an issue you should discuss
with your interviewer.

本题的解答只是把输入的下一个元素拷贝到输入的这个元素中以完成删除输入的元素。
注意:这样的方法并不能删除链表的最后一个元素。这一点需要和你的面试官说清楚。算法有缺陷没有关系,大胆的告诉你的面试官,他们喜欢看到你提出这些。至于怎么解决可以和你的面试官讨论。

bool remove(node *c){
    if(c==NULL || c->next==NULL) return false;
    node *q = c->next;
    c->data = q->data;
    c->next = q->next;
    delete q;
    return true;
}

2.4

 You have two numbers represented by a linked list, where each node contains a single
digit. The digits are stored in reverse order, such that the 1’s digit is at the head of the list. Write a function that adds the two numbers and returns the sum as a linked list.
EXAMPLE
Input: (3 -> 1 -> 5) + (5 -> 9 -> 2)
Output: 8 -> 0 -> 8

译文:

你有两个由单链表表示的数。每个结点代表其中的一位数字。数字的存储是逆序的, 也就是说个位位于链表的表头。写一函数使这两个数相加并返回结果,结果也由链表表示。

例子:(3 –> 1 –> 5), (5 –> 9 –> 2)

输入:8 –> 0 –> 8

解答

这道题目并不难,需要注意的有:1.链表为空。2.有进位。3.链表长度不一样。 代码如下:

Node* addList(Node* l1,Node* l2)
{
	int c = 0;
	Node *head = l1,*p1 = l1,*p2 = l2,*temp;
	while(l1&&l2)
	{
		l1 = l1->next;
		l2 = l2->next;
	}
	if (l1)                //l1长
	{
		head = temp = p1;
	}else{                 //l2长
		head = temp = p2;
	}
	while(p1&&p2)                     //先处理短链表长度的相加
	{
		int v = (p1->data + p2->data + c)/10;
		

		temp->data = (p1->data + p2->data + c)%10;

		if ( v == 1)
		{
			c = 1;
		}else{
			c = 0;
		}
		p1 = p1->next;
 		p2 = p2->next;
		temp = temp->next;
     }
	if (temp)                        //不等
	{
		if((temp->data + c)/10)      //有进位
		{
			temp->data = (temp->data + c)%10;
			Node *node = new Node();
			node->data = c;
			temp->next = node;
		}else{
			temp->data = temp->data + c;
		}
	}else if (c)                     //一样长,而且有进位
	{
		Node *node = new Node();
		node->data = c;
        temp = node;
	}
	return head;
}

2.5
Given a circular linked list, implement an algorithm which returns node at the beginning
of the loop.
DEFINITION
Circular linked list: A (corrupt) linked list in which a node’s next pointer points to an earlier node, so as to make a loop in the linked list.
EXAMPLE
input: A -> B -> C -> D -> E -> C [the same C as earlier]
output: C

译文:

给定一个循环链表,实现一个算法返回这个环的开始结点。

定义:

循环链表:链表中一个结点的指针指向先前已经出现的结点,导致链表中出现环。

例子:

输入:A –> B –> C –> D –> E –> C [结点C在之前已经出现过]

输出:结点C

解答

If we move two pointers, one with speed 1 and another with speed 2, they will end up meeting if the linked list has a loop   Why?  Think about two cars driving on a track—the faster car will always pass the slower one! The tricky part here is finding the start of the loop   Imagine, as an analogy, two people racing around a track, one running twice as fast as the other   If they start off at the same place, when will they next meet?  They will next meet at the start of the next lap
Now, let’s suppose Fast Runner had a head start of k meters on an n step lap When will 
they next meet?  They will meet k meters before the start of the next lap   (Why? Fast Runner would have made k + 2(n - k) steps, including its head start, and Slow Runner would have made n - k steps   Both will be k steps before the start of the loop ) 
Now, going back to the problem, when Fast Runner (n2) and Slow Runner (n1) are moving around our circular linked list, n2 will have a head start on the loop when n1 enters   Specifically, it will have a head start of k, where k is the number of nodes before the loop   Since n2 has a head start of k nodes, n1 and n2 will meet k nodes before the start of the loop  
So, we now know the following: 
1     Head is k nodes from LoopStart (by definition)  
2     MeetingPoint for n1 and n2 is k nodes from LoopStart (as shown above)  
Thus, if we move n1 back to Head and keep n2 at MeetingPoint, and move them both at the same pace, they will meet at LoopStart  

如果在链表中有两个指针,从表头开始p1以每次一个节点的速度前进,p2每次2个。那么这两个指针一定在链表的环中相遇。想想两辆车以不同的速度在一个环形跑道上运动,那么他们肯定会在跑道上再次相遇。
这个问题最难的部分就在于如何找出这个环开始的节点。假想下如果是在一个圆形的跑道上p2以两倍的速度于p1同时从起点出发,他们将会哪里相遇。还是在起点!
现在我们再假设如果p2超前起跑线k米起跑,他们第一次在哪里相遇呢?在起跑线后面k米处。(为什么?假设p2过了起跑线之后跑了x和p1相遇,那么p2跑了l-k+x,其中l为跑道的长度,至相遇时p1也跑了x。根据相遇时消耗的时间相等得方程 (l-k-x)/2=x/1,解得 x = l-k,也就是在起跑线后k处相遇。)


那重新回到问题本身,当p1指针刚进入环的时候,p2在环中恰好领先p1指正k个节点,k为链表头节点到环开始处的距离。根据之前的结论,当p1、p2相遇的时候,他们都相距环开始节点k个距离。
那么我们得到如下结论:
(1)表头距离环开始处k节点
(2)p1,p2距离环开始处也是k个节点。
如果当p1、p2相遇之后,将p1至于表头然后两个指针都采用1的速度移动的话。那么相遇处即为环开始处。 

node* loopstart(node *head){
    if(head==NULL) return NULL;
    node *fast = head, *slow = head;
    while(fast->next!=NULL){
        fast = fast->next->next;
        slow = slow->next;
        if(fast==slow) break;
    }
    if(fast->next==NULL) return NULL;
    slow = head;
    while(fast!=slow){
        fast = fast->next;
        slow = slow->next;
    }
    return fast;
}


还有另外一种方法也比较直观,让快慢指针走链表直至在环中相遇,固定其中一个,让另外一个单步继续走链表至再次相遇,可得到环的长度L,再将两个指针一个指向表头,一个向前走L步,之后一起走链表至相遇,此时的位置就是环的起始节点。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值