Algorithms(第四版)1.1課後練習答案(我的整理)

最近着手學習Robert Sedgewick的Algorithms這本書,開始作習題時發現配套網站上對應的習題答案並不徹底,google後發現github以及有些人的博客上有部分答案,不過通常只作了第一章節的題目,大概是題目太多了的緣由,在此本身整理本身所作的一份答案,但願有同行的人一塊兒交流,分享。html


練習

1.1.1
a.7
b.200.0000002
c.truejava

1.1.2
a.1.618
b.10.0
c.true
d.33git

1.1.3
須要添加對應官方網站上所提供的標準輸入庫函數StdIn.javagithub

package Chapter1;

import edu.princeton.cs.algs4.*;

public class prac1_1_3 {
    public static void main(String[] args) {
        int a=StdIn.readInt();
        int b=StdIn.readInt();
        int c=StdIn.readInt();
        if(a==b&&a==c)
            System.out.println("equal");
        else
            System.out.println("not equal");
    }
}

1.1.4
a.多餘了then(VB有這種語法)
b.a>b缺乏()
c.正確
d.c=0缺乏;算法

1.1.5shell

package Chapter1;

import edu.princeton.cs.algs4.*;

public class parc1_1_5 {
    public static void main(String[] args) {
        double x=StdIn.readDouble();
        double y=StdIn.readDouble();
        
        if(x>=0&&x<=1&&y>=0&&y<=1)
            System.out.println(true);
        else
            System.out.println(false);
    }
}

1.1.6
一段Fibonacciwindows

0
1
1
2
3
5
8
13
21
34
55
89
144
233
377
610數組

1.1.7
a.3.00009 應該是計算算數平方根
b.499500 計算 1+2+3+...+999也就是(1+999)*999/2
c.10000 1000*10,就外循環來看一共十個輪迴(2^0,2^1,...,2^9=512<1000,2^10=1024>1000,而內循環每次執行1000次)ide

1.1.8 (考察 ASCII表格 )
a.b
b.197 (默認是會轉換爲相加後的數字輸出)
c.e函數

1.1.9

package Chapter1;

import edu.princeton.cs.algs4.*;

public class prac1_1_9 {

    public static void main(String[] args) {
        int N;
        //count the binary form of N
        while((N=StdIn.readInt())>0){
            String s="";
            while(N/2!=0){
                s+=(N%2);
                N/=2;
            }
            s+="1";
            //reverse the string s            
            char[] ch=new char[s.length()];            
            for(int i=0;i<s.length();++i){
                ch[i]=s.charAt(s.length()-i-1);
            }            
            System.out.println(ch);
        }
    }
}

【仍是思惟造成定勢了,基本運算一致,不曾想從右邊加,就像鏈表的頭插尾插同樣】
附課本源代碼

String s="";
for(int n=N;n>0;n/=2)
   s=(n%2)+s;

1.1.10

在新建一個數組時未給該數組用new分配內存,會產生 variable a might not have been initialized的編譯錯誤

1.1.11

package Chapter1;

public class prac1_1_11 {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        boolean[][] array={{true,false,false},{false,false,true},{true,false,true}};
        //print the column number
        System.out.print(" ");
        for(int i=0;i<array[0].length;++i){
            System.out.print(i+1);
        }
        System.out.println();
        
        for(int i=0;i<array.length;++i){
            //print the row number
            System.out.print(i+1);
            //print the boolean element
            for(int j=0;j<array[i].length;++j){
                if(array[i][j]==true)
                    System.out.print("*");
                else
                    System.out.print(" ");
            }
            //start a new row
            System.out.println();
        }
    }

}

關於這個題不知道個人理解是否正確,由於和網上查到的另外一個朋友的答案不同,他是直接輸出每個位置+元素,而個人理解是仍保持矩陣的形式將對應的boolean值替換爲'*'和‘ ’,並輸出行號,列號,因爲沒有標準答案,見仁見智吧

別人的結果以及原連接
別人的結果
我我的的對應的結果
個人結果

1.1.12
1.1.12輸出結果

1.1.13

package Chapter1;

public class prac1_1_13 {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        int[][] a={{1,2,3},{7,5,1}};
        //print 2D array
        System.out.println("before transfer");
        printArray(a);
        System.out.println("after transfer");
        //transfer the 2D array
        printArray(transferArray(a));
    }
    
    public static void printArray(int[][] a){
        for(int i=0;i<a.length;++i){
            for(int j=0;j<a[i].length;++j){
                System.out.print(a[i][j]+" ");
            }
            System.out.println();
        }
    }
    
    public static int[][] transferArray(int[][] a){
        int[][] newArray=new int[a[0].length][a.length];
        for(int i=0;i<newArray.length;++i){
            for(int j=0;j<newArray[i].length;++j){
                newArray[i][j]=a[j][i];
            }
        }
        return newArray;
    }

}

