算法4习题答案

习题答案
jimmysuncpt做的习题答案
国外做的习题答案

原书例子
知乎原始网站
如何学习算法

2022年1月1日
书本:15-24页
习题:递归1.1.16,17, 18,共3题;牛客NC115栈和排序
笔记:
程序简便记法
1)声明语句和赋值语句结合起来,如int i=1;
2)隐式赋值:①递增,如i++;②符合运算符,如i+=2,将变量放在等号左边作为第一个操作数
3)条件或循环语句只有一条语句,省略大括号
4)用for语句替换while语句,因为while循环包括3部分:初始化索引变量,包含索引变量的循环条件,while循环最后一条语句将索引变量加1
数组
1)创建数组的三步:①声明数组的类型和名称;②创建数组;③初始化数组元素
2)简化写法:①等号左侧声明数组,等号右侧创建数组。double类型数组默认初始化为0.0;int类型数组初始化为0;boolean类型数组,初始化为false。②等号左侧声明数组,等号右侧花括号包括逗号分隔的值。
3)复制数组:①数组变量赋值给另一个变量,结果是两个变量指向同一个数组;②复制数组需要将元素全部复制
4)数组作为参数:方法参数按值传递,意味着参数是原数组的别名,方法使用参数变量能改变原数组(调用者)的内容
5) 对象数组定义需要类型转换,Item[] item = (Item[]) new Object[3]
方法
1)方法包括静态方法和实例方法
静态方法的例子:

    /**
     * 判断一个数是否为素数
     */
    public static boolean isPrime(int N){
        if(N<2) return false;
        for(int i=2;i*i<N;i++)
            if(N%i==0) return false;
        return true;
    }

    /**
     * 牛顿迭代法求平方根
     * 参考:https://www.cnblogs.com/qlky/p/7735145.html
     */
    public static double sqrt(double c){
        if(c<0) return Double.NaN;
        double err = 1e-15;
        double t =c;
        while(Math.abs(t-c/t)>t*err){
            t=(c/t+t)/2.0;
        }
        return t;
    }

    /**
     * 计算调和级数
     * @param N
     * @return
     */
    public static double H(int N){
        double sum = 0.0;
        for(int i=1;i<=N;i++) sum+=1/i;
        return sum;
    }

2)方法性质
①方法的参数按值传递,引用类型变量参数是别名,方法中使用参数会改变原对象的值
②方法名可以被重载,一个函数需要变量,另一个函数使用默认值
③方法只有一个返回值,如果返回多个值时,可返回引用类型变量
④方法调用自己就是递归
⑤外部库
<1>系统标准库java.lang.*包括Math库,Integer库等,不需要import
<2>系统库,比如java.util.Arrays,需要import导入
<3>其他库,需要import导入
递归代码编写注意三点:
<1>方法第一条语句为包含return的简单条件语句
<2>递归的参数范围不断缩小,递归需要收敛到最简单的情况
<3>递归调用父问题和子问题不应该有交集

    /**
     * 重载:有序数组二分查找的递归实现
     */
    public static int rank(int key,int[] a){
        return rank(key,a,0,a.length-1);
    }
    /**
     * 有序数组二分查找的递归实现
     */
    public static int rank(int key, int[] a,int lo,int hi){
        if(lo>hi) return -1;
        int mid = lo+(hi-lo)/2;
        if(key<a[mid]) return rank(key,a,lo,mid-1);
        else if(key>a[mid]) return rank(key,a,mid+1,hi);
        else return mid;
    }
    /**
     * 优化:有序数组二分查找的递归实现
     */
    public static int betterRank(int key,int[] a){
        int lo =0;
        int hi = a.length-1;
        while(lo<=hi){
            int mid = lo+(hi-lo)/2;
            if(key<a[mid]) hi =mid-1;
            else if(key>a[mid]) lo= mid+1;
            else return mid;
        }
        return -1;
    }

    /**
     * 缩进打印递归调用参数:二分查找
     */
    public static int rank(int key,int[] a,int lo,int hi,int depth){
        for (int i = 0; i < depth; i++) {
            System.out.printf("  ");
        }
        System.out.println("lo=" + lo + ", hi=" + hi);

        if(lo>hi) return -1;
        int mid = lo+(hi-lo)/2;
        if(key<a[mid]){
            return rank(key,a,mid-1,hi,depth + 1);
        }else if(key>a[mid]){
            return rank(key,a,mid+1,hi,depth + 1);
        }else{
            return mid;
        }
    }

