算法 第四版 习题 答案 笔记 1.1

1.1.1  给出以下表达式的值: 

a. ( 0 + 15 ) / 2 

b. 2.0e-6 * 100000000.1 

c. true && false || true && true 

分析:

a. 表达式值默认为int,15/2 时取整等到结果 7

b.表达式等价于2.0e-6 * 100000000.1d ,默认为double,所以计算结果为 200.0000002  

c.&&优先级高于||,表达式等价于(true && false) || (true && true), 计算结果为true

1.1.2 给出以下表达式的类型和值: 

a. (1 + 2.236)/2 

b. 1 + 2 + 3 + 4.0 

c. 4.1 >= 4

d. 1 + 2 + "3"

分析:

不同类型进行计算时,默认转换为相对范围更大的类型

a, 此处默认转换为double,计算结果为1.618

b,此处默认转换为double,计算结果为10.0

c,此处默认转换为double,比较结果为true

d,表达式从左至右计算,等价于(1+2)+"3",结果为"33"

1.1.3  编写一个程序,从命令行得到三个整数参数。如果它们都相等则打印equal,否则打印not equal
分析:本题应该是为了熟悉一下,输入输出,结果如下
	public static void  checkNumber()
	{
		StdOut.print("input three number:");
		int i1=StdIn.readInt();
		int i2=StdIn.readInt();
		int i3=StdIn.readInt();
		if(i1==i2&&i2==i3)
		{
			StdOut.println("equal");
		}else
		{
			StdOut.println("not equal");
		}
	}
1.1.4 下列语句各有什么问题(如果有的话)?
a. if (a > b) then c = 0; 
b. if a > b { c = 0; } 
c. if (a > b) c = 0;  
d. if (a > b) c = 0 else b = 0
分析:考验Java基本语法
a.其中then非Java关键字
b.条件必须使用“()” 包含
c.没问题
d.赋值语句必需以分号“;”结束
1.1.5  编写一段程序,如果double 类型的变量x 和y 都严格位于0 和1 之间则打印true,否则打印false
分析:熟悉类型比较
	public static void cmpDouble(double x,double y)
	{
		if(0<x&&x<1&&0<y&&y<1)
		{
			StdOut.println("true");
		}else
		{
			StdOut.println("false");
		}
	}
1.1.6 下面这段程序会打印出什么? 
int f = 0; 
int g = 1;  
for (int i = 0; i <= 15; i++)
{  
	StdOut.println(f);
	f = f + g; 
	g = f - g; 
}
分析:将代码分解为如下:
int f = 0 , f1 = 0; 
int f0 = 1;  
for (int i = 0; i <= 15; i++)
{  
	StdOut.println(f);
	f1 = f + f0; 
	f0 = f;f=f1; 
}
不难看出数列的结果 {f , g ,... } 中下一个数的值为当前值加上一个的值, 结果为 0  1 1  2  3 5 8 13 21 34 55 89 144 233 377 610
1.1.7 分别给出以下代码段打印出的值: 
a.double t = 9.0;  
while (Math.abs(t - 9.0/t) > .001) 
t = (9.0/t + t) / 2.0; 
StdOut.printf("%.5f\n", t); 
b.int sum = 0;  
for (int i = 1; i < 1000; i++) 
for (int j = 0; j < i; j++) 
sum++;  
StdOut.println(sum); 
c.int sum = 0;  
for (int i = 1; i < 1000; i *= 2) 
for (int j = 0; j < 1000; j++) 
sum++;  
StdOut.println(sum);
分析:
a.代码段计算结果比较明确是欧几里得开方计算,但是我也没想到快速得出结果的办法,只能硬算3.00009
b.代码段计算的是从1到999 的累加,通过(1+999) + (2+998) +...+(499+501)+500=499500
c.代码段计算,  1 - 1000 , 每次加1000,10次 
1.1.8 下列语句会打印出什么结果?给出解释。 
a. System.out.println('b'); 
b. System.out.println('b' + 'c'); 
c. System.out.println((char) ('a' + 4));
 分析:java方法重载
