笔试强训day36

一、选择题

1、下列关于线程说法错误的是()
A 耗时的操作使用线程,提高程序响应
B 耗内存的操作使用线程,提高内存利用率
C 多CPU的系统使用线程,提高CPU利用率
D 并行操作使用线程,如c/s架构中服务端程序为每个客户端请求创建一个线程来响应
他的回答: B (正确)
正确答案: B
2、如果将固定块大小的文件系统中的块大小设置大一些,会造成()。
A 更好的磁盘吞吐量和更差的磁盘空间利用率
B 更好的磁盘吞吐量和更好的磁盘空间利用率
C 更差的磁盘吞吐量和更好的磁盘空间利用率
D 更差的磁盘吞吐量和更差的磁盘空间利用率
他的回答: C (错误)
正确答案: A
文件是按块存储的,如果块大小设置的大一些,读取的时候一次性读取的就更多,磁盘吞吐量提升,但是文件可能不能占满整个块,导致利用率下降。
3、在下列进程的四个特征中,最基本的特征是()。
A 并发性
B 动态性
C 独立性
D 异步性
他的回答: C (错误)
正确答案:B
A.并发性:指多个进程实体同存于内存中,且在一段时间内同时运行。并发性是进程的重要特征,同时也成为操作系统的重要特征。
B.动态性:进程的实质是进程实体的一次执行过程,因此,动态性是进程最基本的特征。
C.独立性:进程实体是一个独立运行、独立分配资源和独立接受调度的基本单位。
D.异步性:指进程按各自独立的、不可预知的速度向前推进,或者说实体按异步方式运行。
4、进程调度是从()选择一个进程投入运行。
A 就绪队列
B 等待队列
C 作业后备队列
D 提交队列
他的回答: A (正确)
正确答案: A
B.等待队列:用于使线程等待某一特定的事件发生而无需频繁的轮询,进程在等待期间睡眠,在某件事发生时由内核唤醒。
C.作业后备队列:操作系统首先从外存的后备队列中选取某些作业调入内存,并为它们创建进程、分配必要的资源。然后再将新创建的进程插入就绪队列,准备执行。
5、下面有关Cache的说法哪一个是不正确的?
A 设置Cache的目的,是解决CPU和主存之间的速度匹配问题
B 设置Cache的理论基础,是程序访问的局部性原理
C Cache与主存统一编址,Cache的地址空间属于主存的一部分
D Cache的功能均由硬件实现,对程序员是透明的
他的回答: D (错误)
正确答案: C
A.Cache出现的原因就是为了解决CPU与主存之间的速度匹配问题,CPU速度>Cache速度>主存速度。
B.程序访问的局部性原理是一个程序在运行的某一时段,它访问的代码或数据大部分是几种在集中在某一块区域的。
C Cache的地址与主存的地址是两码事,不统一编址,也没有从属关系。
D.Cache是由硬件实现。
6、什么是内存抖动(Thrashing)( )
A 非常频繁的换页活动
B 非常高的CPU执行活动
C 一个极长的执行进程
D 一个极大的虚拟内存
他的回答: D (错误)
正确答案:A
页面的频繁更换,导致整个系统效率急剧下降,这个现象称为内存抖动。
抖动一般是内存分配算法不好,内存太小引或者程序的算法不佳引起的页面频繁从内存调入调出。
7、在所有非抢占CPU调度算法中,系统平均响应时间最优的是( )
A 实时调度算法
B 短任务优先算法
C 时间片轮转算法
D 先来先服务算法
他的回答: D (错误)
正确答案: B
响应时间是任务到达和任务开始被处理(响应)之间的时间。
周转时间是到达和处理结束之间的时间。
A.实时调度算法:指系统能够在限定的响应时间内提供所需水平的服务。如果系统的时间约束条件得不到满足将会发生系统出错。
B.短任务优先算法:执行时间短的任务优先执行。
C.时间片轮转算法:由系统调度就绪队列中的进程,每个进程分配一段时间片,利用时钟中断进行进程周期性切换。
D.先来先服务算法:按先后顺序进行调度。
8、假设如下代码中,若t1线程在t2线程启动之前已经完成启动。代码的输出是()

