最近为了准备找工作,刷了July大神整理的微软100题系列,中间有两道题目在原博主文中并没有给出很好地解决方案,在此文中给出个人的解法,希望抛砖引玉,请求大神给予指导。
第一道是30题,原题描述如下:
题目:输入一个整数 n,求从 1到 n这 n个整数的十进制表示中 1出现的次数。例如输入 12 ,从 1到 12 这些整数中包含 1 的数字有 1,10 ,11和 12 ,1一共出现了 5次。
分析:这是一道广为流传的 google面试题。
这道题目很明显是可以用递归实现的。考虑三个数字:
321,111。
1.对于321,首先考虑个位数:个位数大于等于1,在0~9中1只能出现1次,因此这里各位出现1个1;接着考虑十位,十位大于1,可以得知在0~20中只能是0~9中出现1次、10~19中出现11次,也就是一共20次,那么考虑当十位数不是2,而是3,或者4时,增加的也仅仅是1个或者两个1.也就是说在此情况下(注意此时仅考虑当前位,不考虑其他位,也就是整十整百之类的数)1出现的次数可以总结为countN(n,k)=10^(k-1)+n*countN(10,k-1);其中n是当前位的值,k则是其倍率(十位时k=2,百位时k=3).同样的道理可以用在百位上,将所有位出现的加在一起即可得到最终结果。
2.对于111,个位采用同样的方式进行判断,但是十位时我们发现这一位等于1,那么我们首先需要将低于当前位的值记录下,因为最后的结果中需要加上它,以此为例,我们需要记住最终结果需要加上1,同时由于即便当前位的低位全部为0我们也需要加1,也就是说最终结果的组成部分需要+2,(10,11中各自由于十位的1而加1,注意此时我们仅仅计算当前位的,比当前位低的已经计算完成),然后我们对当前位(在此是1)所代表的值(10)减去1,然后对其递归调用计数函数。在此例中是计算9的计数问题。然后我们将所有结果叠加即可得到最后结果。
我发现数字无非这两种情况,因此总可以递归实现其求解。算法详情见下文。
//30.在从1到n的正数中1出现的次数
#include
int countN(int n,int k){//k为位数,这里的n不能为1,除非为个位数
if (k == 1){
if (n >= 1)
return 1;
else
return 0;
}
if (n > 1){
return (pow(10,(k-1)) + n*countN(10, k - 1));
}
else if (n == 1)
return -1;
else
return 0;
}
int count1(int num){
//判断num的位数
int unit = 0;//位数
int count = 0;//1的个数
int mod = 0;//余数
int tem = num*10;//除以10的结果
while (tem /10 != 0){
tem /= 10;
++unit;
mod = tem % 10;
if (mod != 1||(mod==1&&unit==1)){
int temp = countN(mod, unit);
count += temp;
}
else{
int temp2 = (num % int(pow(10, (unit - 1))) + 1);//当前位为1
temp2 = temp2 + count1(pow(10, (unit - 1))- 1);
count += temp2;
}
}
return count;
}
int main(){
int n = 11;
std::cout << count1(n) << std::endl;
system("pause");
}
第二道题目是32题,原题描述如下:
有两个序列a,b,大小都为n,序列元素的值任意整数,无序;
要求:通过交换a,b中的元素,使[序列a元素的和]与[序列b元素的和]之间的差最小。
例如:
var a=[100,99,98,1,2, 3];
var b=[1, 2, 3, 4,5,40];
据说这一题是微软的面试题。
当我第一次看到这个题目,最简单的思路就是直接合在一起排序,然后逐个抽取数字分配到两个数组中。这当然是大错特错的。奈何本人比较愚笨,只能查看答案。然而答案给出的代码也是不正确的。网上所传的算法我看到的目前有三种,前两种算法可以参照一下原博主July大神的博文http://blog.csdn.net/v_july_v/article/details/6126444,但是可以很负责任地告诉大家这两种方法都是错的,从大神贴出来的答案也是可以很明显看出的。第三种方法链接在此
//32.有两个序列a,b,大小为n,序列元素的值为任意整数,无序;要求通过交换a,b中的元素,使序列a的和与序列b的和之间的差最小。
//writer&idea:JayLeeUSTC
//date:2016.07.22
#include
void swap(int&a,int&b){
int temp = a;
a = b;
b = temp;
}
void QuickSort(int* a,int left,int right){//快速排序
if (left < right){//当left=right的时候说明仅有一个元素
int i = left, j = right, val = a[left];
while (i < j){
while (ival)
--j;
if (i < j)
a[i++] = a[j];
while (i < j&&a[i] < val)
++i;
if (i < j)
a[j--] = a[i];
}
a[i] = val;
QuickSort(a, left, i - 1);
QuickSort(a, i+1, right);
}
}
int sum(int*a, int len){
int temp = 0;
for (int i = 0; i < len; ++i){
temp += a[i];
}
return temp;
}
void Arrange(int a1[],int a2[],int len){
int *a3 = new int[2*len];
for (int i = 0; i < len; ++i){
a3[i] = a1[i];
a3[i + len] = a2[i];
}//合并序列
QuickSort(a3, 0, 2*len-1);//排序
for (int i = 0; i < len; ++i){
a1[i] = a3[i];
a2[i] = a3[i+ len];
}//排序后的拆分序列
bool sign = true;//符号标识符,正数为true,负数为false。
bool ifswap = false;
int prev = sum(a2, len) - sum(a1, len);//存储上一次运算的差值。
while (true){
for (int i = 0; i < len; ++i){
if (sign){//符号为正,第二组序列之和较大
int sumch = prev - 2 * a2[i] + 2 * a1[i];
if (sumch0)//交换当前项后和的差值变小但是未变号
{
swap(a1[i], a2[i]);
prev = sumch;
ifswap = true;
}
else if (sumch < 0 && abs(sumch) < prev)//交换当前项后和的差值变小且变号
{
swap(a1[i], a2[i]);
ifswap = true;
prev = abs(sumch);
sign = false;
}
else if (sumch == 0||sumch==prev)//找到最佳值或交换对总和无变化
return;
}
else if (!sign){//第一组序列之和较大
int sumch = prev - 2 * a1[i] + 2 * a2[i];
if (sumch0){
swap(a1[i], a2[i]);
ifswap = true;
prev = sumch;
}
else if (sumch < 0 && abs(sumch < prev)){
swap(a1[i], a2[i]);
ifswap = true;
prev = abs(sumch);
sign = true;
}
else if (sumch == 0 || sumch == prev)//找到最佳值或交换对总和无变化
return;
}
}
if (!ifswap)
return;
//重新排序
QuickSort(a1, 0, len - 1);
QuickSort(a2, 0, len - 1);
ifswap = false;
}
}
int main(){
int a1[4] = { 1, 4, 6, 700};
int a2[4] = { 2, 3, 5, 800};
int len=sizeof(a1)/sizeof(a1[0]);
Arrange(a1, a2, len);
for (int i = 0; i < len; ++i)
std::cout << a1[i] << " ";
std::cout << std::endl;
for (int i = 0; i < len; ++i)
std::cout << a2[i] << " ";
std::cout << std::endl;
std::cout <<"The final result is:"<
写在最后:其实自己水平很渣,看到个位大牛的解题思路有时候就像个小孩子一样激动。希望对算法感兴趣的同道中人一起讨论一起学习!