a.调用println(char c),输出b
b.'b'+'c' 等于197,调用println(int i),输出197
c.(char) ('a' + 4) 等于‘e’,调用println(char c),输出e
1.1.9 编写一段代码,将一个正整数N 用二进制表示并转换为一个String 类型的值s。
分析:实现如下
	public static String toBinaryString(int n)
	{
		String s="";
		for(int i=n;n>0;i/=2)
		{
			s=(i%2)+s;
		}
		return s;
	}
1.1.10 下面这段代码有什么问题?
  int[] a; 
  for (int i = 0; i < 10; i++) 
  a[i] = i * i;
分析:数组a没使用new初始化分配内存, java中需要new,c++中可以直接定义赋值
1.1.11  编写一段代码,打印出一个二维布尔数组的内容。其中,使用* 表示真,空格表示假。打印出行号和列号。
分析:基础,练习编码,实现如下
	public static void printBooleanArr()
	{
		//init
		boolean[][] bools=new boolean[10][10];
		for(int i=0;i<10;i++)
		{
			for(int j=0;j<10;j++)
			{
				bools[i][j]=StdRandom.bernoulli(0.5);
			}
		}
		//print
		for(int i=0;i<10;i++)
		{
			for(int j=0;j<10;j++)
			{
				if(bools[i][j])
				{
					StdOut.print("* ");
				}else
				{
					StdOut.print("  ");
				}
			}
			StdOut.println(" ");
		}
	}
1.1.12 以下代码段会打印出什么结果? 
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(i);
分析:本题应该主要考验仔细
(1)分析最后为System.out.println(i); 那么结果为0 1 2 3 4 5 6 7 8 9
(2)如果最后为System.out.println(a[i]);那么需要注意第二个循环到i=5时,a[a[5]]=a[4],此时a[4]已经在第二次循环中由5变为4了,后面的同理,结果为 0 1 2 3 4 4 3 2 1 0
1.1.13 编写一段代码,打印出一个M 行N 列的二维数组的转置(交换行和列)。
分析:实现代码如下,本例如果使用一个新的数组进行转换,实现比较简单,如果在原数组中进行交换,可能比较麻烦
	public static void printArr(int[][] arr)
	{
		StdOut.println("arr["+arr.length+"]["+arr[0].length+"]");
		for(int i=0;i<arr.length;i++)
		{
			for(int j=0;j<arr[i].length;j++)
			{
				StdOut.print(arr[i][j]+" ");
			}
			StdOut.println(" ");
		}
	}
	public static void revertArr(int m,int n)
	{
		int[][] a1=new int [m][n];
		int[][] a2=new int [n][m];
		//init
		for(int i=0;i<m;i++)
		{
			for(int j=0;j<n;j++)
			{
				a1[i][j]=StdRandom.uniform(10);
			}
		}
		//print
		printArr(a1);
		//revert
		for(int i=0;i<m;i++)
		{
			for(int j=0;j<n;j++)
			{
				a2[j][i]=a1[i][j];
			}
		}
		//print
		printArr(a2);
	}
1.1.14 编写一个静态方法lg(),接受一个整型参数N,返回不大于log2N 的最大整数。不要使用Math 库。
分析:题意换个方向思考为,2的M次幂<=N, 求m 的最大值,实现如下
	public static int lg(int n)
	{
		int m=0;
		for(int s=1;s<=n;s*=2)
		{
			m++;
		}
		return m;
	}
1.1.15  编写一个静态方法histogram(),接受一个整型数组a[] 和一个整数M 为参数并返回一个大小为M的数组,其中第i个元素的值为整数i在参数数组中出现的次数。如果a[]中的值均在0到M-1之间,返回数组中所有元素之和应该和a.length 相等。
分析:我想到两种实现方式,如下
	static int[] histogram(int arr[],int m)
	{
		int a[]=new int[m];
		for(int i=0;i<m;i++)
		{
			a[i]=0;//依次遍历
			for(int j=0;j<arr.length;j++)
			{
				if(arr[j]==i)
					a[i]++;
			}
		}
		
		return a;
	}
	static int[] histogram1(int arr[],int m)
	{
		int a[]=new int[m];
		for(int i=0;i<m;i++)
		{
			a[i]=0;
		}
		for(int j=0;j<arr.length;j++)//遍历依次
		{
			if(arr[j]>0&&arr[j]<m)
				a[arr[j]]++;
		}
		
		return a;
	}
