《算法(第四版)》练习1-1答案

《算法(第四版)》练习答案,自己做的,记录一下~
如有错误,烦请不吝赐教!
很多代码题没写,其他的题25,31,32待做。

1-1-1.

a.7
b.200.0000002,没溢出,正常算就可以
c.true,因为&&的优先级高于||

1-1-2.

a.1.618,类型自动转换了,整型转换为浮点型
b.10.0,类型自动转换了,整型转换为浮点型
c.true,类型自动转换了,整型转换为浮点型,这里4.1>4.0也是true
d.33,类型自动转换了,转换为字符串,但是1和2还是能计算的,如果要得到字符串123可以尝试1+""+2+“3”,或者把1和2中的一个变为字符串类型,如"1"。

1-1-3.

命令行操作如图所示,代码见下。
命令行运行

public class Exercise1_1_3 {

    public static void main(String[] args) {
        Integer a = Integer.parseInt(args[0]);
        Integer b = Integer.parseInt(args[1]);
        Integer c = Integer.parseInt(args[2]);

        if(a==b&&b==c) System.out.println("equal");
        else System.out.println("not equal");
    }

}

1-1-4.

a.错误,then不是关键字,把then去掉。
b.正确
c.正确
d.错误,c=0后应该加分号。

1-1-5.
public static void main(String[] args) {
    double x=1,y=0.2;
    if(x>0&&x<1&&y>0&&y<1) StdOut.println("true");
    else StdOut.println("false");
}
1-1-6.

首先i是0到15,16次循环,输出16行。
然后每次循环内先输出f的值,再将f和g的值相加赋值给f。
再将已经被赋值为f+g的f减掉g后赋值给g。循环输出此规则产生的数列中的元素。
实际上,从循环开始,f记录的是前两个数相加的和,g记录的是上一次两数相加的和。
没错,这个循环计算得到的结果就是斐波那契数列(Fibonacci Sequence)。
an=a(n-1)+a(n-2)(n>=3,n∈N*)
而循环的过程如上所述,其实就是斐波那契数列产生的过程,从初始的两个数0和1开始的累加过程。

程序结果如下所示。

0
1
1
2
3
5
8
13
21
34
55
89
144
233
377
610
1-1-7.

第一段输出:3.00009

double t = 9.0;
while(Math.abs(t-9.0/t)>.001)
     t = (9.0/t+t)/2.0;
StdOut.printf("%.5f\n",t);

第二段输出499500
1+2+3+…+999 = 1000*499+500

int sum = 0;
for(int i=1;i<1000;i++)
    for(int j=0;j<i;j++)
        sum++;
StdOut.println(sum);

第三段输出10000

int sum = 0;
        for(int i=1;i<1000;i*=2)
            for(int j=0;j<1000;j++)
                sum++;
        StdOut.println(sum);
1-1-8.

第一个输出b,输出字符b。
第二个输出197,因为有加号,加号两边没有字符串,这里加号不是连接的作用,是相加的作用,所以输出的是b和c的ASCII码值的和。
第三个输出e,a的ASCII码值加上4转换为字符输出后是e。

System.out.println('b');
System.out.println('b'+'c');
System.out.println((char)('a'+4));
1-1-9.
String s="";
for(int n=N;n>0;n/=2)
    s = (n%2)+s;
1-1-10.

问题在于没有初始化数组a。
在Java中,未初始化就使用变量会报错,这与C++不同。
但是Java类的域会被初始化为默认值。

1-1-11.

略。

1-1-12.

这个地方原题目的第三个循环是输出i,应该是输出a[i],否则这个题目就没什么意义了。
下面是程序:

int[] a = new int[10];
for(int i=0;i<10;i++)
    a[i] =  9-i;
for(int i=0;i<10;i++)
    a[i] =  a[a[i]];
for(int i=0;i<10;i++)
    System.out.println(a[i]);

下面是答案,手写一下就明白了。

0
1
2
3
4
4
3
2
1
0
1-1-13.

略。

1-1-14.

输入从1开始。

public static int lg(int n){
        int temp=1;
        int res=0;
        while(temp<=n){
            temp *= 2;
            res++;
        }
        return res-1;
    }
1-1-15.
 public static int[] histogram(int a[],int M){
     int[] res = new int[M];
     for(int i=0;i<a.length;i++){
         if(a[i]<M) res[a[i]]++;
     }
     return res;
 }
1-1-16.

这是个递归程序,这个题没啥实际意义。
应该是为了理解:1.递归。2.加号做连接功能。这两点的。

public static String exR1(int n){
   if(n<=0) return "";
    return exR1(n-3) + n + exR1(n-2) + n;
}
1-1-17.

这段代码的出口永远调用不到,调用exR2(3)会产生调用exR2(0)和exR2(-3),循环往复直到发生java.lang.StackOverflowError

public static String exR2(int n){
    String s = exR2(n-3) + n + exR2(n-2) + n;
    if(n<=0) return "";
    return s;
}
1-1-18.

