100个小问题_每日一题_第1题
来源:互联网 发布:zoz软件下载吧 编辑:程序博客网 时间:2024/05/22 05:38
problem 1:
假设一个节点集合,无空指针(每个指针都指向自身或是指向集合中的其他节点)。
1:编写一个代码断,已知某节点的指针,求从该节点开始,沿着链接最终可以到达不同的节点数,要求不修改任何的节点,使用的额外内存空间不多于某个常量。
2:在1的条件下,编写一个函数,沿着两个已知的链接(意思就是知道两个节点指针,分别沿着各自链接下去),判断他们是否最后终止于同一个循环。
值得一提的是:本题最初来源于algorithms in c,是书中的一个课外思考题,后来被一些公司改成了笔试或是面试题。
以下是对于problem1,我个人写出个一个解答吧,算是抛砖引玉。。。
第一问的求解:
首先,可以简单证明从集合中的任意一个已知节点开始,沿着链接最终可以形成一个环。
证明如下(利用反证法):假设从某个节点k开始,沿着链接不能形成一个循环,那么这个链接必然是无穷的(因为没有空指针),然而节点集合却是有限的。矛盾,故必然会形成环。
然后找到环路入口点,设置两个指针(fast, slow),初始值都指给定的开始的节点,slow每次前进一步,fast每次前进二步,经过若干步后,则fast必定先进入环,而slow后进入环。
入环后,两个指针必定相遇。而当fast若与slow相遇时,slow肯定没有走遍历完环路,而fast已经在环内循环了n圈(1<=n)。
简单证明如下:
当slow与fast都进入环后,可以将这个问题比喻为2个人就是在操场当中跑步,速度快的会把速度慢的扣圈追上。
可以证明,fast追赶上slow的时候,slow一定还没有走完一遍环路,fast也不会跨越slow多圈才追上
我们可以从fast和slow的位置差距来证明,fast一定会赶上slow但是不会跳过slow的
因为fast每次走2步,而slow走一步,所以他们之间的差距是一步一步的缩小(把slow看作是在fast前面,让fast去追它),x,x-1 ………… 4,3,2,1,0 到0的时候就fast就追上slow了。
接下来是如何找到这个环路的入口呢?
解法如下: 先让fast按照每次2步,slow每次1步的方式走,直到fast和slow重合。
接下来,让fast回到初始的节点,重新走,每次步长不是走2了,而是走1,那么当fast和slow再次相遇的时候,就是环路的入口了。
这点可以证明如下:
在fast和slow第一次相遇的时候,假定slow走了n步骤,环路的入口是在p步的时候经过的,那么有
slow走的路径: p+c = n; c为slow和fast相交点距离环路入口的距离。
fast走的路径: p+c+k*L = 2*n; L为环路的周长,k是整数。
显然,如果从p+c点开始,slow再走n步骤的话,还可以回到p+c这个点
同时fast从头开始走的话,经过n步,也会达到p+c这点
显然在这个步骤当中fast和slow只有前p步骤走的路径不同,而后面c步是必须相同的。
所以当fast和slow再次重合的时候,必然是在节点的环路入口点上,此时就求得了p值,再加上环的长度L就可以求得所能走过的最多不同节点数目。
程序如下:
int search_most_diffrent_nodes(list *start){
list *slow = start , * fast = start;
int num = 0;
while (1) {
slow = slow -> next;
fast = fast -> next -> next;
if ( slow == fast ) break ; //第一次相遇
}
for(fast = start; fast != slow; fast = fast -> next, slow = slow -> next)
num++; //求得p,即起点到环路入口的节点数目
do {
slow = slow -> next;
num++; //加上环路的长度,即环路的节点数目
} while(slow != fast)
return num;
}
时间复杂度为O(n),空间复杂度为O(1).
第二问2求解:
先根据问题的思想找到两个链的各自第一次相遇点,即保证两个链都已经进入环内,然后选择其中的任意一个环,遍历该环,若是两环相交,那么必须在遍历过程中经过另外一个环的第一次相遇点。
否则不相交,即两个链接不能最后终止于同一个循环。
代码如下:
bool is_intersect(list *st1, list *st2){
list *slow1 = st1, fast1 = st1;
list *slow2 = st2, fast2 = st2;
do {
slow1 = slow1 -> next;
fast1 = fast1 -> next -> next;
} while ( slow1 != fast1 )
do {
slow2 = slow2 -> next;
fast2 = fast2 -> next -> next;
} while ( slow2 != fast2 )
if(slow1 = slow2) return true;
for( slow1 = slow1 -> next; slow1 != fast1; slow1 = slow1 -> next) if(slow1 == slow2) return true;
return false;
}
时间复杂度为O(n),空间复杂度为O(1).
- 100个小问题_每日一题_第1题
- 100个小问题_每日一题_第2题
- 100个小问题_每日一题_第3题
- 100个小问题_每日一题_第4题
- 编程小题^_^
- 每日一题(6) - 链表中倒数第 k 个结点
- 【2013-1-24】算法每日一题:查找链表中倒数第k个结点
- 面试_技术问题_典型题
- 每日一题:过桥问题
- 每日一题——寻找倒数第k个节点
- 每日一题之查找单链表的第K个节点
- 笔试题_红包问题
- 每日一题-1
- 《汇编语言》_第1章_基础知识
- 每日一题1:查找前k个最小值
- 写个自己看的博客_每日随笔_unity_particleSystem
- C++算法题_第一周
- 第一周编程题_分数
- Java api 全集
- ASP.NET利用Global.asax统计在线人数
- 拖拽
- 拖拽
- PS(留学动机)的妙用——扭转你的劣势
- 100个小问题_每日一题_第1题
- 详细讲述CV的创作与包装
- 用VC,VB进行图像数据(二进制大对象)存储数据库的方法
- jquery之jsonp跨域
- ms sql 多行記錄合併成一個字符串或多字段(行轉列)
- 最近对 UCanCode 公司的 XD++软件包产生了浓厚的兴趣
- 2010年会计从业资格考试相关内容汇总(全国各地)
- 求1+2+...+n--总结
- J2EE的13种核心技术简介