链表中一些有趣的小题目总结
2016-03-28 23:45
337 查看
1、单链表中间结点
问:如何快速查找定位到一条单链表的中间结点?
答:(1)、可以将链表中的所有结点遍历一遍得到总个数,再查找到中间结点(这不废话嘛,这么low的答案就不拉出来献丑了=、=)
(2)、可以使用快慢指针法,一个指针一倍速率遍历,另一个指针两倍速率遍历链表,当第一个走到末尾时第二个则刚好在中间位置
代码:
NODE *Search(NODE *pHead)
{
NODE *fast = pHead, *slow = pHead;
while(fast)
{
if (fast->pNext == NULL)
fast = fast->pNext;
else
fast = fast->pNext->pNext;
slow = slow->pNext;
}
return slow;
}
2、链表中是否有环
问:如何判断一个单链表中是否有环存在,如果存在则找出环的入口(即链表环的)
答:还是用快慢指针的方式,将快指针二倍速率遍历链表,用慢指针一倍速率遍历链表,分别记录快慢指针走的步数,如果两个指针相遇,且步数不一致则表示有环,否则无环。
代码:
3、判断两个单链表是否相交
问:如何判断两个单链表是否相交,如果相交则给出第一个相交的点
答:(1)、将一个链表首尾相连,判断另一个链表中是否有环,如果有环,则两个链表相交,而链表的环入口就是第一个相交的点,如果没有环则两个链表不相交
代码:
(2)、将一条链表从头遍历到尾,再判断第二条链表的尾结点是否和第一条相同,如果相同则相交。这时我们记下链表的长度。将两条链表重新遍历一次,此次遍历时较长链表的起点置为length(较长) – length(较短)的结点处,较短链表从头结点开始,当两个结点第一次相遇时该点就是相交的第一个点。
代码:
4、在平均时间复杂度为O(1)内删除给定的结点
问:在时间复杂度为O(1)的范围内删除给定的结点。
答:采用“偷梁换柱法”,将待删除结点后边的那个结点的值赋值待删除结点,再将待删除结点后边的结点删除。当然此方法只能用于非尾结点,如果是尾结点则只能通过遍历找到尾结点的前一个结点,此时的平均时间复杂度为:[(n-1)*O(1)+O(n)]/n
= O(1)
代码:
5、求链表倒数第k个结点
问:求单链表的倒数第k个结点(尾结点是倒数第一个结点)
答:两个指针p1和p2,p1,p2指向首结点,再将p1向后移动k步,将p1和p2同时向后移,移动到p1为最后一个结点时p2所在位置就是倒数第k个结点。
代码:
问:如何快速查找定位到一条单链表的中间结点?
答:(1)、可以将链表中的所有结点遍历一遍得到总个数,再查找到中间结点(这不废话嘛,这么low的答案就不拉出来献丑了=、=)
(2)、可以使用快慢指针法,一个指针一倍速率遍历,另一个指针两倍速率遍历链表,当第一个走到末尾时第二个则刚好在中间位置
代码:
NODE *Search(NODE *pHead)
{
NODE *fast = pHead, *slow = pHead;
while(fast)
{
if (fast->pNext == NULL)
fast = fast->pNext;
else
fast = fast->pNext->pNext;
slow = slow->pNext;
}
return slow;
}
2、链表中是否有环
问:如何判断一个单链表中是否有环存在,如果存在则找出环的入口(即链表环的)
答:还是用快慢指针的方式,将快指针二倍速率遍历链表,用慢指针一倍速率遍历链表,分别记录快慢指针走的步数,如果两个指针相遇,且步数不一致则表示有环,否则无环。
代码:
int IsRing(NODE *pHead, NODE **pEnter) { int a = 0, b = 0; NODE *pFast = pHead, *pSlow = pHead; while(pFast != NULL && pFast->pNext != NULL) { pFast = pFast->pNext->pNext; pSlow = pSlow->pNext; a++; b += 2; if (pFast == pSlow && a != b){ pFast = pHead; while(pFast != pSlow){ pFast = pFast->pNext; pSlow = pSlow->pNext; } *pEnter = pSlow; return 1; } } *pEnter = NULL; return 0; }
3、判断两个单链表是否相交
问:如何判断两个单链表是否相交,如果相交则给出第一个相交的点
答:(1)、将一个链表首尾相连,判断另一个链表中是否有环,如果有环,则两个链表相交,而链表的环入口就是第一个相交的点,如果没有环则两个链表不相交
代码:
int IsIntersection(NODE *pHead1, NODE *pHead2, NODE **intersec) { NODE *temp = pHead1; while(temp->pNext){ temp = temp->pNext; } temp->pNext = pHead1; return IsRing(pHead2, intersec); //上题中的函数 }
(2)、将一条链表从头遍历到尾,再判断第二条链表的尾结点是否和第一条相同,如果相同则相交。这时我们记下链表的长度。将两条链表重新遍历一次,此次遍历时较长链表的起点置为length(较长) – length(较短)的结点处,较短链表从头结点开始,当两个结点第一次相遇时该点就是相交的第一个点。
代码:
int IsIntersection(NODE *pHead1, NODE *pHead2, NODE **intersec) { int length1 = 0, length2 = 0, i, len; NODE *pTemp1 = pHead1, *pTemp2 = pHead2; //第一条链表从头遍历到尾 while(pTemp1->pNext){ pTemp1 = pTemp1->pNext; length1++; } //第二条链表从头遍历到尾 while(pTemp2->pNext){ pTemp2 = pTemp2->pNext; length2++; } //如果相交则从新遍历 if (pTemp1 == pTemp2){ len = abs(length1 - length2); pTemp1 = pHead1; pTemp2 = pHead2; //将较长链表的遍历起始位置到lengthmax - lengthmin处 if (length1 > length2){ for (i = 0; i < len; i++){ pTemp1 = pTemp1->pNext; } } else { for (i = 0; i < len; i++){ pTemp2 = pTemp2->pNext; } } while(pTemp1 != pTemp2){ pTemp1 = pTemp1->pNext; pTemp2 = pTemp2->pNext; } *intersec = pTemp1; return 1; } *intersec = NULL; return 0; }
4、在平均时间复杂度为O(1)内删除给定的结点
问:在时间复杂度为O(1)的范围内删除给定的结点。
答:采用“偷梁换柱法”,将待删除结点后边的那个结点的值赋值待删除结点,再将待删除结点后边的结点删除。当然此方法只能用于非尾结点,如果是尾结点则只能通过遍历找到尾结点的前一个结点,此时的平均时间复杂度为:[(n-1)*O(1)+O(n)]/n
= O(1)
代码:
void DelNode(NODE *pHead, NODE *pDel) { NODE *pTemp = pHead, *pTar; if (pDel == pHead){ printf("不能删除头结点\n"); return; } if (pDel->pNext != NULL){ pDel->data = pDel->pNext->data; pTar = pDel->pNext; pDel->pNext = pTar->pNext; } else { while(pTemp->pNext != pDel){ pTemp = pTemp->pNext; } pTar = pTemp->pNext; pTemp->pNext = pTar->pNext; } free(pTar); }
5、求链表倒数第k个结点
问:求单链表的倒数第k个结点(尾结点是倒数第一个结点)
答:两个指针p1和p2,p1,p2指向首结点,再将p1向后移动k步,将p1和p2同时向后移,移动到p1为最后一个结点时p2所在位置就是倒数第k个结点。
代码:
NODE *ListNode(NODE *pHead, int k) { int i = 0; NODE *p1 = pHead, *p2 = pHead->pNext; if (k < 0) return NULL; while(p1 != NULL && i < k){ p1 = p1->pNext; i++; } if (p1 != NULL){ while(p1->pNext != NULL){ p1 = p1->pNext; p2 = p2->pNext; } return p2; } else{ return NULL; } }
相关文章推荐
- 链表中一些有趣的小题目总结
- 关于Uri的java.lang.SecurityException: Permission Denial错误、(Android权限Uri.parse的详细资料)
- 重写与重载的区别?重载的方法是否可以改变返回值的类型?
- c++上机作业求两点间距离
- 4.ServletContext的getLastModified方法阻止页面刷新每次都访问服务器
- get与post浅谈
- 简单了解面向对象
- Android获取缓存大小和清除缓存功能
- 蓝桥杯记忆
- 198. House Robber
- MoKee OpenSource项目介绍及开发流程
- struts2中ognl表达式%$#在jsp页面的使用总结以及<s:a title=%{title}>的作用
- Xen启动过程分析(还是分享过来吧,找了好长时间)
- Spring Bean的生命周期管理方法
- 79. Word Search
- hadoop生态系统学习之路(三)java实现上传文件(本地或ftp)至hdfs
- 快速排序算法
- POJ 1064 切绳子 二分搜索求一个可行解
- ES6学习小计
- 拉格朗日乘子法(编辑中)