3)优化递归
优化递归方法:使用数组存储中间值减少重复计算
习题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) 的一个更好的实现,用数组保存已经计算过的值。
答案

        public static long F2(int N){
            long[] res = new long[N+1];
            if(N==0) return res[0];
            res[1]=1;
            if(N==1) return res[1];
            for(int i=2;i<=N;i++) res[i]=res[i-1]+res[i-2];
            return res[N];
        }

习题1.1.27
二项分布。估计用以下代码计算binomial(100, 50,0.25)将会产生的递归调用次数:

public static double binomial(int N, int k, double p) {
    if (N == 0 && k == 0) return 1.0;
    if (N < 0 || k < 0) return 0.0;
    return (1.0 - p) * binomial(N - 1, k, p) + p * binomial(N - 1, k - 1, p);
}

将已经计算过的值保存在数组中并给出一个更好的实现
答案

    public static double betterBinomial(int N,int k,double p){
        double[][] res = new double[N+1][k+1];
        for(int i=0;i<N;i++){
            res[i][0]=Math.pow(1-p,i);
        }
        for(int i=1;i<=N;i++){
            for(int j=1;j<=k;j++){
                res[i][j]=(1-p)*res[i-1][j]+p*res[i-1][j-1];
            }
        }
        return res[N][k];
    }

27题参考
1月2日
书本:63-130页
习题:1.1.19, 20, 21, 22, 23, 24, 27,共7题
抽象数据类型(ADT)
1)将数据和函数实现关联,并将数据的表示方式隐藏起来
2)使用抽象数据类型时,将注意力集中在API描述的操作而不关心数据的表示
3)实现抽象数据类型时,将注意力集中在数据的表示和对数据的操作
使用抽象数据类型
1)创建对象构成:①new 类名() 为新对象分配内存空间;② 触发构造函数,初始化对象中的值。③构造函数无返回值,因为其总是返回它的数据类型的对象的引用;④对象的变量指向对象的引用
2)赋值语句,创建另一个引用指向已经存在的对象
3)对象作为参数,传递的是对象的引用(的值),能够改变对象的值。
4)对象作为返回值,能够返回多个值
抽象数据类型举例
1)系统标准库java.lang.*中抽象数据类型
2)系统库中抽象数据类型:需要import
3)I/O处理类抽象数据类型:输入输出流
4)面向数据类抽象数据类型:几何和信息处理中简化数据的组织和处理
①几何对象
②信息处理:定义和事物对应的对象
③字符串
???
5)集合类抽象数据类型:Bag,Stack,Queue;优先队列PQ;符号表ST和集合SET
6)面向操作的抽象数据类型:分析算法
①计数器
②累加器
③可视累加器
④计时器
7)图算法相关的抽象数据类型:图的表示和图的处理
1月3日
书本:131-140页
实例代码:动态数组实现可以遍历的栈,3遍
表示一组数据对象的数据结构
1)泛型:
①存储任意类型的数据;
②类名后,Item是类型参数,一个占位符,使用时用具体类型替换
③有了泛型只需要一份API就能处理所有类型的数据
2)可迭代的集合类型
①实现Iterable
②可以用foreach语句变量元素
3)背包
①不支持从中删除元素的集合类型
②迭代的顺序不确定且与用例无关
③典型用法求和
4)先进先出队列
①使用foreach语句迭代队列中的元素,元素处理顺序就是添加到队列的顺序
②日常现象中的自然模型
5)下压栈
①使用foreach迭代栈中的元素,元素处理顺序与被压入栈的顺序相反
②典型实例:不断地点击网页链接访问新网页,点击回退按钮浏览以前的网页
双栈法求算术表达式
可调节大小的数组实现下压栈

class ResizingArrayStack<Item> implements Iterable<Item> {
        private Item[] a = (Item[])new Object[3];
        private int N = 0;

        public boolean isEmpty(){
            return N==0;
        }
        public int size(){
            return N;
        }
        public void resize(int max){
            Item[] temp = (Item[])new Object[max];
            for(int i=0;i<N;i++){
                temp[i]=a[i];
            }
            a=temp;
        }
        public void push(Item item){
            if(N==a.length){
                resize(2*N);
            }
            a[N++]=item;
        }
        public Item pop(){
            Item item = a[--N];
            if(N>0&&N==a.length/4){
                resize(a.length/2);
            }
            return item;
        }
        public Iterator<Item> iterator(){
            return new ReverseArrayIterator();
        }

        private class ReverseArrayIterator implements Iterator<Item> {
            private int i= N;
            public Item next(){
                return a[--i];
            }
            public boolean hasNext(){
                return i>0;
            }
            public void remove(){

            }
        }
  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值