华为机试--中等(二)

HJ26 字符串排序

知识点:字符串;排序
描述
编写一个程序,将输入字符串中的字符按如下规则排序。
规则 1 :英文字母从 A 到 Z 排列,不区分大小写。
如,输入: Type 输出: epTy
规则 2 :同一个英文字母的大小写同时存在时,按照输入顺序排列。
如,输入: BabA 输出: aABb
规则 3 :非英文字母的其它字符保持原来的位置。
如,输入: By?e 输出: Be?y
数据范围:输入的字符串长度满足1≤n≤1000
输入描述:
输入字符串
输出描述:
输出字符串
示例1

输入:A Famous Saying: Much Ado About Nothing (2012/8).
输出:A aaAAbc dFgghh: iimM nNn oooos Sttuuuy (2012/8).

代码:
分析:
1,首先要获得只有字母的排序列表(不能破坏相同字母本身的顺序),
其中的技巧就是循环字符串遇到子母后,添加一个元素(letter - ‘a’)len + i(这是因为:
以B和b 为例:若遇见B则B-A=1;但是b-a=1,都是1,为了区分先后,for循环是从0开始的,
所以(letter - ‘a’)len + i,解析的时候对len取余数,就可以的数字就是i,i可以说明先后顺序),
2,然后对整个列表排序,对len取余数,这样我们既能知道字母的顺序,有可以知道他原来
在什么位置,是什么字母
3,然后我们就可以判断原字符串每个位置是否是字母,如果不是,
就把原字符串该位置的字符赋给结果对应的位置,如果是,
就弹出列表的值(取余获得原来位置,取出字母)赋给结果的这个位置,以此循环

                      /*方法1*/
#include<stdio.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
int cmp(const void *a,const void *b){
    return (*(int *)a-*(int *)b);
}
void printf_order(int *or,int len)
{
    printf("--------------order-------------------\r\n");
    for(int i=0;i<len;i++){
            printf("%d    ",or[i]);
            if(i!=0&&i%10==0){
                printf("\r\n");
            }
    }
    printf("\n---------------------------\n");
}

int main(void)
{
    char str[1000];
    while(scanf("%[^\n]",str)){
        getchar();
        int len = strlen(str);
        int *order = (int*)malloc(sizeof(int)*len);
        char *result = (char*)malloc(sizeof(char)*len+1);
        memset(order, 0, sizeof(int)*len);
        memset(result, 0, sizeof(char)*len+1);

        printf("len:%d\r\n", len);
        int temp = 0;
        for(int i=0; i<len; i++){
            if(str[i]>='a' && str[i]<='z'){
                order[temp++] = (str[i] - 'a')*len + i;   /*i最大也是小于len的,*len既可以避免i对原有字符大小的影响,又可以获得相同字符的顺序*/
            }else if(str[i]>='A' && str[i]<='Z'){
                order[temp++] = (str[i] - 'A')*len + i;
            }
        }
        //printf_order(order,len);    /*测试查看使用*/
        qsort(order, temp, sizeof(int), cmp);
       // printf_order(order,len);  /*测试查看使用*/

        temp = 0;
        for(int j=0; j<len; j++){
            if((str[j]>='a' && str[j]<='z')||(str[j]>='A' && str[j]<='Z')){
                int n = order[temp++]%len;
            //    printf("n:%d  str:%c\r\n",n,str[n]);
                result[j] = str[n];
            }else{
                result[j] = str[j];
            }
        }
        printf("%s\n",result);

        free(result);
        free(order);
    }
}

--------------------结果-------------------------
song@song-virtual-machine:~/C_Program/interview_code$ ./test
A Famous Saying: Much Ado About Nothing (2012/8)
len:48
A aaAAbc dFgghh: iimM nNn oooos Sttuuuy (2012/8)
^C
song@song-virtual-machine:~/C_Program/interview_code$

HJ41 称砝码