mystery(2,25)输出50。
mystery(3,11)输出33。
+换*后的结果为:
33554432
177147
这里说一下第一个结果的过程,其他类似:

mystery(2,25)
mystery(2+2,25/2)+2
mystery(4+4,12/2)
mystery(8+8,6/2)
mystery(16+16,3/2)+16
mystery(32+32,1/2)+32
最终结果32+16+2=50
public static int mystery(int a,int b){
    if(b==0) return 0;
    if(b%2 == 0) return mystery(a+a,b/2);
    return mystery(a+a,b/2) + a;
}
1-1-19.

下面原始程序的问题在于重复计算,每次的结果没有保存,比如计算F(4)的时候实际上F(3)的结果又重新算了一遍。

public static long F(int N){
    if(N==0) return 0;
    if(N==1) return 1;
    return F(N-1)+F(N-2);
}

下面是改进的代码,其实就是把中间结果保存了一遍。
最后结果是溢出的,但是速度很快,1秒左右就运行完毕了。

static long[] F_temp = new long[100];
public static long F(int N){
    if(N==0) return 0;
    if(N==1) return 1;
    if(F_temp[N]!=0) return F_temp[N];
    return F(N-1)+F(N-2);
}

public static void main(String[] args){
    for(int N=0;N<100;N++){
        StdOut.println(N+" "+F(N));
        F_temp[N] = F(N);
    }
}
1-1-20.

根据对数运算法则:ln(MN) = lnM + lnN,所以递归把阶乘写成和的形式就可以了。
写递归就注意怎么把问题划分为子问题和出口就可以了。

public static double ln(int N){
    if(N==1) return 0;
    return Math.log(N)+ln(N-1);
}
1-1-21.

略。

1-1-22.

加一个参数记录深度即可。

    public static int rank(int key,int[] a)
    {   return rank(key,a,0,a.length-1,0);}

    public static int rank(int key,int[] a,int lo,int hi,int deep)
    {   //如果key存在于a[]中,它的索引不会小于lo且不会大于hi
        StdOut.println(lo+" "+hi+" "+deep);
        if(lo>hi) return -1;
        int mid = lo+(hi-lo)/2;
        if(key<a[mid]) return rank(key,a,lo,mid-1,deep+1);
        else if(key>a[mid]) return rank(key,a,mid+1,hi,deep+1);
        else return mid;
    }
1-1-23.

略。

1-1-24.

如何从命令行接受参数见第三题,这里不再赘述接受命令行参数的算法。

 public static int gcd(int p,int q)
 {
     StdOut.println(p+" "+q);//添加这一行输出p和q的中间结果
     if(q==0) return p;
     int r = p%q;
     return gcd(q,r);
 }

105和24的计算结果如下。

105 24
24 9
9 6
6 3
3 0
3

1111111和1234567的最大公约数运行结果为1,说明两数互质。

1111111 1234567
1234567 1111111
1111111 123456
123456 7
7 4
4 3
3 1
1 0
1
1-1-25.

待做。

1-1-26.

第一个判断排列a和b,把最小的放在位置a,第二个判断排列a和c,把较小的放在a。
这样经过两个判断后,位置a的数字是三个里最小的,这时候把b和c位置的数字比较一下就可以了。

1-1-27.

递归层数100层,每层调用两个递归调用,次数在2^100数量级。
保存中间结果的代码略,可以参考19题。

1-1-28.

略。

1-1-29.

略。找到值之后中心扩散一下就可以了。

1-1-30.

略。结合欧几里得算法判断一下就可以了。

1-1-31.

待做。

1-1-32.

待做。

1-1-33.

略。

1-1-34.

1.只需要两个变量记录最大最小值更新。
2.需要记录所有值。
3.需要记录k个值的数组。
4.使用一个变量累加。
5.使用一个变量累加,一个变量计数,来计算平均值。
6.需要记录所有的数。
7.需要记录所有的数。
8.需要记录所有的数。

1-1-35.

注释的代码是准确概率,未注释的代码是模拟掷骰子。
大约N为50000左右比较准确,

public static void main(String[] args){
    int SLIDES = 6;
    int N = 1000000;
    Random r = new Random();
    int i1,i2;
    double[] dist = new double[2*SLIDES+1];
    for(int i=0;i<N;i++)
    {
        i1 = r.nextInt(6)+1;
        i2 = r.nextInt(6)+1;
        dist[i1+i2] += 1.0;
    }
    for(int i=2;i<=2*SLIDES;i++)
    {
        dist[i] /= 1000000.0;
    }
    System.out.println(dist[2]);

//        int SLIDES = 6;
//        double[] dist = new double[2*SLIDES+1];
//        for(int i=1;i<=SLIDES;i++)
//            for(int j=1;j<=SLIDES;j++)
//                dist[i+j] += 1.0;
//        for(int k=2;k<=2*SLIDES;k++)
//            dist[k] /= 36.0;
//        System.out.println(dist[2]);
}
1-1-36.

略。

1-1-37.

略。

1-1-38.

略。

1-1-39.

略。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值