public static void main(String[]args)throws Exception {
	final Object obj = new Object();
	Thread t1 = new Thread() {
	public void run() {
		synchronized (obj) {
		try {
			obj.wait();//释放对象锁,让当前线程等待
			System.out.println("Thread 1 wake up.");
			} catch (InterruptedException e) {
	}
	}
}
};
t1.start();
Thread.sleep(1000);//We assume thread 1 must start up within 1 sec.
Thread t2 = new Thread() {
public void run() {
synchronized (obj) {
obj.notifyAll();
System.out.println("Thread 2 sent notify.");
}
}
};
t2.start();
}

A Thread 1 wake up Thread 2 sent notify.
B Thread 2 sent notify. Thread 1 wake up
C A、B皆有可能
D 程序无输出卡死
他的回答: A (错误)
正确答案: B
t1启动后执行objwait()时,进入阻塞状态,让出时间片并释放锁,等待其他线程的唤醒。
然后t2获取到obj,并唤醒t1,待t2执行完毕,释放锁后,t1再继续执行。
9、以下哪句的说法是正确的?
A 在页式存储管理中,用户应将自己的程序划分为若干个相等的页
B 所有的进程都挂起时,系统将陷入死锁
C 执行系统调用可以被中断
D 进程优先数是进程调度的重要依据,必须根据进程运行情况动态改变
他的回答: B (错误)
正确答案: C
A.页的划分是操作系统做的。
B.系统进入死锁必须满足4个条件:互斥、循环并等待、不剥夺、请求与保持;所有的进程都挂起,并不表示这些进程间有资源调用和循环等待的关系,有些进程定时器结束后可能自动唤醒。
D.有静态优先级调度。
10、下列方法中,____不可以用来程序调优?
A 改善数据访问方式以提升缓存命中率
B 使用多线程的方式提高 I/O 密集型操作的效率
C 利用数据库连接池替代直接的数据库访问
D 利用迭代替代递归
E 合并多个远程调用批量发送
F 共享冗余数据提高访问效率
他的回答: D (错误)
正确答案: B
参考答案:
IO密集型通过少量线程和回调机制来调优

二、编程题

【Rational Arithmetic (20)】
For two rational numbers, your task is to implement the basic arithmetics, that is, to calculate their sum, difference,
product and quotient.
输入描述:
Each input file contains one test case, which gives in one line the two rational numbers in the format “a1/b1 a2/b2”.
The numerators and the denominators are all in the range of long int. If there is a negative sign, it must appear only in front of the numerator. The denominators are guaranteed to be non-zero numbers.
输出描述:
For each test case, print in 4 lines the sum, difference, product and quotient of the two rational numbers, respectively. The format of each line is “number1 operator number2 = result”. Notice that all the rational numbers must be in their simplest form “k a/b”, where k is the integer part, and a/b is the simplest fraction part. If the number is negative, it must be included in a pair of parentheses. If the denominator in the division is zero, output “Inf” as the result. It is guaranteed that all the output integers are in the range of long int.
示例1:
输入
5/3 0/6
输出
1 2/3 + 0 = 1 2/3
1 2/3 - 0 = 1 2/3
1 2/3 * 0 = 0
1 2/3 / 0 = Inf

