新浪笔试题
1如何判断单链表是否有环?
给定一个单链表,只给出头指针h:
1、如何判断是否存在环?
2、如何知道环的长度?
3、如何找出环的连接点在哪里?
4、带环链表的长度是多少?
解法:
1、对于问题1,使用追赶的方法,设定两个指针slow、fast,从头指针开始,每次分别前进1步、2步。如存在环,则两者相遇;如不存在环,fast遇到NULL退出。
2、对于问题2,记录下问题1的碰撞点p,slow、fast从该点开始,再次碰撞所走过的操作数就是环的长度s。
3、问题3:有定理:碰撞点p到连接点的距离=头指针到连接点的距离,因此,分别从碰撞点、头指针开始走,相遇的那个点就是连接点。
该定理的证明可参考:http://fayaa.com/tiku/view/7/
4、问题3中已经求出连接点距离头指针的长度,加上问题2中求出的环的长度,二者之和就是带环单链表的长度
判断是否存在环的程序:
1. bool IsExitsLoop(slist *head)
2. {
3. slist *slow = head, *fast = head;
4.
5. while ( fast && fast->next )
6. {
7. slow = slow->next;
8. fast = fast->next->next;
9. if ( slow == fast ) break;
10. }
11.
12. return !(fast == NULL || fast->next == NULL);
寻找环连接点(入口点)的程序:
1. slist* FindLoopPort(slist *head)
2. {
3. slist *slow = head, *fast = head;
4.
5. while ( fast && fast->next )
6. {
7. slow = slow->next;
8. fast = fast->next->next;
9. if ( slow == fast ) break;
10. }
11.
12. if (fast == NULL || fast->next == NULL)
13. return NULL;
14.
15. slow = head;
16. while (slow != fast)
17. {
18. slow = slow->next;
19. fast = fast->next;
20. }
21.
22. return slow;
23. }
2.10层楼,可以一步走1层或2层,求有多少种走法?
到达第一层: 1 种
到达第二层: 2种
到达第三层:1 + 2种 =3
到达第四层:=到达第二层的方法数 + 到达第三层的方法数 = 2 + 3 = 5
到达第五层:=到底第三层的方法数 + 到达第四层的方法数 = 3 + 5 = 8
到达第六层:5+8 = 13
到达第七层:8+13 = 21
余此类推
得到如下一个数列
1 2 3 5 8 13 21 34 55 ……
它的特点是 从第三项开始 每项是之前2项的和,即
a<n> = a<n-1> + a<n-2>
这就是著名的 裴波那契数列,参见http://zhidao.baidu.com/question/8948025.html?si=3
对于本题目,其通项公式演化为,
F(n) = {[(1+√5)/2]^(n+1) -[(1-√5)/2]^(n+1)}/√5
但以 n=15 代入,计算仍然麻烦。
还不如直接推算。
1 2 3 5 8
13 21 34 55 89
144 233 377 610 987
最终结果 987
#include <iostream>
using
namespace
std;
int
CountMethod(
int
n)
{
int
i, j, k;
int
count = 0;
for
(i = 0; i <= n/3; i++)
for
(j = 0; j <= n/2; j++)
for
(k = 0; k <= n; k++)
if
(3*i + 2*j + k == n)
count++;
return
count;
}
int
main()
{
int
count = CountMethod(100);
cout << count << endl;
return
0;
}
思路跟百钱买百鸡一样吧
#include<stdio.h>
double
fun(
int
n) {
if
(n == 1)
return
1;
if
(n == 2)
return
2;
if
(n == 3)
return
4;
else
return
fun(n - 1) + fun(n - 2) + fun(n - 3);
}
int
main() {
double
a[100];
a[0] = 1;
a[1] = 2;
a[2] = 4;
for
(
int
x = 3; x < 100; x++) {
a[x] = a[x - 1] + a[x - 2] + a[x - 3];
}
for
(
int
i = 0; i < 100; i++) {
printf
(
"Level Amount--->%d\t"
, (i + 1));
//printf("Sol:1--->%e\t", fun(i + 1));
printf
(
"Sol:2--->%e\n"
, a[i]);
}
return
0;
}
3.2000个各含有100个数字的数组,求前1000个数字的降序排序?
4.10G的文件,每行不同长度的语句,500G内存,如何对文件排序?
在许多实际应用系统中,经常遇到要对数据文件中的记录进行排序处理。由于文件中的记录很多、信息量庞大,整个文件所占据的存储单元远远超过一台计算机的内存容量。因此,无法把整个文件输入内存中进行排序。于是,就有必要研究适合于处理大型数据文件的排序技术。通常,这种排序往往需要借助于具有更大容量的外存设备才能完成。相对于仅用内存进行排序(又称为内排序)而言,这种排序方法就叫做外排序。在实际应用中,由于使用的外存设备不同,通常又可以分为磁盘文件排序和磁带文件排序两大类。磁带排序和磁盘排序的基本步骤相类似,它们的主要不同之处在于初始归并段在外存贮介质中的分布方式,磁盘是直接存取设备,磁带是顺序取设备。
外部排序基本上由两个相对独立的阶段组成。首先,按可用内存大小,将外存上含n个记录的文件分成若干长度为h的子文件,依次读入内存并利用有效的内部排序方法对它们进行排序,并将排序后得到的有序子文件重新写入外存,通常称这些有序子文件为归并段或顺串;然后,对这些归并段进行逐趟归并,使归并段(有序的子文件)逐渐由小到大,直至得到整个有序文件为止。
最简单的归并方法类似于内部排序中的二路归并算法。二路归并排序的方法,其基本思想就是:先把具有n个记录的文件看作是由n个长度为1的顺串构成的。在此基础上进行一趟又一趟的归并。一趟归并,是把文件中每一对长度为 h的顺串合并成一个长度为2h的顺串;其结果将使文件中顺串的长度增加一倍而使顺串的数量减少一半。经过若干趟归并之后,当文件中只含有一个长度为n的顺串时,整个文件的排序就完成了。
还有一种常用的快速的多路归并法:多路归并排序。多路归并排序是二路归并排序的推广,它可以减少归并趟数,m 路归并排序的基本方法是:开始,把若干长度为K的初始顺串尽量均匀地分布到m个输入文件f1...,fm上。然后反复从f1,...,fm各读一个顺串,归并成长度为mk的顺串,轮流地写到输出文件g1,...,gm上。下一趟从g1,...,gm归并到f1,...,fm.一趟又趟地反复进行,直到排序结束。在进行多路归并时,需要从K个记录中选关键字最小的记录,为了不增加内部归并时需进行关键字比较的次数,在具体实现时,通常不用选择排序的方法,而用"败者树"来实现。又从外部的趟数[logkm]可见,若减少m也可减少外排的时间,对待排序的初始记录进行"置换选择排序"可以得到平均长度为2h的有序子序列。这些内容在此不予讨论,有兴趣者可参阅有关参考书。
小 结
本章共介绍了五种内排序算法,它们是:直接插入排序,快速排序、直接选择排序、堆排序和归并排序。另外辅助性地介绍了冒泡排序和树形选择排序。重点在前五种排序算法。
一般说来,比较简单的排序(如直接插入、直接选择、冒泡排序等)所需要的时间代价大,为O(n2),但在某些特殊情况下可能取得很好的效果。例如,当初始序列已排序或接近排序的情况下,直接插入排序和冒泡排序的时间代价可能达到O(n)量级。另外,在待排序序列中记录数较小时,多采用算法简单的排序。当记录数较大,并且没有规律时,可采用快速排序、堆排序、直接选择排序是不稳定的排序,其它排序都是稳定的。
外排序的基本方法是归并。归并的思想本来是简单的;但为了减少访问外存的次数,减少外设的台数和输入输出缓冲区的个数,并使主机和外设尽量并行工作,这就给外排序的讨论增加了难度。