1.1.14

package Chapter1;

import edu.princeton.cs.algs4.*;

public class prac1_1_14 {

    public static void main(String[] args) {
        int N=StdIn.readInt();
        System.out.println(lg(N));
    }
    
    public static int lg(int N){
        int lg=0;
        for(int i=0;i<N;++i){
            if(myPow(2,i)<=N&&myPow(2,i+1)>N){
                lg=i;
                break;
            }
        }
        return lg;
    }
    
    public static int myPow(int m,int n){
        int temp=m;
        while(--n>0){
            m*=temp;
        }
        return m;
    }

}

1.1.15

package Chapter1;

public class prac1_1_15 {

    public static void main(String[] args) {
        int[] testArray={1,1,2,3,1,7,5,3,2,2,2};
        System.out.println("histogram result");
        printArray(histogram(testArray, 8));
    }
    
    public static int[] histogram(int[] a,int M){
        int[] hArray=new int[M];
        for(int i=0;i<M;++i){
            int count=0;
            for(int j=0;j<a.length;++j){
                if(i==a[j]){
                    count++;
                }
            }
            hArray[i]=count;
        }
        return hArray;
    }
    
    public static void printArray(int[] a){
        for(int i=0;i<a.length;++i){
            System.out.println("a["+i+"]: "+a[i]);
        }
    }

}

1.1.16
311361142246

1.1.17

該代碼中的基礎狀況永遠不會被調用,由於調用exR2(3)會產生調用exR2(0),exR2(-3)和exR2(-6),循環往復直至產生StackOverflowError.

1.1.18
乘法的遞歸實現
mystery(2,25)=50
mystery(3,11)=33
mystery(a,b)=a*b
修改後結果:
乘方的遞歸實現
mystery(a,b)=a^b

1.1.19

package Chapter1;

public class prac1_1_19 {

    public prac1_1_19() {
        int[] F = new int[100];
        F[0] = 0;
        F[1] = 1;
        for(int i=2;i<100;++i)
            F[i]=F[i-1]+F[i-2];
        System.out.println(F[30]);
    }

    public static void main(String[] args) {
        prac1_1_19 test=new prac1_1_19();

    }

}

1.1.20

package Chapter1;

import java.lang.Math;
import edu.princeton.cs.algs4.*;

public class prac1_1_20 {

    public static void main(String[] args) {
        int N=StdIn.readInt();
        System.out.println(ln(N));
    }

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

因爲此題考察遞歸,因此對於ln的計算是調用Math裏的現成庫

1.1.21

package Chapter1;

import edu.princeton.cs.algs4.*;

public class prac1_1_21 {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        while(StdIn.hasNextLine()){
            String name=StdIn.readString();
            int m=StdIn.readInt();
            int n=StdIn.readInt();
            StdOut.printf("%8s | %8d | %8d | %8.3f", name,m,n,(m*1.0)/n);
        }    
    }
}

1.1.22

package Chapter1;

public class prac1_1_22 {
    
    
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        int[] array={1,3,5,7,9};
        int location=rank(3,array,0);
        if(location<0)
            System.out.println("key not found");
        else
            System.out.println("key location="+(location+1));

    }

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

    private static int rank(int key, int[] a, int lo, int hi,int dep) {
        // TODO Auto-generated method stub
        for(int i=0;i<dep;++i)
            System.out.print(" ");
        System.out.println("low: "+lo+" high: "+hi);
        dep++;
        if (lo > hi)
            return -1;
        int mid = (lo + hi) / 2;
        if (key < a[mid])
            return rank(key, a, lo, mid - 1,dep);
        else if (key > a[mid])
            return rank(key, a, mid + 1, hi,dep);
        else
            return mid;
    }
}

1.1.23

折騰了大半天,最後找到別人的一份代碼應該是符合條件的

/**
 * 二分查找 : 非遞歸描述
 * @param key   關鍵字
 * @param arr   數組
 * @return  若找到則返回true,不然返回false
 */
public static boolean BinaryLookup(int key, int[] arr) {
    int low = 0;
    int high = arr.length - 1;
    while(low <= high) {
        int mid = low + ((high - low) >> 1);
        if(key < arr[mid])
            high = mid - 1;
        else if(key > arr[mid])
            low = mid + 1;
        else
            return true;
    }
    return false;
}

