挑战面试编程:单词翻转、高斯公式、魔方矩阵、黑白球、3n+1
题一:
把一字符串如"I love you."变为"you. love I"。
分析:
这并不是一简单的字符串reverse的操作,在reverse的过程中要保持单词本身的字母顺序。这就要求我们找到单词中间的间隔,显然是空格,或者是标点。单词也并非只是字母,也有可能是数字。
于是我们总结:两个标点或空格之间的内容,我们把它当做一单词。细节还得看代码……
代码:
这是一段简易的代码:
<span style="font-size:18px;">
#include<iostream>
using namespace std;
char* reverseWords(const char *s,char *t)
{
assert(s&&t);
int slen=strlen(s);
int start,end,begin=0; //start指向一个单词的起始位置的前一个,end表示结束位置的后一位
start=end=slen-1;
while(start>=0 && !(isalpha(s[start]))) //从右向左,找第一个字母出现的位置
start--;
while(start>=0)
{
while(start>=0 && isalnum(s[start]))
start--;
//此时start的位置要么是空格,要么就是标点
memcpy(t+begin,s+start+1,end-start);
//以下的调整需画图理解
begin+=end-start;
end=start;
start--;
}
*(t+begin)='\0';
return t;
}
int main()
{
char *s="I love you.";
cout<<"原字符串"<<endl;
cout<<s<<endl;
//构建一新的字符串存储变换后的
char *t=new char[strlen(s)+1]; //多一个位置存放'\0'
reverseWords(s,t);
cout<<"翻转……"<<endl;
cout<<t<<endl;
delete []t;
return 0;
}</span></span>
运行实例:
说它简易,是因为它还不能处理诸如:句子中有括号()、有引号“”、有分号:等等的类型,如果考率这么多情况,
代码的逻辑判断就会异常复杂,希望后续完善它。
题二:
高斯在上小学时发明了等差数列求和公式:1+2+..+100=5050。现在问题在于给你一个正整数n,问你他可以表示为多少种连续正整数之和?(自身也算)。(取自csdn高校俱乐部线上编程挑战赛)
很简单直接给代码:
<span style="font-size:18px;">
#include<stdio.h>
void print(int start,int end,int n) //负责打印
{
for(int i=start; i<end; i++)
printf("%d+",i);
printf("%d=%d\n",end,n);
}
int main()
{
int n;
printf("输入给定的正整数:");
scanf("%d",&n);
while(n<=0)
{
printf("输入数据有问题!,请重新输入:");
scanf("%d",&n);
}
int count=1; //代表种类,至少自身可以,所以赋初值1
int start=1;
int end=1;
int sum=start;
while(start<=n/2)
{
while(sum<n)
{
end++;
sum+=end;
if(sum==n)
{
count++;
print(start,end,n);
}
if(sum>n)
break;
}
start++;
end=start;
sum=start;
}
printf("%d=%d\n",n,n);
printf("一共有%d种\n",count);
return 0;
}</span></span>
这种代码只能算是解决了问题,但效率很低,有更好的解法吗?
题三:
打印魔方矩阵:如三阶的:
8 1 6
3 5 7
4 9 2
规律是:
- 将“1”放在第一行中间一列;
- 从“2”开始直到n×n为止各数依次按下列规则存放:每一个数存放的行比前一个数的行数减1,列数加1;
- 如果上一个数的行数为1,则下一个数的行数为 n(指最下一行);
- 当一个数的列数为 n,下一个数的列数应为1,行数减1;
- 如果按上面规则确定的位置已有数,或上一个数是第 1行第 n列时, 则把下一个数放在上一个数的下面。
看到了其他人的解法,不过觉得太罗嗦,我的代码:
<span style="font-family:Courier New;">
<span style="font-size:18px;">
#include<iomanip>
#include<iostream>
using namespace std;
int main()
{
int i,j;
int n;
cout<<"输入方阵阶数(奇数):";
cin>>n;
while(n<=0||n%2==0)
{
cout<<"输入的阶数有问题!,请重新输入:";
cin>>n;
}
int **a=new int*[n];
for(i=0; i<n; i++)
a[i]=new int[n];
for(i=0; i<n; i++) //初始化
for(j=0; j<n; j++)
a[i][j]=0;
int k=1;
i=0;
j=n/2;
int a1,a2;
a[i][j]=k++;
while(k<n*n+1)
{
//记录旧值
a1=i;
a2=j;
//按规律二,变化新值
i=(i-1+n)%n;
j=(j+1)%n;
//对于规律五的判断
if(i==n-1 && j==0)
{
i=1;
j=n-1;
}
//还是规律五的判断
if(a[i][j])
{
i=a1+1;
j=a2;
}
//经过以上的判断,确定赋值位置
a[i][j]=k++;
}
cout.setf(ios::left);
for(i=0; i<n; i++)
{
for(j=0; j<n; j++)
cout<<setw(4)<<a[i][j];;
cout<<endl;
}
delete[]a;
system("pause");
return 0;
}</span>
</span>
运行:
题四 黑白球
一个袋子里有两种颜色的球,黑色和白色,你每次从中取出两个球,如果是同色的,则在袋子里放一个白球,否则放回一个黑球。 最后袋子里剩下一个球,你能最后判断球的颜色么?(取自csdn高校俱乐部线上编程挑战赛)
分析:
题目其实不难,代码很简单,不过得分析清楚。我们得明白以下几点:
1.取出的球组合只有三种:
- 双白
- 双黑
- 一白一黑
- 双白、双黑:放回白球
- 一白一黑:放回黑球
- 双白、一黑一白:袋中黑球不变,白球减一 (类一)
- 双黑:袋中黑球减二,白球加一 (类二)
<span style="font-family:Courier New;">
<span style="font-size:18px;">
#include<iostream>
using namespace std;
int main()
{
int w, b;
while (cin >> w >> b)
{
if (b % 2 == 0)
cout << "WHITE" << endl;
else
cout << "BLACK" << endl;
}
return 0;
}</span>
</span>
题五 3n+1
对任何一个自然数n,如果它是偶数,那么把它砍掉一半;如果它是奇数,那么把(3n+1)砍掉一半。这样一直反复砍下去,最后一定在某一步得到n=1。给定的任一不超过1000的正整数n,简单地数一下,需要多少步(砍几下)才能得到n=1?(取自csdn高校俱乐部线上编程挑战赛)
分析:
题目其实很简单,但很多人没看懂,我们得明白每一步操作后的新值作为n。可得代码:
<span style="font-family:Courier New;">
<span style="font-size:18px;">
#include<iostream>
using namespace std;
int fun(int n)
{
int count = 0;
while (n != 1)
{
if (n % 2 == 0)
n /= 2;
else
n = (3 * n + 1) / 2;
count++;
}
return count;
}
int main()
{
int n;
while (cin >> n)
cout << fun(n) << endl;
return 0;
}
</span></span>
所有内容的目录