知识点:字符串;哈希
描述
现有n种砝码,重量互不相等,分别为 m1,m2,m3…mn ;
每种砝码对应的数量为 x1,x2,x3…xn 。现在要用这些砝码去称物体的重量(放在同一侧),问能称出多少种不同的重量。
注:
称重重量包括 0
数据范围:每组输入数据满足1≤n≤10 ,1≤mi≤2000 ,1≤xi≤10
输入描述:
对于每组测试数据:
第一行:n — 砝码的种数(范围[1,10])
第二行:m1 m2 m3 … mn — 每种砝码的重量(范围[1,2000])
第三行:x1 x2 x3 … xn — 每种砝码对应的数量(范围[1,10])
输出描述:
利用给定的砝码可以称出的不同的重量数
示例1
输入:
2
1 2
2 1
输出:
5
说明:可以表示出0,1,2,3,4五种重量。

代码:
方法1:

                                      /*方法1*/
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<malloc.h>
#include <math.h>

typedef struct Kindcode{
        int kind;
        int number;
}Kindcode;


/*为了看可以拼接成哪些重量,就从最大重量开始往下遍历
首先要求出总重量,然后定义一个存储所有重量的数组,当存在这个重量是,标1
然后三层for循环,第一层是种类,第二层是在该种类下,小于该种类下砝码的数目
第三层是从总重量开始,判断是否该重量存在,不存在减一,当标志位1,也就是存在时,
在这个重量的基础上,加上当前种类的重量,并标志为1
最后,对所有的标志求和得到最终种类
*/
int main(void)
{
    int n;  /*砝码的种数*/
    while(scanf("%d",&n)!=EOF){
        Kindcode *fama=(Kindcode *)malloc(n*sizeof(Kindcode));
        for(int i=0;i<n;i++){
            scanf("%d",&fama[i].kind);
        }
        for(int i=0;i<n;i++){
            scanf("%d",&fama[i].number);
        }
        // for(int i=0;i<n;i++){
        //     printf("kind:%d  number:%d\r\n",fama[i].kind,fama[i].number);
        // }
        /*1,求所有砝码的宗重量*/
        int total=0;
        for(int i=0;i<n;i++){
            total=total + fama[i].kind*fama[i].number;
        }
        //printf("total:%d\r\n",total);
        /*2,定义每个重量的标志数组,为1表示可以称量这个重量*/
        int *weight_flag=(int *)malloc((total+1)*sizeof(int));
        memset(weight_flag,0,sizeof(int)*(total+1));
        weight_flag[0]=1;   /*称重0时,肯定存在*/
        /*3,遍历*/
        for(int i=0; i<n; i++){
            for(int j=0;j<fama[i].number;j++){
                for(int k=total;k>=0;k--){
                    if(weight_flag[k]==1){
                        weight_flag[k+fama[i].kind]=1;
                    }
                }
            }
        }
        int kind=0;
        for(int i=0;i<total+1;i++){
            kind=kind+weight_flag[i];
        }
        printf("%d\n",kind);
        free(weight_flag);
        free(fama);
    }
}
--------------------结果-------------------------
song@song-virtual-machine:~/C_Program/interview_code$ ./test
2
1 2
2 1
total:4
5
^C
song@song-virtual-machine:~/C_Program/interview_code$ 

HJ57 高精度整数加法

知识点:字符串
描述
输入两个用字符串 str 表示的整数,求它们所表示的数之和。
数据范围: 1≤len(str)≤10000
输入描述:
输入两个字符串。保证字符串只含有’0’~'9’字符
输出描述:
输出求和后的结果
示例1
输入:
9876543210
1234567890
输出:
11111111100
代码:
方法1:
解析:这个问题将字符串转为数字然后相加,但是这样显然是不行的,因为字符串长度为1~10000,长整形也没有这么大的精度。

1, 首先求出两个数字字符的最长长度max
2,根据max,从两个字符串的尾端,开始相加(注意判断索引是否仍然小于字符串的长度)
3,处理进位情况

                              /*方法1*/
#include "stdio.h"
#include "string.h"