public static void main(String[] args) {
    // 「 + 」 --> 打印出標準輸入中不在白名單上的值,
    // 「 - 」 --> 打印出標準輸入中在白名單上的值
    char symbol = '-';
    int[] whitelist = new In(args[0]).readAllInts();
    Arrays.sort(whitelist);
    while(!StdIn.isEmpty()) {
        int key = StdIn.readInt();
        boolean found = BinaryLookup(key, whitelist);
        if('+' == symbol && !found)
            StdOut.println(key);
        if('-' == symbol && found)
            StdOut.println(key);
    }
}

不過須要注意的是,在windows的環境下的控制檯直接調用書上的命令是行不通的,首先是調用了書上一直在提的 algs4.jar,而後是須要從命令行讀取文件進行比對,而windows控制檯是無法運行書上所述的

java xxx largeW.txt < largeT.txt

即便將須要用到的做者寫好的庫放在java文件的同一目錄下也會產生以下異常
圖片描述
多是命令行不支持「<」命令吧,由於最近聯繫到這段代碼的做者,發現他是在Linux系統下編譯執行的,聽說是沒問題。

通過一番查找,最終我發現有一種方法是用本書做者開發的一套控制檯程序,而後按照該鏈接的操做,使用以下指令進行編譯和運行才能夠成功

javac-algs4 xxx.java  //編譯指令

java-algs4 xxx largeW.txt < largeT.txt    //執行指令

固然注意其中的largeW.txtlargeT.txt也來自相應網站的data文件裏,須要放到和java文件相同目錄

【更新】後來我在stackoverflow上提問,有人解答了,在windows上的命令應該是這樣的

Get-Content tinyT.txt | java prac1_1_23 tinyW.txt

不過比較奇怪的是,用原始的largeW.txtlargeT.txt的話PowerShell就直接崩潰了,應該是數據量過大的緣故吧,可是用所提供的CLI卻是能夠跑

【更新】此外,cmd是能夠直接執行的,另一種方法是把命令寫爲'.bat'文件而後執行該文件,效果相似,卻是破除了PowerShell必定優於cmd的封建迷信了,stackoverflow上的朋友仍是至關熱心嚴謹那~

【更新】若堅持使用powershell,stackoverflow上有人提出能夠用以下指令,親測有效

cmd /c --% java prac1_1_23 largeW.txt < largeT.txt

如有更好的方法還但願能不吝賜教

1.1.24

package Chapter1;

import edu.princeton.cs.algs4.*;

public class prac1_1_24 {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        while(StdIn.hasNextLine()){
            int x=StdIn.readInt();
            int y=StdIn.readInt();
            StdOut.println("the greatest common divisor of "+x+" and "+y+" is: "+gcd(x,y));
        }
    }
    
    public static int gcd(int a,int b){
        StdOut.println(a+" "+b);
        int m=max(a,b);
        int n=min(a,b);
        if(m%n==0)
            return n;
        else
            return gcd((m%n),n);
    }
    
    public static int max(int a,int b){
        if(a>=b)
            return a;
        else
            return b;
    }
    
    public static int min(int a,int b){
        if(a>=b)
            return b;
        else
            return a;
    }

}

輸出結果以下
最大公約數
考慮到讓用戶輸入不必定按先大後小的順序輸入因此加入了一點預處理

1.1.25
網上找的證實1,證實2


提升題

1.1.26
本質上是在說java裏的變量的值的交換的算法,須要第三個數來進行臨時存儲從而完成交換,其實也有另外一種方法,經過兩次異或運算‘^’完成交換操做

a=a^b;
b=b^a;   //此時b變爲a
a=a^b;    //此時a變爲b

1.1.27
第一問是向遞歸函數裏添加了一個計數器參數,使用了第二節的現有的計數器類,每次調用遞歸時即遞增一次,代碼以下:

package Chapter1;

import Chapter1.Counter;
import edu.princeton.cs.algs4.StdOut;

public class prac1_1_27 {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        int n=Integer.parseInt(args[0]),
            k=Integer.parseInt(args[1]);
        double p=Double.parseDouble(args[2]);
        
        Counter c=new Counter("calls");
        double b=binomial(n,k,p,c);
        
        StdOut.println(b);
        StdOut.println(c);
        
    }
    
    public static double binomial(int N, int k, double p,Counter c){
        double[][] a=new double[N+1][k+1];
        for(int i=0;i<=N;++i){
            for(int j=0;j<=k;++j){
                a[i][j]=-1;
            }
        }
        return binomial(a,N,k,p,c);
    }

    private static double binomial(double[][] a, int N, int k, double p, Counter c) {
        if(N==0&&k==0)
            return 1.0;
        if(N<0||k<0)
            return 0.0;
        if(a[N][k]==-1){
            c.increment();
            a[N][k]=(1.0-p)*binomial(a,N-1,k,p,c)+p*binomial(a,N-1,k-1,p,c);
        }
        return a[N][k];
    }

}