【题目翻译】:
24505-有理数运算
实现对两个有理数的基本运算,包括加、减、乘、除。
输入描述:
每个输入文件只包含一个测试用例,测试用例会给出一行数据,格式为“a1/b1 a2/b2”
分子分母的范围都在长整型的范围内,如果数字为负,则符号只会出现在分子的前面。分母一定是非零数。
输出描述:
针对每个测试用例,都输出四行,分别是这两个有理数的和、差、积和商,格式为“数1 操作符 数2 = 结果”。注
意,所有的有理数都将遵循一个简单形式“k a/b”,其中k是整数部分,a/b是最简分数形式,如果该数为负数,则必
须用括号包起来。如果除法中的除数为0,则输出“Inf”。结果中所有的整数都在long int的范围内。
【题目解析】:
本题看上去不难,但是存在几个问题:
1、除数为0,这个很好解决,做个判断即可。
2、负数的输出,这个只要一个标签即可。
3、题目中虽然没有明说,但是这个数字处理后其实是有可能不存在分数部分或者整数部分的。也就是说将数据处
理完形成k a/b的格式后,有可能只有一个k,也可能只有一个a/b,也有可能两者皆有,所以要分别考虑这几种情
况。

【解题思路】:
可以尝试实现一个有理数类,将数据处理后重载一下加减乘除即可。处理数据的方法就是除一下mod一下的问题,
加减乘除遵循基本的分数加减乘除原则,最后求一下最大公约数,做一下约分,再处理一下数据,就OK了。

牛客网ACM模式代码

import java.util.*;
class Rational{
    private long numerator; // 分子
    private long denominator; // 分母
    private long integer; // 整数部分
    private boolean negetive = false; // 负数
    private boolean isZero = false; // 分母为零
    private long totalNumerator; // 参与运算的分子:整数+原来分子
    public static long paraseNumerator(String s){
    //只需从字符串中将分子截取出来
        return Long.parseLong(s.substring(0, s.indexOf('/')));
    }
    public static long paraseDenominator(String s){
    //只需从字符串中将分子截取出来
        return Long.parseLong(s.substring(s.indexOf('/')+1, s.length()));
    }
    public Rational(long n, long d){
    // 在输入的时候分母永远不可能为0,但是经过计算之后分母可能会为0
        if(0 == d){
            isZero = true;
            return;
        }
    // 如果分子小于0,表示为负数
        if(n < 0){
            negetive = !negetive;
        }
    // 在输入的时候,分母永远不可能小于0,但是经过计算之后分母也可能会小于0
        if(d < 0){
            negetive = !negetive;
        }
    // 如果输入是假分数,需要将其调整为真分数,比如:5 / 3 ===> 1 2/3
        integer = n / d;
        numerator = n - integer * d;
        denominator = Math.abs(d);
    // 如果分数不是最简的形式,需要将其约分为最简的形式,比如:10 / 15--->2/3
    // 在分子和分母的基础之上分别处以分子和分母的最大公约数
        if(numerator > 1 || numerator < -1){
            long gcd = calcGCD(Math.abs(numerator), denominator);
            if(gcd > 0){
                numerator /= gcd;
                denominator /= gcd;
            }
         }
        totalNumerator = numerator + integer*denominator;
    }
    // 求最大公约数:采用辗转相除法
    private long calcGCD(long a, long b){
        if(0 == b){
            return a;
        }
    return calcGCD(b, a%b);
    }
    public Rational Add(Rational r){
        long n = totalNumerator * r.denominator + denominator * r.totalNumerator;
        long d = denominator * r.denominator;
        return new Rational(n, d);
    }
    public Rational Sub(Rational r){
        long n = totalNumerator * r.denominator - denominator * r.totalNumerator;
        long d = denominator * r.denominator;
        return new Rational(n, d);
    }
    public Rational Mul(Rational r){
        long n = totalNumerator * r.totalNumerator;
        long d = denominator * r.denominator;
        return new Rational(n, d);
    }
    public Rational Div(Rational r){
        long n = totalNumerator * r.denominator;
        long d = denominator * r.totalNumerator;
        return new Rational(n, d);
    }
    public String toString(){
        StringBuffer s = new StringBuffer();
    // 分母为0,输出Inf
        if(isZero){
            s.append("Inf");
            return new String(s);
        }
    // 如果结果为0
        if(0 == integer && 0 == numerator){
            s.append("0");
            return new String(s);
        }
        if(negetive){
            s.append("(-");
        }
    // 输出Rational: 整数部分 + 分数部分
    // 整数部分
        if(0 != integer){
            s.append(Math.abs(integer));
    // 整数部分和分数部分需要使用空格隔开
            if(0 != numerator){
                s.append(' ');
            }
        }
    // 分数部分: 可能存在,也可能不存在
        if(0 != numerator){
            s.append(Math.abs(numerator));
            s.append('/');
            s.append(denominator);
        }
        if(negetive){
            s.append(')');
        }
        return new String(s);
    }
}
public class Main{
    public static void main(String[] args){
    // 循环输入处理多组测试用例
        Scanner sc = new Scanner(System.in);
        while(sc.hasNext()){
    // 接收一组用例
            String s = sc.next();
            Rational r1 = new Rational(Rational.paraseNumerator(s),
            Rational.paraseDenominator(s));
            s = sc.next();
            Rational r2 = new Rational(Rational.paraseNumerator(s),
            Rational.paraseDenominator(s));
    // Add Sub Mul Div, toString()
            System.out.println(r1 + " + " + r2 + " = " + r1.Add(r2));
            System.out.println(r1 + " - " + r2 + " = " + r1.Sub(r2));
            System.out.println(r1 + " * " + r2 + " = " + r1.Mul(r2));
            System.out.println(r1 + " / " + r2 + " = " + r1.Div(r2));
        }
    }
}

