第一节:求链表倒数第k个节点的值
题目:输入一个单向链表,输出该链表中倒数第k个结点,链表的倒数第0个结点为链表的尾指针
分析:首先这个链表时单向链表,并且我们也不知道链表的长度,那么仅仅凭借一个指针来找到倒数第k个节点,就需要知道链表的长度,因此需要先遍历整个链表,得到链表的长度过后,然后再从头结点开始寻找,这种方法显然很笨,那么我们可以用比较简单的方法吗?答案是肯定的,若当一个指针直到最后一个节点为一个flag,我们就可以知道另外一个指针已经指到了倒数第k个节点时,就可以很简单的解决这个问题,正好可以使用快慢指针方法。
> 快慢指针:还可以用于判断链表时否有环。
ElemType ReturnKValue(LinkList list, int k){
if(NULL == list || k > LengthList(&list)-1)
return '0';
LinkList p = list->next;
LinkList q = list->next;
while(k--){
q = q->next;
}
while(q->next != NULL){
q = q->next;
p = p->next;
}
return p->data;
}
第二节:编程判断两个链表是否相交
题目描述:给出两个单向链表的头指针(如下图所示),
比如h1、h2,判断这两个链表是否相交。这里为了简化问题,我们假设两个链表均不带环。
要想判断两个链表是否相交,其实方法有很多种:
- 暴力法:即将链表2中的每一个节点都与链表1中的每一个节点相比较,若存在相等的节点,那么两个链表即相交,这种方法的复杂度为O(Length(list1)*Length(list2);
- 将链表2添加到链表1的末尾,然后判断新的链表是否存在环,若存在环则表明两个链表相交(这种方法仅仅局限于两个链表都无环的情况);
- 针对第一个链表直接构造hash表,然后检查第二个链表中的每一个节点是否在该hash表中,若存在链表在hash表中,则表明两个链表相交,该方法的;
- 如上图所示,若两个链表相交,那么相交节点之后的节点都应该相同,因此我们只需要判断最后两个链表的最后一个节点是否相同即可,若相同则相交(链表无环)。
bool CheckListIntersect(LinkList list1, LinkList list2){
LinkList p = list1->next;
LinkList q = list2->next;
while(p->next != NULL)
p = p->next;
while(q->next != NULL)
q = q->next;
if(p == q)
return true;
return false;
}
上面的方法是已知两个链表都无环的判断情况,那么现在我们不知道两个链表是否有环,该如何判断两个链表是否相交呢?
- 首先判断两个链表是否有环:若一个链表有环,而一个链表无环,那么两个链表肯定不相交,若两个链表都无环则可以使用上面的方法;
- 若两个链表都有环,那么就求出其中一个链表上俩指针相遇的节点,然后检查该节点是否在另外一个链表上,若在,那么两个链表相交,若不在,则两个链表不相交。
检测链表是否有环:
bool isCircle(Node * head, Node *& circleNode, Node *& lastNode) {
Node * fast = head->next;
Node * slow = head;
while(fast != slow && fast && slow)
{
if(fast->next != NULL)
fast = fast->next;
if(fast->next == NULL)
lastNode = fast;
if(slow->next == NULL)
lastNode = slow;
fast = fast->next;
slow = slow->next;
}
if(fast == slow && fast && slow)
{
circleNode = fast;
return true;
}
else
return false;
}
判断两个链表是否相交:
bool detect(Node * head1, Node * head2)
{
Node * circleNode1;
Node * circleNode2;
Node * lastNode1;
Node * lastNode2;
bool isCircle1 = isCircle(head1,circleNode1, lastNode1);
bool isCircle2 = isCircle(head2,circleNode2, lastNode2);
//一个有环,一个无环
if(isCircle1 != isCircle2)
return false;
//两个都无环,判断最后一个节点是否相等
else if(!isCircle1 && !isCircle2)
{
return lastNode1 == lastNode2;
}
//两个都有环,判断环里的节点是否能到达另一个链表环里的节点
else
{
Node * temp = circleNode1->next;
while(temp != circleNode1)
{
if(temp == circleNode2)
return true;
temp = temp->next;
}
return false;
}
return false;
}
注:求环和该代码转自july博客:http://blog.csdn.net/v_july_v/article/details/6447013
扩展:求两个链表相交的第一个节点
思路:首先判断两个链表的尾节点是否相等,若相等,则两个链表必定相交。由于相交的部分是等长的,因此我们可以先判断两个链表的长度,若等长,则从第一个节点开始比较,第一个相等的节点即为相交的第一个节点;若不等长呢?这时候我们就可以使用快慢指针:让长的一个链表先走Length(long)-Length(short)步,因为在开始出长的部分肯定不存在相交的节点,这样就可以先等长两个链表,然后通过上述的方法来求第一个节点。