5.1.1 WERTYU
虽然可以用if else或者switch进行这种变换,但是这样是非常麻烦的,会存在很多的分支,显得程序很臃肿。
一个优雅的解决方法是采用常量数组的方式。
#include<stdio.h>
char *s = "`1234567890-=qwertyuiop[]asdfghjkl;'\zxcvbnm,./"; // 常量数组能够很好解决按键位移问题
int main(){
int i,c;
while((c=getchar())!=EOF){
for(i=1; s[i] && c!=s[i]; i++);
if(s[i]) putchar(s[i-1]); // 如果是以上s字符串里面的字符,可以变成它的前一个
else putchar(c); // 否则,空格等别的占位符,保持不变
}
return 0;
}
5.1.3 周期串问题
#include<stdio.h>
#include<string.h>
int main(){
char word[100];
scanf("%s",word); // %s要求的是一个地址,字符串的名字就是第一个字符的地址
int len = strlen(word);
for(int i=1; i<len; i++) // 第一个循环是确定循环节的大小
if(len%i==0){
int ok=1;
for(int j=i; j<len; j++){ // 第二个循环是确保每个小节内容一致
if(word[j]!=word[j%i]){ ok=0; break; }
}
// i是从小开始的递增的,因此只要找到第一个ok的周期就可以收工break了
if(ok){ printf("%s",word); break; }
}
}
5.2.1 小学生算术
#include<stdio.h>
int main(void) {
int a, b;
scanf("%d%d",&a,&b);
if(!a && !b) return ;
int c=0, ans=0;
for(int i=9; i>=0; i--){ // 最高为九位,因此需要进行9次(除以10的)循环
c=(a%10 + b%10 + c) > 9 ? 1 : 0; // c负责保存进位
// 注意,当前位数a、b两者相加时还要考虑小一倍数的进位
ans +=c; // 每次有进位就记入ans
a/=10;
b/=10;
printf("%d",c);
}
printf("%d",ans);
}
5.2.2 阶乘的精确值
#include<stdio.h>
#include<string.h>
const int maxn = 3000;
int main(void) {
int f[maxn]; // 定义数组,由于1000!约等于4*10^2567,因此数组可以取3000位
int n, j, i;
scanf("%d",&n);
memset(f,0,sizeof(f)); // 将f从f[0]到f[2999]全部置零
f[0]=1; // 对于n<2的那两个阶乘,结果均为1,这也是为什么i要从2开始
for(i=2; i<=n; i++){
int c=0;
for(j=0; j<maxn; j++){ // 将f从f[0]到f[2999]每一位手动乘一遍i
int s=f[j]*i+c; // 乘完得出来的数为s
f[j] = s%10; // 取s的个位当作当前第j位的数字
c = s/10; // s的十位作为大一位数的进位
}
}
for(j=maxn-1; j>=0; j--) if(f[j]) break; // 从后往前数,直到第一个非零数字出现,也是乘积的最大位数
for(i=j; i>=0; i--){ // 逆序表示,个位是f[0]、十位是f[1]……,方便进位,但是输出时要从后往前输出
printf("%d",f[i]);
}
printf("\n");
}
然后以下就是根据上面阶乘的原理用java做出来的大数乘法器:
import java.util.Scanner;
public class Main {
// inspired by ‘5.2.2阶乘的精确值’ 的 乘法器
public static void main(String[] args) {
final int maxn=3000;
int[] f = new int[maxn];
int i, j, carry;
Scanner s = new Scanner(System.in);
String a = s.next();
String b = s.next();
// System.out.print("a="+a+", b="+b+"\n");
int len_a = a.length();
int len_b = b.length();
// System.out.print("a.len="+len_a+", b.len="+len_b+"\n");
// f全部置零
for(int k=len_a-1; k>=0; k--){
f[k] = 0;
}
//倒序,从低位(个位)开始计算,为了方便计算进位,将数组f的下标低位设置为结果的低位
for(i=len_a-1; i>=0; i--){
for(j=len_b-1; j>=0; j--){
// 个位是0,十位是1...这样第i+j位就是两个当前被乘数的和所在的位置(乘法笔算)
f[(len_a-i-1)+(len_b-j-1)]+=(a.charAt(i)-'0')*(b.charAt(j)-'0');
}
}
// 把数组f中原先保留的数现在变成个位数,通过进位
for(i=0; i<len_a+len_b-1; i++){
carry = f[i]/10;
f[i] = f[i]%10;
f[i+1] += carry;
}
j=maxn-1;
// for循环的作用仅仅是让j从后向前移动,消除首位零,直到第一个非零项
for(; j>=0; j--) {
if(f[j]!=0) {
break;
}
}
for(i=j; i>=0; i--){
System.out.print(f[i]);
}
}
}
这个大数乘法器能够实现超过2^31(Integer的尺寸)的数字的乘法