【Pre-Post】
We are all familiar with pre-order, in-order and post-order traversals of binary trees. A common problem in data structure classes is to find the pre-order traversal of a binary tree when given the in-order and post-order traversals. Alternatively, you can find the post-order traversal when given the in-order and pre-order. However, in general you cannot determine the in-order traversal of a tree when given its pre-order and postorder traversals. Consider the four binary trees below:
在这里插入图片描述
All of these trees have the same pre-order and post-order traversals. This phenomenon is not restricted to binary trees, but holds for general m-ary
trees as well.
输入描述:
Input will consist of multiple problem instances. Each instance will consist of a line of the form m s1 s2, indicating that the trees are m-ary trees, s1 is the pre-order traversal and s2 is the post-order traversal.All traversal strings will consist of lowercase alphabetic characters. For all input instances, 1<= m <= 20 and the length of s1 and s2 will be between 1 and 26 inclusive. If the length of s1 is k (which is the same as the length of s2, of course), the first k letters of the alphabet will be used in the strings. An input line of 0 will terminate the input.
输出描述:
For each problem instance, you should output one line containing the number of possible trees which would result in the pre-order and post-order traversals for the instance. All output values will be within the range of a 32-bit signed integer. For each problem instance, you are guaranteed that there is at least one tree with the given pre-order and post-order traversals.
示例1:
输入
2 abc cba
2 abc bca
10 abc bca
13 abejkcfghid jkebfghicda
输出
4
1
45
207352860