第二道題是用空間換時間的應用,用二維數組來存取所計算的機率值,這樣之後計算某一律率的值時可直接從數組中讀,而沒必要重複計算前面已經計算過的值;

package Chapter1;

import Chapter1.Counter;
import edu.princeton.cs.algs4.StdOut;

public class prac1_1_27 {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        int n=Integer.parseInt(args[0]),
            k=Integer.parseInt(args[1]);
        double p=Double.parseDouble(args[2]);
        
        Counter c=new Counter("calls");
        double b=binomial(n,k,p,c);
        
        StdOut.println(b);
        StdOut.println(c);
        
    }
    
    public static double binomial(int N, int k, double p,Counter c){
        double[][] a=new double[N+1][k+1];
        for(int i=0;i<=N;++i){
            for(int j=0;j<=k;++j){
                a[i][j]=-1;
            }
        }
        return binomial(a,N,k,p,c);
    }

    private static double binomial(double[][] a, int N, int k, double p, Counter c) {
        if(N==0&&k==0)
            return 1.0;
        if(N<0||k<0)
            return 0.0;
        if(a[N][k]==-1){
            c.increment();
            a[N][k]=(1.0-p)*binomial(a,N-1,k,p,c)+p*binomial(a,N-1,k-1,p,c);
        }
        return a[N][k];
    }

}

參考1參考2

1.1.28
這道題個人想法是遍歷已排序後的數組逐一判斷元素是否和前一元素相同,若不相同則用一個list來收集,最後利用list的內置方法直接將list轉換爲數組便可

public static Integer[] distinctArray(int[] whitelist) {
        List<Integer> list=new ArrayList<>();
        list.add(whitelist[0]);
        for(int i=1;i<whitelist.length;++i){
            if(whitelist[i]!=whitelist[i-1])
                list.add(whitelist[i]);
        }
        
        Integer[] newWhitelist=list.toArray(new Integer[list.size()]);
        return newWhitelist;
    }

對應的主函數以下

public static void main(String[] args) {
        // TODO Auto-generated method stub
//        int[] whitelist=In.readInts(args[0]);
        int[] whitelist={1,3,3,3,5,6,6,7,};
        Arrays.sort(whitelist);
        for(int i=0;i<whitelist.length;++i)
            System.out.print(whitelist[i]+" ");
        
        System.out.println();
        
        Integer[] newWhitelist = distinctArray(whitelist);
        for(int i=0;i<newWhitelist.length;++i)
            System.out.print(newWhitelist[i]+" ");
        
        
//        while(!StdIn.isEmpty()){
//            int key=StdIn.readInt();
//            if(rank(key,whitelist)<0)
//                StdOut.println(key);
//        }
    }

1.1.29
這道題我一開始想簡單了就直接遍歷了,卻不知既然是寫在二分查找這一類中的方法天然應該利用二分查找的方式去提升效率,正確的作法是對以前尋找到middle的部分進行修改

package Chapter1;

public class prac1_1_29 {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        int[] a={1,2,3,3,3,4,5,5,6,8};
        int i=rank(3,a);
        int j=count(3,a);
        System.out.println(i+" "+j);
//        for(int k=i;k<=i+j-1;++k){
//            System.out.print(a[k]+" ");
//        }
    }
    
    public static int rank(int key,int[] array){
        int low=0; 
        int high=array.length-1;
        while(low<=high){
            int    middle=(low+high)>>1;
            if(key<array[middle])
                high=middle-1;
            else if(key>array[middle])
                low=middle+1;
            else if(key==array[middle]){
                while(middle>0&&array[middle]==key)
                    middle--;
                return middle+1;
            }                
        }
        return -1;
    }
    
    public static int count(int key,int[] array){
        int count=0;
        int lower=rank(key,array);
        for(int i=lower;i<array.length;++i){
            if(array[i]==key)
                count++;
        }
        return count;
    }
}

1.1.30
判斷是否互質,我的是事先判斷了下兩個數的大小以便進行遍歷

package Chapter1;

public class prac1_1_30 {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        boolean[][] a=new boolean[3][19];
        for(int i=0;i<a.length;++i){
            for(int j=0;j<a[i].length;++j){
                a[i][j]=rel_prime(i,j);
            }
        }
        
        for(int i=0;i<a.length;++i){
            for(int j=0;j<a[i].length;++j){
                System.out.print(a[i][j]+" ");
            }
            System.out.println();
        }        
    }

    public static boolean rel_prime(int i,int j){
        if(i>j){
            i=i^j;
            j=j^i;
            i=i^j;
        }
        for(int k=2;k<=i;k++)
            if(j%k==0&&i%k==0)
                return false;
        return true;
    }
}

測試結果
圖片描述


實驗題

相關文章
相關標籤/搜索