题目三:
http://topic.youkuaiyun.com/u/20071005/22/73AD4AFD-35B8-4864-AB89-DF45CECED7D6.html
简述:n个空间,存放a到a+n-1的数,位置随机且数字不重,a为正且未知.
现在第一个空间的数被误设置为-1.
说明:已经知道被修改的数不是最小的.
例子:n=6, a=2,原始的串为5, 3, 7, 6, 2, 4.现在被别人修改为-1, 3, 7, 6, 2, 4.
现在希望找到5.
限制:n不超过1M,现在希望找出这个数,并且实现尽量快.
要求:完成函数(实现尽可能高效)
unsigned int find_lost(const int* source, const length)
source为数组起址,length为长度.
给出思路(文字描述),完成代码,并且分析你算法的时间复杂度.
Answer1:(排序太耗时间)
抛砖引玉!!!首先排序,然后从第二个元素开始遍历。第i个元素值=第i+1个元素值-1,不满足这个条件,即:得到被修改的值为: 第i各元素值+1。时间复杂度为o(n)。那么因为要排序,所以时间为O(nlogn)。
Answer2:
思路:
此题关键是hash函数H(X)的设计,为了减少数组遍历次数,可把数组看成环形,
设H(X):
H(a[1])=1,
H(x)=(x-a[1]+1+n)%n x <>a[1]
代码如下,复杂度为遍历2次:
#include <iostream.h>
#include <string.h>
#include <stdlib.h>
#define H(x,a1,n) (x-a1+1+n)%n
unsigned int find_lost(const int* source, const length) {
int h;
int i;
int ret=-1;
int *a=(int *)malloc(length*sizeof(int));
for(i=0;i <length;i++)
a[i]=0; // 存放hash值
a[1]=*(source+1); // 存放hash值
// H(x)=(x-a[1]+1+n)%n x <>a[1]
for(i=2;i <length;i++) {
h=H(*(source+i),*(source+1),length);
a[h]=*(source+i);
}
for(i=0;i <length;i++) {
if (a[i]==0)
break;
}
free(a);
return a[(i-1+length)%length]+1;
}
void main() {
int a[]={-1, 33, 32, 35, 31, 34};
cout < <find_lost(a,6) < <endl;
system("PAUSE");
}
Answer3:
由题目可知数组里的数字是连续不重复的,所以前N项和很容易求得。
遍历整个数组(从第二个开始,-1不算),求出数组的和total,顺便求出最小值min。结果就是(min+min+length-1)*length/2-total.前N项和减去前N-1项和就是要找的那一项。
最小值没有被改变保证了找到的最小值一定是正确的。如果数值很大可以采用64位数o(∩_∩)o。时间O(n),空间O(1).
7楼的,一个64位数存放1M的32位整数和绰绰有余。。。。。。
题目四:
http://topic.youkuaiyun.com/t/20060928/11/5053862.html
1. 任何一个基于“比较”的内部排序的算法,若对6个元素进行排序,则在最坏情况下所需的比较次数至少为____。
A.10 B.11 C.21 D.36
Answer1:
据严蔚敏数据结构,问题等价于给n个不同的砝码和一台天平要称几次能分辨它们的顺序。
含n个记录的序列可能出现的初始状态有n!个,则描述n个记录排序过程的判定树必有n!个叶子节点,若有n个叶子节点,则二叉树的高度至少为log 2 n!,(2为底)+ 1,也即是说必然存在一条长为log 2 n!的路径,求出来n为10
Answer2:
http://topic.youkuaiyun.com/u/20090516/21/437e6adb-fffd-4fe3-b900-a3f20f1063da.html
任何一个基于“比较”的内部排序的算法,若对5个元素进行排序,则在最坏情况下所需的比较次数至少为(71)。
(71)A.7
B.8
C.21
D.120
答案:(71)A
解析:对于5个记录的集合任何一个基于“比较”的内部排序的算法的判定树的叶子结点数目为5!,此判定树的树高至少为log25!。由5!=120,2^7=128,2^6=64可得6 <log25! <7。因此在最坏情况下所需的比较次数至少为7。
题目五:
http://topic.youkuaiyun.com/u/20071025/15/9258458F-22D2-4C50-85CD-101705978633.html
一个自然数可以分解为若干个自然数相乘,对于指定自然数n,请求出每种分解自然数之和最小的一个。
说明:不考虑1,若是素数,则是它本身。
例子:如6=2*3,或是它本身,则2+3最小。
限制:无
要求:完成函数
unsigned int minsum(unsigned int n),n为输入自然数,返回最小的和。
给出思路分析(文字描述),完成代码,并分析你算法的时间复杂度和空间复杂度。
Answer1:
http://www.cppblog.com/xpcer/archive/2008/09/18/62151.html
一个自然数可以分解为若干个自然数相乘,求出每种分解自然数之和最少的一个。 如12=2*2*3,和为7=2+2+3
分析:如果把用穷举法把所有可能的组合计算出来,那无疑是复杂的。 假设a=b*c。其中b,c>=2。则a>=2*max{b,c}>=a+b。由此可见a因数分解后的和比a小。显然a的完全因数分解之后的和最小。问题就变成了自然数完全因数分解求和。
#include <math.h>
unsigned int minsum(unsigned int n)
{
unsigned int sum = 0;
unsigned int div_idx = 2;
unsigned int sqrt_n=sqrt(n);
while (1)
{
if (div_idx > sqrt_n)
break;
if (n % div_idx ==0)
{
sum += div_idx;
n /= div_idx;
sqrt_n = sqrt(n);
}
else
div_idx++;
}
return sum+n;
}