【题目翻译】:
23561-前序和后序
我们都很熟悉二叉树的前序、中序和后序遍历。在数据结构类中,通常会遇到给定中序和后序的情况下求前序的问
题,或是给定前序和中序求后序的问题。但一般情况下,当给定树的前序和后序时,并不能确定树的中序遍历。例
如下面的这四个二叉树:
它们都拥有着相同的前序和后序。其实这种情况不仅仅限于二叉树,M叉树也是一样。
输入描述:
输入是由多个测试用例组成。每个用例只有一行,格式为m s1 s2,表示树是m叉树,s1是前序遍历,s2是后序遍
历。所有字符串将由小写字母字符组成。对于所有的输入实例,1<=m<=20,s1和s2的长度将介于1和26之间(含
1和26)。如果s1的长度是k(当然,s2也是这么长),那使用的就是字母表的前K个字母。输入一行0表示终止输
入。
输出描述:
对于每个测试用例都要输出一行,表示中序遍历满足该条件的数的个数。输出的范围不会超过int的范围,对于每条
用例,都保证至少有一棵树满足要求。
【题目解析】:
这道题本质上其实是一个排列组合问题。通过前序和后序我们虽然还原不出来树,但是谁是谁的子树我们还是知道
的。
【解题思路】:
假设我们的前序是abejkcfghid,后序是jkebfghicda,那么我们根据前序,就能知道:
1、最多可以有13颗子树,也就是每一层都有13个可能位置
2、a是根,第一棵子树的根是b
3、通过后树我们能知道,b的子树有j、k、e、b共四个结点
4、再回到前序,向前走4个结点,下一棵子树的根是 c
5、以此类推,最终得到 a 为根的下一层共有 3 棵子树
好了三颗子树长这样:
前序 bejk cfghi d
后序 jkeb fghic d
则这一层一共的可能性就是13个空位随便挑3个摆这3颗子树,那么有在这里插入图片描述
种可能。
之后再递归处理b这棵子树,bejk|jkeb,看以b为根时下一层有多少棵子树。可以看出,只有一棵以e为根的子树,那么可能性就只有在这里插入图片描述
种。再递归ejk|jke这棵树,可能情况自然是在这里插入图片描述
种,递归cfghi|fghic这棵树,可能情况是
在这里插入图片描述
所以这道题根本上是排列组合问题,我们需要实现排列组合中的C这个方法。

牛客网ACM模式代码

import java.util.*;
    // 从前序和后序中分离出子树的前序和后序遍历结果
class SubPrePost{
    public SubPrePost(String pre, String post){
        preOrder = pre;
        postOrder = post;
    }
    String preOrder;
    String postOrder;
}
public class Main{
    // 求n的阶乘
    public static long fac(int n){
         long r = 1;
         for(int i = 1; i <= n; ++i){
             r *= i;
         }
         return r;
    }
     // 求C(n,m)的组合
     // 注意:C(n,m) = C(n,n-m)
    public static long calcCom(int n, int m){
        m = Math.min(m, n - m);
        long r = 1;
        for(int i = n - m + 1; i <= n; ++i){
            r *= i;
        }
        return r / fac(m);
    }
    public static List<SubPrePost> splitSubTree(String pre, String post){
        List<SubPrePost> subTree = new ArrayList<>();
        int preIdx = 1;
        int postFirst = 0; // 子树在后序编列结果中第一个元素的位置
        while(preIdx < pre.length()){
    // 在前序中找到子树的根
            char subRoot = pre.charAt(preIdx);
    // 在后序中找到根的位置
            int postRootIdx = post.indexOf(subRoot);
    // 子树中节点的个数
            int nodeCount= postRootIdx - postFirst + 1;
            subTree.add(new SubPrePost(pre.substring(preIdx, preIdx + nodeCount),
            post.substring(postFirst, postFirst+nodeCount)));
    // 找后序的子树
            preIdx += nodeCount;
            postFirst += nodeCount;
        }
        return subTree;
    }
    public static long CalcPossible(int m, String preOrder, String postOrder){
        if(preOrder.isEmpty() || preOrder.length() == 1){
            return 1;
        }
    // 先分离出根的子树
        List<SubPrePost> subTree = splitSubTree(preOrder, postOrder);
        long treeCount = calcCom(m, subTree.size());
    // 递归再对子树进行求解
        for(SubPrePost e : subTree){
            treeCount *= CalcPossible(m, e.preOrder, e.postOrder);
        }
        return treeCount;
    }
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        while(sc.hasNext()){
            int m = sc.nextInt();
    // 如果接受到的是0,表示后序没有测试用例了
            if(0 == m){
                break;
            }
            String preOrder = sc.next();
            String postOrder = sc.next();
            System.out.println(CalcPossible(m, preOrder, postOrder));
        }
    }
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值