void add(char *stra,char *strb)
{
    int flag =0;
    int temp =0;
    char value[10002]={0};
    int lena=strlen(stra);
    int lenb=strlen(strb);
    int max=lena;       /*求出两个字符串的最大长度*/
    if(lenb>lena) max=lenb;
    
    for(int i=0;i<max;i++){
        temp=0;
        if(lena-1-i>=0){ /*当i未超过lena长度时*/
            temp=temp+stra[lena-1-i] - '0';
        }
        if(lenb-1-i>=0){ /*当i未超过lenb长度时*/
            temp=temp+strb[lenb-1-i] - '0';     /*将两个字符串相同位相加*/
        }       
        if(flag == 1){  /*上一位计算中,如果大于10,也就是产生了进位*/
            temp=temp+1;
        }
        temp=temp+'0';      /*将数字转换为对应的字符*/
        if(temp>'9'){   /*产生了进位*/
            value[max-1-i]=temp-10;
            flag=1;
        }else{
            value[max-1-i]=temp;    /*没有产生进位*/
            flag=0;
        }
    }
    if(flag==1){    /*最后一位产生进位的话,说明最终的结果比max多一位,且一定是1*/
        printf("1%s\n",value);
    }else{
        printf("%s\n",value);
    }
}

int main(void)
{
    char stra[10001],strb[10001];
    while(scanf("%s %s",stra,strb)!=EOF) {
        add(stra,strb);
    }
    return 0;
}
--------------------结果-------------------------
song@song-virtual-machine:~/C_Program/interview_code$ ./test
9876543210
1234567890
11111111100
^C
song@song-virtual-machine:~/C_Program/interview_code$ 

HJ70 矩阵乘法计算量估算

知识点:字符串;栈
描述
矩阵乘法的运算量与矩阵乘法的顺序强相关。
例如:
A是一个50×10的矩阵,B是10×20的矩阵,C是20×5的矩阵
计算ABC有两种顺序:((AB)C)或者(A(BC)),前者需要计算15000次乘法,后者只需要3500次。
编写程序计算不同的计算顺序需要进行的乘法次数。

数据范围:矩阵个数:1≤n≤15 ,行列数: 1≤rowi ,coli≤100 ,保证给出的字符串表示的计算顺序唯一。
进阶:时间复杂度: O(n) ,空间复杂度: O(n)
输入描述:
输入多行,先输入要计算乘法的矩阵个数n,每个矩阵的行数,列数,总共2n的数,最后输入要计算的法则计算的法则为一个字符串,仅由左右括号和大写字母(‘A’~‘Z’)组成,保证括号是匹配的且输入合法!
输出描述:
输出需要进行的乘法次数
示例1
输入:
3
50 10
10 20
20 5
(A(BC))
输出:
3500

代码:
对于矩阵乘法次数的计算,
乘法计算次数为: 第一个矩阵的行第二个矩阵的列第二个矩阵的行,或者: 第一个矩阵的行第二个矩阵的列第一个矩阵的列

例如:
A是一个50×10的矩阵,B是10×20的矩阵,C是20×5的矩阵
((AB)C):首先是AB:502010=10000,D=AB的大小为5010,则DC:50520=5000,一共15000次
(A(BC)): 首先是BC:10
520=1000,D=BC的大小为105,则DC:50510=2500,一共3500次

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*
1,获得没有(的计算法则
2,在for循环里面判断,如果遇见(
利用公式:第一个矩阵的行*第二个矩阵的列*第一个矩阵的列  计算得到乘法次数
3,判断str[i+1]是否为'\0',如果是,则break,否则把第二个矩阵的列赋给第一个矩阵的列,然后将
&str[i+1]开始的字符串复制到&str[i-1]
*/
int main(void)
{
    int n;       /*矩阵数量*/
    while(scanf("%d", &n) != EOF){
        int *x_data=(int *)malloc(n*sizeof(int));   /*行列*/
        int *y_data=(int *)malloc(n*sizeof(int));    
        char type[100]={'\0'};
        char str[100]={'\0'};
        for(int i=0; i<n; i++){
            scanf("%d",&x_data[i]);
            scanf("%d",&y_data[i]);
        }
        scanf("%s",type);
        int len=strlen(type);
        /*1,去掉所有的(*/
        int j=0;
        for(int i=0;i<len;i++){
            if(type[i]!='('){
                str[j++]=type[i];
            }
        }
        printf("%s\r\n",str);

        /*计算次数*/
        int count=0;
        for(int i=0;i<len;i++){
            if(str[i]==')'){
                count=count+x_data[str[i-2]-'A']*y_data[str[i-1]-'A']*y_data[str[i-2]-'A'];
                // printf("%d*%d*%d\r\n",x_data[str[i-2]-'A'],y_data[str[i-1]-'A'],y_data[str[i-2]-'A']);
                // printf("%d*%d*%d\r\n",str[i-2]-'A',str[i-1]-'A',str[i-2]-'A');
                // printf("%c*%c*%c\r\n",str[i-2],str[i-1],str[i-2]);
                // printf("i:%d\r\n",i);

                if(str[i+1]=='\0'){
                    break;
                }
                y_data[str[i-2]-'A']=y_data[str[i-1]-'A'];
                strcpy(&str[i-1],&str[i+1]);
                i=i-2;
            }
        }

        printf("%d\r\n",count);


        // for(int i=0; i<n; i++){
        //     printf("%d,%d\r\n",x_data[i],y_data[i]);
        // }
        // printf("%s",type);

        free(y_data);
        free(x_data);
    }
    return 0;
}


-------------------------结果------------------------------
song@song-virtual-machine:~/C_Program/interview_code$ ./test
4
50 10
10 20
20 5
5 10
((A(BC))D)
ABC))D)
6000
^C
song@song-virtual-machine:~/C_Program/interview_code$

