知识点:字符串;排序
描述
给定 n 个字符串,请对 n 个字符串按照字典序排列。
数据范围: 1≤n≤1000 ,字符串长度满足1≤len≤100
输入描述:
输入第一行为一个正整数n(1≤n≤1000),下面n行为n个字符串(字符串长度≤100),字符串中只含有大小写字母。
输出描述:
数据输出n行,输出结果为按照字典序排列的字符串。
示例1
输入:
9
cap
to
cat
card
two
too
up
boat
boot
输出:
boat
boot
cap
card
cat
to
too
two
up
代码:
#include
#include
#include
int main(void)
{
int n=0,i,j;
char temp[100];
scanf("%d", &n);
char words[n][100];
for(i=0;i<n;i++){ /*输入所有字符串*/
scanf("%s", words[i]);
}
for(i=0;i<n-1;i++){ /*冒泡排序*/
for(j=0;j<n-i-1;j++){
if(strcmp(words[j],words[j+1])>0){
strcpy(temp,words[j]);
strcpy(words[j],words[j+1]);
strcpy(words[j+1],temp);
}
}
}
//printf("-----------------------------------------------\r\n");
for(i=0;i<n;i++){ /*输出*/
printf("%s\r\n",words[i]);
}
return 0;
}
---------------------------结果----------------------------------
song@song-virtual-machine:~/C_Program/interview_code$ ./test
5
cap
to
cat
too
boot
boot
cap
cat
to
too
song@song-virtual-machine:~/C_Program/interview_code$
知识点: 字符串;基础数学;栈
描述
给定一个字符串描述的算术表达式,计算出结果值。
输入字符串长度不超过 100 ,合法的字符包括 ”+, -, *, /, (, )” , ”0-9” 。
数据范围:运算过程中和最终结果均满足∣val∣≤2^31-1, 即只进行整型运算,确保输入的表达式合法
输入描述:
输入算术表达式
输出描述:
计算出结果值
示例1
输入:400+5
输出:405
代码:
#include
#include
#include
int pos;
/*检查是否为数字*/
int check(char c)
{
if(c >= '0' && c <= '9'){
return 1;
}
return 0;
}
/*开始计算*/
int compute(char *data)
{
int len = strlen(data);
int num = 0;
int stack[100] = {0};
int top = -1;
char flag = '+';
while(pos < len){
/*进入括号时,就相当于递归一次当前的方法*/
if(data[pos] == '{' || data[pos] == '[' || data[pos] == '('){
pos ++;
num = compute(data);
}
/*当前字符为数字时,则计算当前的数字*/
while(pos < len && check(data[pos])){
num = num * 10 + data[pos] - '0';
pos++;
}
/*开始计算当前的数字*/
switch(flag){
case '+':
++top;
stack[top] = num;
break;
case '-':
++top;
stack[top] = -num;
break;
case '*':
stack[top] *= num;
break;
case '/':
stack[top] /= num;
break;
}
num = 0;
flag = data[pos];
pos++;
/*结束的标志,退出当前的递归,返还上一个运算*/
if(flag == '}' || flag == ']' || flag == ')' || flag == '\n'){
break;
}
}
int res = 0;
for(int i = 0;i<=top;i++){
res += stack[i];
}
return res;
}
int main(void)
{
char *s = (char *)malloc(sizeof(char)*100);
memset(s, 0, sizeof(char)*100);
while(fgets(s,sizeof(char)*100,stdin) != NULL){
pos = 0;
printf("%d\n",compute(s));
}
free(s);
s=NULL;
return 0;
}
-------------------结果------------------------
song@song-virtual-machine:~/C_Program/interview_code$ ./test
2*3-1
5
2*(3-1)
4
^C
song@song-virtual-machine:~/C_Program/interview_code$
#include
#include
#include
#include
int pos;
int check(char st)
{
if(st>='0'&&st<='9'){
return 1;
}else{
return 0;
}
}
int compute(char *data)
{
int len = strlen(data);
int num = 0;
char flag='+';
int top=-1;
int stack[100] = {0};
while(pos<len){
if(data[pos]=='{'||data[pos]=='['||data[pos]=='('){
pos++;
num=compute(data);
}
while(pos<len&&check(data[pos])){
num=num*10+data[pos]-'0';
pos++;
}
switch(flag){
case '+':
++top;
stack[top]=num;
break;
case '-':
++top;
stack[top]=-num;
break;
case '*':
stack[top]*=num;
break;
case '/':
stack[top]/=num;
break;
}
num=0;
flag=data[pos];
pos++;
if(flag=='}'||flag==']'||flag==')'||flag=='\n'){
break;
}
}
int res=0;
for(int i=0;i<=top;i++){
res=res+stack[i];
}
return res;
}
int main(void)
{
char str[100];
while(scanf("%s",str)!= EOF){
pos=0;
printf("%d\n",compute(str));
}
知识点: 字符串;穷举
描述
给定一个仅包含小写字母的字符串,求它的最长回文子串的长度。
所谓回文串,指左右对称的字符串。
所谓子串,指一个字符串删掉其部分前缀和后缀(也可以不删)的字符串
数据范围:字符串长度1≤s≤350
进阶:时间复杂度:O(n) ,空间复杂度:O(n)
输入描述:
输入一个仅包含小写字母的字符串
输出描述:
返回最长回文子串的长度
示例1
输入:cdabbacc
输出:4
说明:
abba为最长的回文子串
代码:
方法1:虽然复杂度为O(n^2),但是好理解,马拉车法不好理解
#include
#include
#include
#include
char* insert(char* str, int n)
{
char* res = (char*)malloc(sizeof(char) * (2 * n + 1));
int i;
for(i=0;*(str+i)!='\0';i++){
res[2 * i] = '#';
res[2 * i + 1] = str[i];
}
res[2 * i] = '#';
return res;
}
int getvalue(char* str, int n)
{
int len=1,max=1;
for(int i=1; i<n; i++){
for(int j=1;(j<=i)&&(j<=n-i);j++){
//printf("* ");
// printf("%c %c %c ",*(str+i-j),*(str+i),*(str+i+j));
if(*(str+i-j)==*(str+i+j)){
len++;
}else{
break;
}
}
// printf("\n");
if(len>max){
max=len;
}
len=1;
}
return max-1;
}
int main(void)
{
char str[351];
while (~scanf("%s", str)) {
int len=strlen(str);
printf("%d\n", len);
char *ptr1 = insert(str, len);
printf("%s\n",ptr1);
printf("%d\n",getvalue(ptr1, 2*len+1));
free(ptr1);
}
}
知识点:字符串;排序;哈希
描述
输入一个只包含小写英文字母和数字的字符串,按照不同字符统计个数由多到少输出统计结果,如果统计的个数相同,则按照ASCII码由小到大排序输出。
数据范围:字符串长度满足1≤len(str)≤1000
输入描述:
一个只包含小写英文字母和数字的字符串。
输出描述:
一个字符串,为不同字母出现次数的降序表示。若出现次数相同,则按ASCII码的升序输出。
示例1
输入:aaddccdc
输出:cda
说明:样例里,c和d出现3次,a出现2次,但c的ASCII码比d小,所以先输出c,再输出d,最后输出a.
代码:
#include
#include
#include
int main(void)
{
char str[1000]={'\0'};
while(scanf("%s",str)!=EOF){
int max=0;
int buf[128]={0};
int len=strlen(str);
for(int i=0;i<len;i++){
buf[str[i]]++;
if(buf[str[i]]>max){
max=buf[str[i]];
}
}
for(int i=max;i>0;i--){
for(int j=0;j<128;j++){
if(i==buf[j]){
printf("%c",j);
}
}
}
printf("\n");
}
}
----------------------结果--------------------------
song@song-virtual-machine:~/C_Program/interview_code$ ./test
aaddccdc
cda
aaccd
acd
aacccd
cad
^C
song@song-virtual-machine:~/C_Program/interview_code$
知识点:基础数学
描述
以上三角形的数阵,第一行只有一个数1,以下每行的每个数,是恰好是它上面的数、左上角数和右上角的数,3个数之和(如果不存在某个数,认为该数就是0)。
求第n行第一个偶数出现的位置。如果没有偶数,则输出-1。例如输入3,则输出2,输入4则输出3,输入2则输出-1。
数据范围:1≤n≤10^9
输入描述:
输入一个int整数
输出描述:
输出返回的int值
示例1
输入:4
输出:3
代码:
方法1:
#include
#include
#include
#include
int main(void)
{
int n=0;
while(scanf("%d",&n)!=EOF){
int i=0,j=0,m=0;
m=2*n-1;
int **buf=(int **)malloc(sizeof(int *)*n); /*数组的行*/
for(i=0;i<n;i++){ /*数组的列,并初始化为0*/
buf[i]=(int *)malloc(sizeof(int)*m);
memset(buf[i],0,m*sizeof(int));
}
buf[0][m/2]=1; /* 第一行 */
for(i=1;i<n;i++){
buf[i][m/2-i]=1;
buf[i][m/2+i]=1;
for(j=m/2-i+1;j<m/2+i;j++){
buf[i][j]=buf[i-1][j]+buf[i-1][j-1]+buf[i-1][j+1];
}
}
// for(i=0;i
// for(j=0;j
// if(buf[i][j]==0){
// //printf("%3d ",buf[i][j]);
// printf(" "); /*4个空格,为了美观*/
// }else{
// printf("%3d ",buf[i][j]);
// }
// }
// printf("\n");
// }
if(n==1||n==2){
printf("%d\n",-1);
}else if(n>=3){
for(i=0;i<(2*n-1)/2;i++){
if(buf[n-1][i]%2==0){
printf("%d\n",i+1);
break;
}
}
}
for(i=0;i<n;i++){
free(buf[i]);
}
free(buf);
}
return 0;
}
方法2:其实没有必要求出来这个数组,只要求求得是第一个偶数
-1 -1 2 3 2 4 2 3 2 4 2 3 2 4
#include
#include
#include
#include
int main(void)
{
int n=0,num=0,buf[4]={2,3,2,4};
while(scanf("%d",&n)!=EOF){
if(n==1||n==2){
num=-1;
}else if(n>2){
num=buf[(n-3)%4];
}
printf("%d\r\n",num);
}
return 0;
}
知识点:动态规划;基础数学
描述
请计算n*m的棋盘格子(n为横向的格子数,m为竖向的格子数)从棋盘左上角出发沿着边缘线从左上角走到右下角,总共有多少种走法,要求不能走回头路,即:只能往右和往下走,不能往左和往上走。
注:沿棋盘格之间的边缘线行走
数据范围:1≤n,m≤8
输入描述:
输入两个正整数n和m,用空格隔开。(1≤n,m≤8)
输出描述:
输出一行结果
示例1
输入:2 2
输出:6
代码:
方法1:
动态规划
分析:
1, dp[i][j]:表示从左上角到i行j列格子的右下角的走法
2, 递推关系:
dp[i][j]=dp[i-1][j]+dp[i][j-1]
3,寻找初值,dp[1][1]=dp[0][1]+dp[1][0]=2; dp[0][1]=dp[1][0]=1;
dp[1][2] = dp[0][2]+dp[1][1]=3, dp[0][2]=1
dp[2][1] = dp[1][1]+dp[2][0]=3, dp[2][0]=1
所以dp[i][0]=1;dp[0][i]=1;
代码:
/*方法1,动态规划做法*/
#include
int main(void)
{
int n, m;
while(scanf("%d %d", &n, &m) != EOF) {
int i, j, dp[n+1][m+1];
for(i=0; i<=n; i++) {
for(j=0; j<=m; j++) {
if(i == 0 && j == 0) {
dp[i][j] = 1;
continue;
}
if(i == 0)
dp[i][j] = dp[i][j-1];
else if(j == 0)
dp[i][j] = dp[i-1][j];
else
dp[i][j] = dp[i][j-1] + dp[i-1][j];
}
}
printf("%d\n", dp[n][m]);
}
}
------------------------------结果---------------------------
song@song-virtual-machine:~/C_Program/interview_code$ ./test
2 2
6
1 3
4
^C
song@song-virtual-machine:~/C_Program/interview_code$
/*方法2,递归做法*/
#include
int fun(int m,int n)
{
if(m==0||n==0)
return 1;
else
return fun(m,n-1)+fun(m-1,n);
}
int main(void)
{
int m,n;
while(scanf("%d%d",&n,&m)!=EOF)
{
printf("%d\n",fun(n,m));
}
}
函数功能:返回走法数。
结束条件:找下规律不难发现:当n或m有一个为1时,走法数等于较大的那个数加一,所以结束条件可以设置为
if(n==1||m==1)
return (n+1>m+1)?n+1:m+1;
等价关系:要走到右下角必须经过最后一个方格的左下角或右上角,所以可以把所有走法分为走到最后一个方格的左下角和走到最后一个方格的右上角,即f(n,m)=f(n,m-1)+f(n-1,m)。
#include
int f(int n,int m)
{
if(n==1||m==1)
return (n+1>m+1)?n+1:m+1;
else
return f(n-1,m)+f(n,m-1);
}
int main(void)
{
int n,m;
while(scanf("%d %d",&n,&m)!=EOF)
{
printf("%d\n",f(n,m));
}
return 0;
}
-------------------结果--------------------
song@song-virtual-machine:~/C_Program/interview_code$ ./test
2 2
6
1 3
4
^C
song@song-virtual-machine:~/C_Program/interview_code$
知识点:递归;基础数学
描述
正整数A和正整数B 的最小公倍数是指 能被A和B整除的最小的正整数值,设计一个算法,求输入A和B的最小公倍数。
数据范围:1≤a,b≤100000
输入描述:
输入两个正整数A和B。
输出描述:
输出A和B的最小公倍数。
示例1
输入:5 7
输出:35
示例2
输入:2 4
输出:4
代码:
最小公倍数=两数的乘积/最大公约(因)数,解题时要避免和最大公约(因)数问题混淆。
辗转相除法, 又名欧几里德算法(Euclidean algorithm),是求最大公约数的一种方法。它的具体做法是:用较小数除较大数,再用出现的余数(第一余数)去除除数,再用出现的余数(第二余数)去除第一余数,如此反复,直到最后余数是0为止。如果是求两个数的最大公约数,那么最后的除数就是这两个数的最大公约数。
#include
#include
/*最大公因数*/
int greatest_common_factor(int a,int b)
{
if(a<b){
int temp = a;
a = b;
b=temp;
}
while(a%b){
int temp=a;
a=b;
b=temp%b;
}
return b;
}
int main(void)
{
int m,n;
while(scanf("%d %d",&m,&n)!=EOF){
printf("%d\n",(m*n)/greatest_common_factor(m,n));
}
}
---------------------------------结果---------------------------------
song@song-virtual-machine:~/C_Program/interview_code$ ./test
2 3
6
150 200
600
^C
song@song-virtual-machine:~/C_Program/interview_code$
知识点:数组
描述
蛇形矩阵是由1开始的自然数依次排列成的一个矩阵上三角形。例如,当输入5时,应该输出的三角形为:
1 3 6 10 15
2 5 9 14
4 8 13
7 12
11
输入描述:
输入正整数N(N不大于100)
输出描述:
输出一个N行的蛇形矩阵。
示例1
输入:4
输出:
1 3 6 10
2 5 9
4 8
7
代码:
#include
#include
int main(void)
{
int n;
while(scanf("%d", &n) != EOF){
int count = 0;
int **buf=(int **)malloc(n*sizeof(int *));
for(int i=0; i<n; i++){
buf[i]=(int *)malloc(n*sizeof(int));
}
for(int i=0; i<n; i++){
for(int j=i; j>=0; j--){
count++;
buf[j][i-j]=count;
}
}
for(int i=0; i<n; i++){
for(int j=0; j<n-i; j++){
printf("%3d",buf[i][j]);
}
printf("\n");
}
for(int i=0; i<n; i++){
free(buf[i]);
}
free(buf);
}
}
知识点:排序;数组;哈希
描述
题目标题:
将两个整型数组按照升序合并,并且过滤掉重复数组元素。输出时相邻两数之间没有空格。
输入描述:
输入说明,按下列顺序输入:
1 输入第一个数组的个数
2 输入第一个数组的数值
3 输入第二个数组的个数
4 输入第二个数组的数值
输出描述:
输出合并之后的数组
示例1
输入:
3
1 2 5
4
-1 0 3 2
输出:-101235
代码:
#include
#include
#include
#include
int cmp(const void* a,const void* b)
{
return ( *(int*)a - *(int*)b);
}
int main(void)
{
int s1,s2;
while(scanf("%d",&s1)!=EOF){
int *n1=(int *)malloc(s1*sizeof(int));
for(int i=0;i<s1;i++){
scanf("%d",&n1[i]);
}
scanf("%d",&s2);
n1=(int *)realloc(n1,(s1+s2)*sizeof(int));
for(int i=s1;i<s1+s2;i++){
scanf("%d",&n1[i]);
}
qsort(n1,s1+s2,sizeof(int),cmp);
int old=n1[0];
printf("%d",n1[0]);
for(int i=1;i<s1+s2;i++){
if(n1[i]!=old){
old=n1[i];
printf("%d",n1[i]);
}
}
printf("\n");
free(n1);
}
return 0;
}
知识点:排序
描述
功能:输入一个正整数,按照从小到大的顺序输出它的所有质因子(重复的也要列举)(如180的质因子为2 2 3 3 5 )
数据范围: 1≤n≤2×10^9 + 14
输入描述:
输入一个整数
输出描述:
按照从小到大的顺序输出它的所有质数的因子,以空格隔开。
示例1
输入:180
输出:2 2 3 3 5
解析:sqrt
什么是质数因子
“质数是指在大于1的自然数中,除了1和它本身以外不再有其他因数的自然数。
代码
/*方法1*/
#include
#include
int main(void)
{
int a,b,i=0;
scanf("%d",&a);
for(b=2;b<=a;b++){ /*最小质数因子必小于输入数字的平方根*/
if(b>(sqrt(a)+1)){
b =a;
}
while(a%b==0){
printf("%d ",b);
a = a/b;
}
}
printf("\n");
return 0;
}
-------------------------结果------------------------------
song@song-virtual-machine:~/C_Program/interview_code$ ./test
180
2 2 3 3 5
song@song-virtual-machine:~/C_Program/interview_code$
知识点:查找;排序
描述
有一种兔子,从出生后第3个月起每个月都生一只兔子,小兔子长到第三个月后每个月又生一只兔子。
例子:假设一只兔子第3个月出生,那么它第5个月开始会每个月生一只兔子。
假如兔子都不死,问第n个月的兔子总数为多少?
数据范围:输入满足1≤n≤31
输入描述:
输入一个int型整数表示第n个月
输出描述:
输出对应的兔子总数
示例1
输入:3
输出:2
代码:
分析:
1、数组定义
dp[i]表示第i个月的兔子总数
2、数组元素关系式
dp[i]=dp[i-1]+dp[i-2]
3、初值
dp[1]=1
dp[2]=1
#include
#include
#include
int main(void)
{
int mon;
while(scanf("%d",&mon)!=EOF) {
int *dp=(int *)malloc((mon+1)*sizeof(int)); /*创建一个数组用于保存历史数据*/
dp[1]=dp[2]=1; /*赋初值*/
for(int i=3;i<=mon;i++) { /*根据元素关系式求dp[mon]*/
dp[i]=dp[i-1]+dp[i-2];
}
printf("%d\r\n",dp[mon]);
free(dp);
}
return 0;
}
知识点:链表;双指针
描述
输入一个单向链表,输出该链表中倒数第k个结点,链表的倒数第1个结点为链表的尾指针。
链表结点定义如下:
struct ListNode
{
int m_nKey;
ListNode* m_pNext;
};
正常返回倒数第k个结点指针,异常返回空指针.
要求:
(1)正序构建链表;
(2)构建后要忘记链表长度。
数据范围:链表长度满足1≤n≤1000,k≤n,链表中数据满足0≤val≤10000
本题有多组样例输入。
输入描述:
输入说明
1、输入链表结点个数
2、输入链表的值
3、输入k的值
输出描述:
输出一个整数
示例1
输入:
8
1 2 3 4 5 6 7 8
4
输出:5
代码:
输出第k个节点
#include
#include
#include
//注意链表的定义语句
//next处要用struct ListNode*因为ListNode方法还没有定义
//链表的写入 head tail used三个指针;
typedef struct ListNode {
int m_nKey;
struct ListNode* m_pNext;
}ListNode;
int main(void)
{
int n; /*链表的个数*/
while(scanf("%d",&n) !=EOF){
ListNode *num,*head,*tail; /*结点,头,尾*/
/* 建立链表 */
head =(ListNode *)malloc(sizeof(ListNode));
head->m_pNext = NULL;
tail=head;
for(int i=0;i<n;i++){
num=(ListNode *)malloc(sizeof(ListNode));
scanf("%d",&num->m_nKey);
num->m_pNext =NULL;
tail->m_pNext = num;
tail=num;
}
head=head->m_pNext;
/*打印链表*/
ListNode *p=head;
while(p!=NULL){
printf("%d ",p->m_nKey);
p=p->m_pNext;
}
printf("\n");
/*查找链表第k个结点*/
int search;
scanf("%d",&search);
if(search<=0||search>n){
printf("0\n");
}else{
ListNode *find;
find=head;
for(int i=1;i<search;i++){
find=find->m_pNext;
}
printf("%d\n",find->m_nKey);
}
free(head);
}
return 0;
}
----------------------------结果---------------------------------
song@song-virtual-machine:~/C_Program/interview_code$ ./test
8
2 7 6 3 9 12 12 8
2 7 6 3 9 12 12 8
8
8
^C
song@song-virtual-machine:~/C_Program/interview_code$
方法1:
#include
#include
#include
//注意链表的定义语句
//next处要用struct ListNode*因为ListNode方法还没有定义
//链表的写入 head tail used三个指针;
typedef struct ListNode {
int m_nKey;
struct ListNode* m_pNext;
}ListNode;
int main(void)
{
int n; /*链表的个数*/
while(scanf("%d",&n) !=EOF){
ListNode *num,*head,*tail; /*结点,头,尾*/
/*1, 建立链表 */
head =(ListNode *)malloc(sizeof(ListNode));
head->m_pNext = NULL;
tail=head;
for(int i=0;i<n;i++){
num=(ListNode *)malloc(sizeof(ListNode));
scanf("%d",&num->m_nKey);
num->m_pNext =NULL;
tail->m_pNext = num;
tail=num;
}
head=head->m_pNext;
/*打印链表*/
ListNode *p=head;
while(p!=NULL){
printf("%d ",p->m_nKey);
p=p->m_pNext;
}
printf("\n");
/*2,查找链表倒数第k个结点*/
int search;
scanf("%d",&search);
if(search<=0||search>n){
printf("0\n");
}else{
ListNode *find;
find=head;
for(int i=0;i<n-search;i++){
find=find->m_pNext;
}
printf("%d\n",find->m_nKey);
}
free(head);
}
return 0;
}
----------------------------结果---------------------------------
song@song-virtual-machine:~/C_Program/interview_code$ ./test
8
1 2 3 4 5 6 7 8
1 2 3 4 5 6 7 8
4
5
^C
song@song-virtual-machine:~/C_Program/interview_code$
知识点:数学;模拟
描述
某商店规定:三个空汽水瓶可以换一瓶汽水,允许向老板借空汽水瓶(但是必须要归还)。
小张手上有n个空汽水瓶,她想知道自己最多可以喝到多少瓶汽水。
数据范围:输入的正整数满足1≤n≤100
注意:本题存在多组输入。输入的 0 表示输入结束,并不用输出结果。
输入描述:
输入文件最多包含 10 组测试数据,每个数据占一行,仅包含一个正整数 n( 1<=n<=100 ),表示小张手上的空汽水瓶数。n=0 表示输入结束,你的程序不应当处理这一行。
输出描述:
对于每组测试数据,输出一行,表示最多可以喝的汽水瓶数。如果一瓶也喝不到,输出0。
示例1
输入:
3
10
81
0
输出:
1
5
40
说明:
样例 1 解释:用三个空瓶换一瓶汽水,剩一个空瓶无法继续交换
样例 2 解释:用九个空瓶换三瓶汽水,剩四个空瓶再用三个空瓶换一瓶汽水,剩两个空瓶,向老板借一瓶汽水喝完得三个空瓶换一瓶汽水还给老板
方法1:
解析
题目描述中有讲到:剩2个空瓶子时,可以先找老板借一瓶汽水,喝掉这瓶满的,喝完以后用3个空瓶子换一瓶满的还给老板。也就是说2个空瓶子即可换一瓶汽水喝,而且喝完之后手里也没有空瓶子。求解时直接把空瓶数除以2,即可得到正解。
代码
#include
int main(void)
{
int buf[10],i,nums;
int *ptr = buf;
for(i=0;i<10;i++){
scanf("%d",&buf[i]);
if(buf[i]==0){
break;
}
}
nums=i; /*一共输入可5组数*/
for(i=0;i<nums;i++){
printf("%d\r\n",buf[i]/2);
}
}
方法2:
解析:
并不是所有的问题都能用递归解决。要使用递归就必须要具备两个条件。
递归的思想是:为了解决当前问题 F(n),就需要解决问题 F(n–1),而 F(n–1) 的解决依赖于 F(n–2) 的解决……就这样逐层分解,分解成很多相似的小事件,当最小的事件解决完之后,就能解决高层次的事件。这种“逐层分解,逐层合并”的方式就构成了递归的思想。
使用递归最主要的是要找到递归的出口和递归的方式。所以递归通常分为两部分:递归的方式和递归的终止条件(最小事件的解)。这两个部分是递归的关键!
递归的方式,就是指递归公式,即对问题的分解,同时也是向递归终止条件收敛的规则。而递归的终止条件通常就是得出的最小事件的解。递归终止条件的作用就是不让递归无限地进行下去,最后必须要能“停”下来。
综上所述,使用递归必须要满足的两个条件就是:
/*方法1*/
#include
int bottle(int num)
{
int x=0,y=0;
int res=0;
if(num==1){
return 0;
}else if(num==2){
return 1;
}else{
x=num%3;
y=num/3;
res=y;
res=res+bottle(x+y);
return res;
}
}
int main(void)
{
int buf[10],i,nums;
int *ptr = buf;
for(i=0;i<10;i++){
scanf("%d",&buf[i]);
if(buf[i]==0){
break;
}
}
nums=i; /*一共输入可5组数*/
for(i=0;i<nums;i++){
printf("%d\r\n",bottle(buf[i]));
}
}
--------------------结果-------------------
song@song-virtual-machine:~/C_Program/interview_code$ ./test
3
10
81
0
1
5
40
song@song-virtual-machine:~/C_Program/interview_code$
知识点:递归;动态规划
描述
把m个同样的苹果放在n个同样的盘子里,允许有的盘子空着不放,问共有多少种不同的分法?
注意:如果有7个苹果和3个盘子,(5,1,1)和(1,5,1)被视为是同一种分法。
数据范围:0≤m≤10 , 1≤n≤10 。
输入描述:
输入两个int整数
输出描述:
输出结果,int型
示例1
输入:7 3
输出:8
方法1:动态规划
解析:
1、数组定义
dp[m][n]: 把m个苹果放在n个盘子有dp[m][n]中放法
2、数组元素关系式
这里有两种情况,
1)当苹果数小于盘子数时
也就是m<n,与m个苹果m个盘子的放法是一样的,也就是m<n,dp[m][n]=dp[m][m]
2)当苹果数大于等于盘子数的时候,也就是m>=n,不同的放法可以分成两类:
a、有至少一个盘子空着,原则上相当于dp(m,n) =dp (m,n-1) + dp (m,n-2) + dp (m,n-3)... 但是考虑到dp (m,n-2)包含在dp (m,n-1)中(这里思考下!),避免重复统计,则dp (m,n) = dp (m,n-1)
b、所有盘子都有苹果,相当于可以从每个盘子中拿掉一个苹果,不影响不同放法的数目,即dp(m,n) = dp(m-n,n).
则总的放苹果的放法数目等于两者的和,即 dp(m,n) =dp(m,n-1)+dp(m-n,n)
3、初值
当有一个苹果或者没有苹果,不管有多少篮子,只有一种放法:dp[0][j]=1;dp[1][j]=1;
当有一个篮子或者没有篮子,不管有多少苹果,只有一种放法:dp[i][0]=1; dp[i][1]=1;
代码:
#include
#include
#include
#include
int main(void)
{
int m,n;
while(scanf("%d %d",&m,&n)!=EOF){
int **dp=(int **)malloc((m+1)*sizeof(int *)); /*定义存储历史数据的数组*/
for(int i=0;i<m+1;i++){
dp[i]=(int *)malloc((n+1)*sizeof(int));
memset(dp[i],0,(n+1)*sizeof(int));
}
for(int i=0;i<m+1;i++){
dp[i][0]=1; /*当篮子为0个时,不管苹果有多少,都只有一种方法*/
dp[i][1]=1; /*当篮子为1个时,不管苹果有多少,都只有一种方法*/
}
for(int i=0;i<n+1;i++){
dp[0][i]=1; /*当苹果为0个时,不管篮子有多少,都只有一种方法*/
dp[1][i]=1; /*当苹果为1个时,不管篮子有多少,都只有一种方法*/
}
for(int i=0;i<m+1;i++){
for(int j=0;j<n+1;j++){
printf("%d ",dp[i][j]);
}
printf("\n");
}
printf("-----------------------------------------\r\n");
for(int i=2;i<m+1;i++){
for(int j=2;j<n+1;j++){
if(i<j){
dp[i][j]=dp[i][i];
}else{
dp[i][j]=dp[i-j][j]+dp[i][j-1];
}
}
}
for(int i=0;i<m+1;i++){
for(int j=0;j<n+1;j++){
printf("%d ",dp[i][j]);
}
printf("\n");
}
printf("-----------------------------------------\r\n");
printf("%d\r\n",dp[m][n]);
for(int i=0;i<m+1;i++){
free(dp[i]);
}
free(dp);
}
}
方法2:递归
解析
设f(m,n)为m个苹果,n个盘子的放法数目,则先对n作讨论,
当m<n:必定有n-m个盘子永远空着,去掉它们对摆放苹果方法数目不产生影响,即if(n>m) f(m,n) = f(m,m) 问题变成m个苹果,m个盘子的问题。也就是下面的m>=n的情况
当m>=n:不同的放法可以分成两类:
1、有至少一个盘子空着,原则上相当于f(m,n) = f(m,n-1) + f(m,n-2) + f(m,n-3)... 但是考虑到f(m,n-2)包含在f(m,n-1)中(这里思考下!),避免重复统计,则f(m,n) = f(m,n-1)
2、所有盘子都有苹果,相当于可以从每个盘子中拿掉一个苹果,不影响不同放法的数目,即f(m,n) = f(m-n,n).
则总的放苹果的放法数目等于两者的和,即 f(m,n) =f(m,n-1)+f(m-n,n)
递归出口条件说明: 当n=1时,所有苹果都必须放在一个盘子里,所以返回1; 当m=0时,没有苹果可以放置,返回1种放法; 递归的两条路,第一条n会逐渐减少,终会到达出口n==1; 第二条m会逐渐减少,因为n>m时,我们会return f(m,m) 所以终会到达出口m==0.
代码:
/*方法2*/
#include
/* 设f(m,n)为m个苹果,n个盘子的放法数目, */
int fun(int m,int n){
if(m==0||n==1){
return 1;
}else if(m<n){
return fun(m,m);
}else{
return fun(m-n,n)+fun(m,n-1);/*没有空盘子的情况+有空盘的情况*/
}
}
int main(){
int a,b,num;
while(~scanf("%d%d",&a,&b)){
num = fun(a,b);
printf("%d\n",num);
}
}
------------------------------结果-----------------------------
song@song-virtual-machine:~/C_Program/interview_code$ ./test
7 3
8
^C
song@song-virtual-machine:~/C_Program/interview_code$
知识点:哈希
描述
数据表记录包含表索引index和数值value(int范围的正整数),请对表索引相同的记录进行合并,即将相同索引的数值进行求和运算,输出按照index值升序进行输出。
提示:
0 <= index <= 11111111
1 <= value <= 100000
输入描述:
先输入键值对的个数n(1 <= n <= 500)
接下来n行每行输入成对的index和value值,以空格隔开
输出描述:
输出合并后的键值对(多行)
示例1
输入:
4
0 1
0 2
1 2
3 4
输出:
0 3
1 2
3 4
示例2
输入:
3
0 1
0 2
8 9
输出:
0 3
8 9
/*方法1*/
#include
#include
#include
#include
typedef struct datalist
{
int index;
int value;
}datalist;
int main(void)
{
int n;
while(scanf("%d", &n) != EOF) {
datalist *list=(datalist*)malloc(n*sizeof(datalist));
int max_index=0;
for(int i=0; i<n; i++){
scanf("%d",&list[i].index);
scanf("%d",&list[i].value);
if(list[i].index>max_index){
max_index = list[i].index;
}
}
int *buf=(int *)malloc(max_index*sizeof(int));
memset(buf,0,max_index*sizeof(int));
for(int i=0; i<n; i++){
buf[list[i].index] +=list[i].value;
}
for(int i=0; i<=max_index; i++) {
if(buf[i]){
printf("%d %d\n", i, buf[i]);
}
}
free(buf);
free(list);
}
}
/*方法2*/
#include
#include
#include
typedef struct STU{
int index;
int value;
}STU;
int main(void)
{
int n; /*表示数量*/
while (scanf("%d", &n) != EOF){
STU *group=(STU *)malloc(n*sizeof(STU));
for(int i=0; i<n; i++){
scanf("%d %d",&(group[i].index),&(group[i].value));
}
int m=0;
int sum=0;
for(int i=0; i<n; i++){
for(int j=0; j<n; j++){
if(group[i].index == group[j].index){
sum=sum+group[j].value;
}
}
group[i].value=sum;
sum=0;
}
printf("---------------------------------------\n");
for(int i=0; i<n; i++){
printf("%d %d\n",group[i].index,group[i].value);
}
/*冒泡排序*/
int temp_index = 0;
int temp_value = 0;
for(int i=0; i<n-1; i++){
for(int j=0; j<n-i-1; j++){
if(group[j].index>group[j+1].index){
temp_index=group[j].index;
temp_value=group[j].value;
group[j].index=group[j+1].index;
group[j].value=group[j+1].value;
group[j+1].index=temp_index;
group[j+1].value=temp_value;
}
}
}
printf("---------------------------------------\n");
for(int i=0; i<n; i++){
printf("%d %d\n",group[i].index,group[i].value);
}
printf("---------------------------------------\n");
int last = group[0].index;
printf("%d %d\n",group[0].index,group[0].value);
for(int i=1; i<n;i++){
if(group[i].index!=last){
printf("%d %d\n",group[i].index,group[i].value);
}
last = group[i].index;
}
free(group);
}
return 0;
}
----------------------------结果---------------------------------
song@song-virtual-machine:~/C_Program/interview_code$ ./test
4
1 5
0 1
0 6
2 7
---------------------------------------
1 5
0 7
0 13
2 7
---------------------------------------
0 7
0 13
1 5
2 7
---------------------------------------
0 7
1 5
2 7
^C
song@song-virtual-machine:~/C_Program/interview_code$