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:10520=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$