HJ82 将真分数分解为埃及分数

知识点:基础数学;搜索
描述
分子为1的分数称为埃及分数。现输入一个真分数(分子比分母小的分数,叫做真分数),请将该分数分解为埃及分数。如:8/11 = 1/2+1/5+1/55+1/110。
注:真分数指分子小于分母的分数,分子和分母有可能gcd不为1!
如有多个解,请输出任意一个。
输入描述:
输入一个真分数,String型
输出描述:
输出分解后的string
示例1
输入:
8/11
2/4
输出:
1/2+1/5+1/55+1/110
1/3+1/6
说明:第二个样例直接输出1/2也是可以的

代码:
sprintf的返回值:如果成功,则返回写入的字符总数,不包括字符串追加在字符串末尾的空字符。如果失败,则返回一个负数。

                  /*方法1*/
/**
古埃及人所指的分数,其分子必等于1,例如:1/2、1/3、1/4。
数学家斐波那契提出的一种求解埃及分数的算法:
设某个真分数的分子为b,分母为a,         b/a;  
把c=(a/b+1)作为分解式中第一个埃及分数的分母;
将b-a%b作为新的b;
将a*c作为新的a;
如果b等于1,则最后一个埃及分数为1/a,算法结束;
如果b大于1但是a能整除b,则最后一个埃及分数为1/(a/b),算法结束;
否则重复上面的步骤。
**/
#include<stdio.h>
#include<stdlib.h>
#include<string.h>

int main(void)
{
    int a,b,c,i=0;  /*b/a*/
    char buffer[20]={0};
    while(scanf("%d/%d",&b,&a)!=EOF)
    {
        while(1){
            c=(a/b+1); /*第一个埃及分数的分母*/
            b=b-a%b;
            a=a*c;
            i+=sprintf(buffer+i,"1/%d+",c);
           // printf("%d\r\n",i);
            if(b==1){
                i+=sprintf(buffer+i,"1/%d",a);
                break;
            }
            if(b>1&&a%b==0){
                i+=sprintf(buffer+i,"1/%d",a/b);
                break;
            }
        }
        printf("%s\n",buffer);
        i=0;
        memset(buffer,0,20);
    }
}
-----------------结果----------------------
song@song-virtual-machine:~/C_Program/interview_code$ ./test 
8/11
4
8
13
1/2+1/5+1/37+1/4070
^C
song@song-virtual-machine:~/C_Program/interview_code$
               /*无输入输出格式限制,方法1*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int main(void)
{
    int a,b,c;  /*b/a*/
    while(scanf("%d/%d",&b,&a)!=EOF){
        while(1){
            c=(a/b+1);
            b=b-a%b;
            a=a*c;
            printf("1/%d+",c);
            if(b==1){
                printf("1/%d",a);
                break;
            }
            if(b>1&&a%b==0){
                printf("1/%d",a/b);
                break;
            }
        }
        printf("\n");
    }
    return 0;
}
-----------------结果----------------------
song@song-virtual-machine:~/C_Program/interview_code$ ./test 
8/11
1/2+1/5+1/37+1/4070
^C
song@song-virtual-machine:~/C_Program/interview_code$

