面试算法题
来源:互联网 发布:数据建模是什么 编辑:程序博客网 时间:2024/05/01 15:28
转自http://www.cnblogs.com/zhenjing/archive/2010/10/18/1854020.html
Problem 1 : Is it a loop ? (判断链表是否有环?)
Assume that wehave a head pointer to a link-list. Also assumethat we know the list is single-linked. Can you come up an algorithm to checkwhether this link list includes a loop by using O(n) time and O(1) space wheren is the length of the list? Furthermore, can you do so with O(n) time and onlyone register?
方法:使用两个指针,从头开始,一个一次前进一个节点,一个前进2个节点,则最多2N,后两个指针可以重合;如果无环,则正常停止。
同样的,可以找到链表的中间节点。同上。
Problem 2:设计一个复杂度为n的算法找到链表倒数第k个元素。最后一个元素假定是倒数第1个。
提示:双指针查找(第一个指针先走k-1步,还剩下n-1-(k-1) = n-k步,所以当第一个指针走到链表最后一个节点时,第二个指针正好指向n-k结点,即倒数第k个元素)
Problem 3:用最简单的方法判断一个LONG整形的数A是2^n(2的n次方)
提示:x&(x-1)
Problem 4:两个烧杯,一个放糖一个放盐,用勺子舀一勺糖到盐,搅拌均匀,然后舀一勺混合物会放糖的烧杯,问你两个烧杯哪个杂质多?
提示:相同。假设杂质不等,那么将杂质放回原杯中,则杯中物体重量必变化,不合理。
Problem 5:给你a、b两个文件,各存放50亿条url,每条url各占用64字节,内存限制是4G,让你找出a、b文件共同的url。
50亿条,相当于5G*64 = 320GB,内存不够。
先用hash(url) * 1024 ,将a文件分到a0, a1, ... , a1023共1024个小文件中,对b也是一样。这样相同的url存在于下标相同的小文件中,对a的每一个小文件,用hash_map统计出现的url,再遍历B对应的小文件,看是否有共同的url。
Problem 6:给你一个单词a,如果通过交换单词中字母的顺序可以得到另外的单词b,那么定义b是a的兄弟单词。现在给你一个字典,用户输入一个单词,让你根据字典找出这个单词有多少个兄弟单词。
提示:将每个的单词按照字母排序,则兄弟单词拥有一致的字母排序(作为单词签名)。使用单词签名来查找兄弟单词。
Problem 7:五桶球,一桶不正常,不知道球的重量和轻重关系,用天平称一次找出那桶不正常的球。
Problem 8:给两个烧杯,容积分别是m和n升(m!=n),还有用不完的水,用这两个烧杯能量出什么容积的水?
m, n, m+n, m-n以及线性叠加的组合 (即mx + ny,x,y 为整数,可正可负)
Problem 9:写出一个算法,对给定的n个数的序列,返回序列中的最大和最小的数。
(遍历:需比较2*n-2次)
Problem 10:你能设计出一个算法,只需要执行1.5n次比较就能找到序列中最大和最小的数吗?能否再少?
提示:先通过两两比较,将大的元素跟最大值比较,小的元素跟最小值比较,一次需比较三次。
若n为奇数,比较次数为 3*n/2, 若n为偶数,比较次数为 3*(n-2)/2 + 1 = 3*n/2 -2。
void FindMaxMin(vector<int> v, int& maxV, int& minV)
{
int n = v.size();
if(n & 1)
maxV = minV = v[0];
else
{
if(v[0] < v[1])
{
maxV = v[1];
minV = v[0];
}
else
{
maxV = v[0];
minV = v[1];
}
}
for(int i = 2; i < n-1; i += 2)
{
int tempMax, tempMin;
if(v[i] > v[i+1])
{
tempMax = v[i];
tempMin = v[i+1];
}
else
{
tempMax = v[i+1];
tempMin = v[i];
}
if(tempMax > maxV)
maxV = tempMax;
if(tempMin < minV)
minV = tempMin;
}
}
Problem 11:给你一个由n-1个整数组成的未排序的序列,其元素都是1到n中的不同的整数。请写出一个寻找序列中缺失整数的线性时间算法。
(1)求1到n的累加和,减去n-1个整数的累加和。若n很大,可能会溢出。
(2)异或的方法。先将1到n异或,再将这个结果和n-1个整数异或。相当于除了一个元素,其他元素都出现了两次,相同的数异或结果为0,最后剩下的就是缺失的数。
Problem 12:void strton(const char* src, const char*token) 假设src是一长串字符,token存有若干分隔符,只要src的字符是token中的任何一个,就进行分割,最终将src按照token分割成若干单词。找出一种O(n)算法?
提示:查表的方法,将所有的字符串存储在长度为256的数组中,并将作为分隔符的字符位置1,这样即可用常数时间判断字符是否为分隔符,通过n次扫描,将src分割成单词。(在strtok中是通过在分隔符处添加'\0'实现分割的)
Problem 13:一个排好序的数组A,长度为n,现在将数组A从位置m(m<n,m未知)分开,并将两部分互换位置,假设新数组记为B,找到时间复杂度为O(lgn)的算法查找给定的数x是否存在数组B中?
提示:采用二分查找。核心思想就是确定所查找数所在的范围。通过比较3个数(头,尾,中间)和所查找数之间的关系,可以确定下次查找的范围。
Problem 14:一个排好序的数组A,长度为n,现在将数组A从位置m(m<n,m已知)分开,并将两部分互换位置,设计一个O(n)的算法实现这样的倒置,只允许使用一个额外空间。(循环移位的效率不高)
提示:(A’B’)’ =BA (单词逆序问题)
Problem 15:给出Vector的一个更好实现。(STL的vector内存的倍增的,但是每次倍增需要拷贝已存元素,平均每个元素需要拷贝一次,效率不高)
提示:可使用2^n的固定长度作为每次分配的最小单位,并有序的记录每个块的首地址。这种结构同样可以实现线性查找,并且拷贝代价很低(仅有指针)(是不是相当于deque?)
Problem 16:给出已排序数组A,B,长度分别为n,m,请找出一个时间复杂度为(lgn)的算法,找到排在第k位置的数。
提示:二分查找。
Problem 17:给出任意数组A,B,长度分别为n,m,请找出一个时间复杂度为(lgn)的算法,找到排在第k位置的数。
??
Problem 18:假设数组A有n个元素,元素取值范围是1~n,判定数组是否存在重复元素?要求复杂度为O(n)。
法1:使用n的数组,记录元素,存在记为1,两次出现1,即重复。
法2:交换的方法,使得在数组中下标为i的元素值为i。遍历数组,若下标为i的元素值不为i,则跟下标为a[i]的元素互换。(若互换的两个元素值相同,说明有重复的元素)
bool duplicate(
int
numbers[],
int
length,
int
* duplication)
{
if
(numbers == NULL || length <=
0
)
return
false
;
for
(
int
i =
0
; i < length; i++)
{
while
(a[i] != i)
{
if
(a[i] == a[a[i]])
{
*duplication = a[i];
return
true
;
}
swap(a[i], a[a[i]]);
}
}
return
false
;
}
Problem 19:给定排好序的数组A,大小为n,现给定数X,判断A中是否存在两数之和等于X。给出一个O(n)的算法。
提示:双指针法,从两边向中间遍历
Problem 20:给定排好序的数组A,大小为n,请给出一个O(n)的算法,删除重复元素,且不能使用额外空间。
提示,既然有重复,必有冗余空间。将元素放入数组的前面,并记录下次可放位置,不断向后扫描即可。
Problem 21:给定两个排好序的数组A,B,大小分别为n,m。给出一个高效算法查找A中的哪些元素存在B数组中。
法1: 将小数组的元素作为需查找的对象,在大数组中执行二分查找,O(mlogn)
法2:双指针,分别指向两个数组,依次向前推进。推进的规则是比较两个数组中的数字,小的那个数组的下标向前推进一步。
vector<int> FindElement(vector<int> a, vector<int> b)
{
int len1 = a.size();
int len2 = b.size();
vector<int> ret;
int i = 0, j = 0;
while(i < a.size() && j < b.size())
{
if(a[i] < a[j])
i++;
else if(a[i] == a[j])
{
ret.push_back(a[i]);
i++;
}
else
j++;
}
return ret;
}
Problem 22:问:有1000桶酒,其中1桶有毒。而一旦吃了,毒性会在1周后发作。现在我们用小老鼠做实验,要在1周内找出那桶毒酒,问最少需要多少老鼠。
答案:10只。将酒编号为1~1000 将老鼠分别编号为1 2 4 8 16 32 64 128 256 512 喂酒时 让酒的编号等于老鼠编号的加和如:17号酒喂给1号和16号老鼠 76号酒喂给4号、8号和64号老鼠 七天后将死掉的老鼠编号加起来 得到的编号就是有毒的那桶酒 因为2的10次方等于1024 所以10只老鼠最多可以测1024桶酒
证明如下:使用二进制表示:01, 10, 100, 1000, … , 1,000,000,000。对于任何一个小于1024的数,均可以采用前面的唯一一组二进制数来表示。故成立。
Problem 23:设计一组最少个数砝码,使得天平能够称量1~1000的重量。(十进制转为2进制)
如果砝码只能放单边,1,2 ,4 , 512最好。(只能单加)(10个砝码)
如果允许砝码双边放,1, 3, 9, 27…. 最好。(可加可减)已知1,3,如何计算下一个数。现可称重量1,2,3,4。设下个数为x,可称重量为, x-4, x-3, x-2, x-1, x, x+1, x+2, x+3, x+4。为使砝码最好,所称重量应该不重复(浪费)。故x=9。同理,可得后面。(7个砝码)
图形算法题
Problem 24:如何判断一个点是否在一个多边形内?
提示:对多边形进行分割,成为一个个三角形,判断点是否在三角形内。
一个非常有用的解析几何结论:如果P2(x1,y1),P2(x2,y2), P3(x3,y3)是平面上的3个点,那么三角形P1P2P3的面积等于下面绝对值的二分之一:
| x1 y1 1 |
| x2 y2 1 | = x1y2 + x3y1 + x2y3 –x3y2 – x2y1 – x1y3
| x3 y3 1 |
当且仅当点P3位于直线P1P2(有向直线P1->P2)的右侧时,该表达式的符号为正。这个公式可以在固定的时间内,检查一个点位于两点确定直线的哪侧,以及点到直线的距离(面积=底*高/2)。
这个结论:可以用来判断点是否在三角形内。
法1:判断点和三角形三边所行程的3个三角形的面积之和是否等于原来三角形的面积。(用了三次上面的公式)。
法2:判断是否都在三条边的同一边,相同则满足,否则不在三角形内。
Problem 25:给出两个n为向量与0点形成角的角平分线。
提示:对两条边进行归一化,得到长度为1的两点,取两个的中点即可。
- 面试算法题1
- 面试算法题
- 面试算法题2
- 面试算法题3
- 面试算法题4
- 面试算法题5
- 面试算法题6
- 转:面试算法题
- 面试算法题!
- 面试算法题1
- 面试算法题
- 面试算法题
- 微软面试算法题
- java面试算法题
- 数组面试算法题
- 面试算法题整理
- 某个面试算法题
- 面试算法题
- 协方差的意义
- Linux常用命令——笔记
- bc 29 GTY's birthday gift(矩阵快速幂)
- rpm安装软件
- 1065:生理周期
- 面试算法题
- Thinking in java 之:容器介绍
- spray-routing中的Exception Handling
- POJ 1284:Primitive Roots 求原根的数量
- 详解ORACLE数据库的分区表
- Linux重启中init6与reboot的区别
- Android动画-TweenAnimation
- 试验-探索自动化病毒样本动态行为分析系统中的漏洞
- 微软编译器vs 编译器(cl.exe)和连接器参数