1.1.16 给出exR1(6) 的返回值: 
public static String exR1(int n) 
{  
if (n <= 0) return "";  
return exR1(n-3) + n + exR1(n-2) + n; 
}
分析:目前未分析出其中规律,硬算得出如下结果
exR1(6)=                     exR1(3)       +6+                    exR1(4)           +6
                      =(exR1(0)+3+exR1(1)+3)+6+(exR1(1)+4+exR1(2)+4)  +6
                      = (""+3+(exR1(-2)+1+exR1(-1)+1)+3)+6+((exR1(-2)+1+exR1(-1)+1)+4+(exR1(-1)+2+exR1(0)+2)+4)  +6
     = "311361142246"
1.1.17 找出以下递归函数的问题: 
public static String exR2(int n) 
{  
String s = exR2(n-3) + n + exR2(n-2) + n;
if (n <= 0) return "";
return s;
}
分析:上面代码中递归赋值运算在条件判断赋值之前导致每次进入函数直接进入递归运算,直到发生StackOverflowError
1.1.18 请看以下递归函数:  
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;
}  
mystery(2, 25) 和mystery(3, 11) 的返回值是多少?给定正整数a 和b,mystery(a,b) 计算的结果是什么?
将代码中的+ 替换为* 并将return 0 改为return 1,然后回答相同 的问题。
分析:
给定正整数a 和b,mystery(a,b) 计算的结果是b个a相加,
b=0,mystery(a,b)=0
b%2=0,mystery(a,b)=mystery(2a,b/2)
b%2!=0,mystery(a,b)=mystery(2a,b/2)+a
不难理解当+换成*时,则表示b个a相乘
如此计算的主要目的是提高计算效率(mystery(a,b) 相对 a+a+a+...+a(b个a))

1.1.19 在计算机上运行以下程序:
public class Fibonacci {
public static long F(int N) {
if (N == 0)
return 0;
if (N == 1)
return 1;
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(N) 结果的最大N 值是多少?开发F(N) 的一 个更好的实现,用数组保存已经计算过的值。
分析:
F(N)计算的是以0,1 开头的一个队列值,F(N)=F(N-1)+F(N-2), 直接递归实现则如上,多递归嵌套计算效率较低,依次计算则如下,计算效率较高
	public static long F1(long n)
	{
		if(n==0)return 0;
		if(n==1)return 1;
		int s0=0,s1=1,s2=0;
		for(int i=2;i<=n;i++)
		{
			s2=s1+s0;
			s0=s1;
			s1=s2;
		}
		return s2;
	}
	public static long F2(long n,long a[])
	{
		
		if(n<0)return -1;
		a=new long[(int)n+1];
		a[0]=0;
		if(n==0)return 0;
		a[1]=1;
		if(n==1)return 1;
		int i=2;
		for(;i<=n;i++)
		{
			a[i]=a[i-1]+a[i-2];
		}
		return a[i];
	}
1.1.20 编写一个递归的静态方法计算ln(N!) 的值。
分析:
递归公式推导
(1)  ln(N!) =ln(n*((n-1)!))=ln(n)+ln((n-1)!)  
(2)  N!=N*((N-1)!) 
先算N!再算ln ,复杂度应该低些,所以递归实现时选择第二个公式好些,这里没找到直接计算ln的好方法
1.1.21  编写一段程序,从标准输入按行读取数据,其中每行都包含一个名字和两个整数。然后用printf() 打印一张表格,每行的若干列数据包括名字、两个整数和第一个整数除以第二个整数的结果,精确到小数点后三位。可以用这种程序将棒球球手的击球命中率或者学生的考试分数制成表格。
分析:
该题应该没什么特别的,主要就是熟悉api和编码






展开阅读全文

没有更多推荐了,返回首页