HJ107 求解立方根

知识点:基础数学;二分
描述
计算一个浮点数的立方根,不使用库函数。
保留一位小数。
数据范围:∣val∣≤20
输入描述:
待求解参数,为double类型(一个实数)
输出描述:
输出参数的立方根。保留一位小数。

示例1
输入:
216
输出:
6.0

示例2
输入:
2.7
输出:
1.4

代码:
注意:解题时要看数据范围,看是否有负数的情况

                /*方法1*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int main(void)
{
    double n;
    while(scanf("%lf",&n)!=EOF) {
        int flag=0;
        if(n<0){
            flag=1;
            n=-n;
        }
        double res=0.0;
        while(res*res*res<=n){
            res=res+0.01;
        }
        printf("%lf\r\n",res);
        if(flag==1){
            res=-res;
            printf("%.1lf\r\n",res);    /*观察结果可知,可以自动四舍五入*/
        }else{
            printf("%.1lf\r\n",res);
        }
    }
}
-----------------结果----------------------
song@song-virtual-machine:~/C_Program/interview_code$ ./test 
3.8
1.570000
1.6
3.6
1.540000
1.5
^C
song@song-virtual-machine:~/C_Program/interview_code$

方法二:
牛顿迭代
在这里插入图片描述
对于开3次方根
在这里插入图片描述

#include <stdio.h>
double myabs(double x)
{
    return (x>0?x:-x);
}
double cubert(const double y)
{
    double x=1.0;
    while(myabs(x*x*x-y)>1e-7){
        x=(2*x+y/x/x)/3;
    }
    return x;
}
int main(void)
{
    double y=0;
    while(scanf("%lf",&y)!=EOF){
        int flag =0;
        if(y<0){
            flag=1;
            y=-y;
        }
        double x=cubert(y);
        if(flag==1){
            x=-x;
        }
        printf("%lf   %lf\n",x,x*x*x);
    }
    return 0;
}
----------------结果--------------------
song@song-virtual-machine:~/C_Program/interview_code$ ./test 
-2
-1.259921   -2.000000
2
1.259921   2.000000
-8
-2.000000   -8.000000
5
1.709976   5.000000
^C
song@song-virtual-machine:~/C_Program/interview_code$

对于开4次方根
在这里插入图片描述

#include <stdio.h>
double myabs(double x)
{
    return (x>0?x:-x);
}

double cubert(const double y)
{
    double x=1.0;
    while(myabs(x*x*x*x-y)>1e-7){
        x=(3*x+y/x/x/x)/4;
    }
    return x;
}
int main(void)
{
    double y=0;
    while(scanf("%lf",&y)!=EOF){
        if(y<0){
            printf("error\r\n");
        }else{
            double x=cubert(y);
            printf("%lf   %lf\r\n",x,x*x*x*x);
        }
    }
    return 0;
}
-------------------结果----------------------
song@song-virtual-machine:~/C_Program/interview_code$ ./test 
16
2.000000   16.000000
1.2
1.046635   1.200000
1.7
1.141858   1.700000
^C
song@song-virtual-machine:~/C_Program/interview_code$

用库函数求:

#include <stdio.h>
#include <math.h>
int main(void)
{
    double y=0;
    while(scanf("%lf",&y)!=EOF){
        int flag=0;
        if(y<0){
            flag=1;
            y=-y;
        }
        double x=pow(y,1.0/3.0);
        if(flag==1){
            x=-x;
        }
        printf("%lf   %lf\r\n",x,x*x*x);

    }
    return 0;
}
-----------------------结果---------------------
song@song-virtual-machine:~/C_Program/interview_code$ ./test 
8
2.000000   8.000000
-8
-2.000000   -8.000000
-9
-2.080084   -9.000000
^C
song@song-virtual-machine:~/C_Program/interview_code$ 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值