其他面经

1.重定向和转发

转发过程:客户浏览器发送http请求—-》web服务器接受此请求–》调用内部的一个方法在容器内部完成请求处理和转发动作—-》将目标资源发送给客户。

整个过程只涉及一次浏览器和服务器之间的“请求-响应”,转发过程中的组件共享同一个请 求(request)和响应(response)对象。

RequestDispatcher对象封装了转发操作,通过request的getRequestDispatcher(String path)方法获得RequestDispatcher对象,通过forward(request, response)方法实现转发。

只能在一个应用内的组件进行,不可以转发给其他应用的地址

可以使用相对地址和绝对地址;绝对地址只需从应用名后面的的路径开始即可。

组件之间涉及数据传递可以通过request对象传递数据。

注:转发操作之前的response输出内容是没有意义的,因为转发操作之前会清空缓冲区,但是如果在转发之前的数据超过了缓冲区,或者调用了flush方法,响应内容输出到了客户端(响应信息已提交),此时执行转发操作会抛出运行时异常IllegalStateException。

重定向:

客户浏览器发送http请求—-》web服务器接受后发送302状态码响应及对应新的location给客户浏览器–》客户浏览器发现是302响应,则自动再发送一个新的http请求,请求url是新的location地址—-》服务器根据此请求寻找资源并发送给客户

response的sendRedirect(String url)方法来实现,注意String类型的参数url表示重定向到的地址,需要注意的是,如果表示重定向到本应用内的一个绝对地址时,要从应用名前开始,例如:tst应用中的某个组件要重定向到本应用内的/jsp/somewhere.jsp,则重定向的绝对地址应该是:“/tst/jsp /somewhere.jsp”

区别

转发是一次请求一次响应,重定向是两次请求两次响应

转发地址栏不会变,重定向地址栏会显示第二次请求的地址

转发只需要给出资源路径,不需要项目名,而重定向要全路径包括项目名

转发效率高,因为是一个请求。

 

2.两个文件都有一亿条url,然后得出重复的url

分析:我们先来看如果要把这些URL全部加载到内存中,需要多大的空间。

1MB = 2^20 = 10^6 = 100W

1GB = 2^30 = 10^9 = 10亿

1亿 = 0.1G * 64 Byte = 6.4G

明显是不可能全部加载到内存中的。我们可采用以下方法解决:

①采用布隆过滤器,位数组大小为m约为输入元素个数n的13倍,

元素个数:n=0.1G;

位数组大小:m = 0.1G * 13 = 1.3亿,即需要1.3亿bit位才能达到错误率0.01

而我们拥有的内存可容纳bit为 4G * 8 bit = 32G bit = 320 亿数据,,可以满足

②分别扫描A,B两个文件,根据hash(url) % k,如果k = 100,那么0.1g的url需要64m的空间,每个小文件需要64m,完全够;将url划分到不同的k个文件中,比如a0,a1,…,a99;b0,b1,…b99;这样处理后相同的url肯定在对应的小文件中,即a0&b0,a1&b1等。但是同一个文件中也会出现冲突,因此每个小文件中,即使url不同,也可能被放入同一个小文件里面;只需要找出100对文件中的相同url,对比a0,b0,,遍历a0,将url存放到hashset中,然后遍历b0,如果b0中某个url在hashset中,说明url在a,b中同时存在,输出即可。例如a0:a,b,c,d; b0:a,b;;就会输出a,b

3.辅助栈:对某个栈进行一系列的进栈,出栈的操作后,如何以o(1)的求出栈里面的最大值;

建立两个栈,一个是数据栈data,一个是辅助栈maxData;

进行push的时候,先对data进行push操作,如果maxData为空,直接push,如果data>=maxData,也push;

Pop的时候,date为空,直接return,如果不为空,且data的栈顶等于max的栈顶,那么就将maxData进行pop,并且data进行pop;

import java.util.Stack;

 

/**

 * 对某个栈进行一系列的进栈,出栈的操作后,

 * 如何以o(1)的求出栈里面的最大值;

 * @author 49692

 *

 */

public class PopStackMax {

       public static void push(Stack<Integer> data, Stack<Integer> maxData, int d){

              data.push(d);

              if(maxData.empty() || d >= maxData.peek()){

                     maxData.push(d);

              }

       }

      

       public static void pop(Stack<Integer> data, Stack<Integer> maxData){

              if(data.empty()){

                     return ;

              }

              if(data.peek() == maxData.peek()){

                     maxData.pop();

              }

              data.pop();

       }

      

       public static int getMax(Stack<Integer> maxData){

              if(maxData.isEmpty()){

                     return -1;

              }

              return maxData.peek();

       }

       public static void main(String[] args) {

              Stack<Integer> data = new Stack<Integer>();

              Stack<Integer> maxData = new Stack<Integer>();

              push(data, maxData, 1);

              push(data, maxData, 2);

              push(data, maxData, 3);

              push(data, maxData, 4);

              pop(data, maxData);

              pop(data, maxData);

              push(data, maxData, 5);

              push(data, maxData, 6);

              pop(data, maxData);

              System.out.println(getMax(maxData));

       }

}

 

4.会议室预定

小刘的工作就是安排学校小礼堂的活动,每个时间最多安排一个活动。现在小刘有一些活动计划的时间表,他想尽可能的安排更多的活动,请问他该如何安排。

2

2

1 10

11 12

3

1 10

10 11

12 20

样例输出

1

2

import java.util.ArrayList;

import java.util.Collections;

import java.util.List;

import java.util.Scanner;

 

/**

 * 会议室开会时间,起始时间和结束时间,时间不能重叠,

 * 各个活动顺利进行,最少需要多少个会议室;

2

2

1 10

11 12

3

1 10

10 11

12 20

样例输出

1

2

 

注意:如果上一个活动在t时间结束,下一个活动最早应该在t+1时间开始

定义两个类,会议室room和活动时间roomTime;

按照活动结束时间进行排序,创建活动的list和会议室的list;

然后遍历活动list,先添加第一个活动,然后贪心算法,遍历剩下每个活动

的开始时间与middleTime的大小,判断该添加哪个最合适的活动,

开始时间和middleTime最接近的

 * @author 49692

 *

 */

public class ArrangeRoom {

       public static void main(String[] args){

              Scanner sc = new Scanner(System.in);

              int n = sc.nextInt();

              List<RoomTime> list = new ArrayList<RoomTime>();

              List<Room> rooms = new ArrayList<Room>();

              for(int i = 0; i < n; i++){

                     int timeCount = sc.nextInt();

                     for(int j = 0; j < timeCount; j++){

                            RoomTime rt = new RoomTime();

                            rt.setStart(sc.nextInt());

                            rt.setEnd(sc.nextInt());

                            list.add(rt);

                     }

              }

              Collections.sort(list);

              int current = -1;

              int roomCount = 0;

              greedySelect(list, rooms);

              for(int i = 0 ; i < rooms.size(); i++){

                     List<RoomTime> tls = rooms.get(i).getTimeList();

                     for(RoomTime rt : tls){

                            System.out.println(i + "-----start:" + rt.getStart() + ",,,end:" + rt.getEnd());

                     }

              }

       }

 

       private static void greedySelect(List<RoomTime> list, List<Room> rooms) {

              // TODO Auto-generated method stub

              Room room = new Room();

              int middleTime = list.get(0).getEnd();

              room.addTime(list.get(0));

              list.remove(0);

              rooms.add(room);

              for(int i = 0; i < list.size(); i++){

                     int index = -1;

                     if((index = getBestTime(list, i, middleTime)) >= 0){

                            middleTime = list.get(index).getEnd();

                            room.addTime(list.get(index));

                            list.remove(index);

                     }

              }

              if(list.size() != 0){

                     greedySelect(list, rooms);

              }

       }

 

       private static int getBestTime(List<RoomTime> list, int index, int middleTime) {

              int min = -1;

              int minData = 100;

              int minEnd = 100;

              for(int i = index ; i < list.size(); i++){

                     int data = list.get(i).getStart() - middleTime;

                     if(data >= 0 && minData >= data){

                            int end = list.get(i).getEnd();

                            if(minData > data){

                                   minData = data;

                                   minEnd = end;

                                   min = i;

                            }else{

                                   if(minEnd > end){

                                          minEnd = end;

                                          min = i;

                                   }

                            }

                     }

              }

              return min;

       }

}

 

class RoomTime implements Comparable<RoomTime>{

       private int start;

       private int end;

      

       public int getStart() {

              return start;

       }

 

       public void setStart(int start) {

              this.start = start;

       }

 

       public int getEnd() {

              return end;

       }

 

       public void setEnd(int end) {

              this.end = end;

       }

 

       @Override

       public int compareTo(RoomTime o) {

              // TODO Auto-generated method stub

              return this.end - o.end;

       }

}

 

class Room{

       private List<RoomTime> timeList = new ArrayList<RoomTime>();

 

       public List<RoomTime> getTimeList() {

              return timeList;

       }

 

       public void setTimeList(List<RoomTime> timeList) {

              this.timeList = timeList;

       }

      

       public int addTime(RoomTime rt){

              timeList.add(rt);

              return timeList.size();

       }

}

 

5. 应对分布式缓存宕机

①缓存恢复前,如何保证系统正常有序的工作

②缓存恢复后,如何保证缓存在K/V恢复前,对应的服务会不会过载

缓存宕机后,并且未恢复数据前,调用方系统请求通过调用cache,发现cache系统状态不可用,则转向请求服务方系统(通过接口访问数据库):

针对缓存恢复前,系统的操作:

A:发现缓存不可用,不进一步调用服务端(数据库)的数据,直接返回预先设定的系统默认值

B:发现缓存不可用,调用方系统按照一定的比率或者概率,决定让部分请求调用数据库数据

C:调用服务方数据库之前,根据服务方反馈的状态,动态决定请求是否调用服务方数据,或者直接返回默认值

方案A:实施起来最容易,如果调用方法知道调用服务器数据库可能扛不住自己的全部流量,索性不请求数据库,等待缓存恢复后在继续访问。但这个方案的局限性在于,如果有写需求,这个方案就行不通了,因为很难简单的设定默认值,并且,如果缓存缺乏持久化,数据缓存的更新需要一次次调用来初始化的。

方案B:让一部分线程请求服务端数据库,保证数据能及时更新的同时,缓存也能持续初始化,至于让多少比例的流量请求服务端数据库,保守的做法就是保证调用方的并发不大于服务方的最大吞吐量。该方案之前需要做好性能的压力测试。

方案C:如果服务方系统运行正常,执行请求;如果服务方系统过载,则拒绝服务,保护服务方的同时,最大限度挖掘服务方性能。

针对缓存恢复后,保证k/v恢复前,对应服务会不会过载

如果缓存的key的数量较少,那么自然不用担心,很快就将缓存预热成功,也不会引起服务过载的情况出现,但是如果混村的数量流量不好估计的时候,不建议贸然将流量直接切过来,怕引起服务过载。

为了保证系统能顺利恢复,我们应该采用流控的方法,循序渐进的放开流量,让缓存逐步预热。流量控制刚开始可以为20%,然后50%,最后全量,放开一部分流量的时候,需要实时观察系统的状态,根据前端流量的变化和后端的承受能力,指定放开的节奏。

 

6.hash冲突的处理,为什么hashmap不安全,怎么解决

链式处理法,默认将entry放到table数组的index处,通过hash函数,计算hash值,通过hash值和length-1 相与,得到table的索引值index,如果已经有了一个entry对象,将新的entry对象放在table的index处,即头结点,,然后它的next是原有的entry对象。

loadFactor是用于计算threshold的,threshold=capacity*loadFactor;因此,如果loadFactor过大,会导致扩容的次数变少,即链的长度会增加,查询效率会下降;如果loadFactor过小,会导致扩容的次数变多,即数组的容量频繁增加,增加查询效率,但是内存空间会增加;因此取了一个0.75折中方案。

线程不安全体现在:添加元素和扩容方面

添加元素:根据hash值和length-1相与,确定index索引值,如果出现hash冲突,那么就采用拉链法;

如果线程1,2分别操作a1,a2;那么两者都读取到e1,然后线程先后将自己entry的next指向e1;此时总会有一个entry会被另一个覆盖;

扩容:新长度变为原来2倍,以新长度生成新数组,,然后将旧的数组拷贝到新数组中;如果线程1,2同时操作新数组newTab,那么最终只有一组数据会成功赋值到新数组中。

7.实现equals要注意哪些原则

1、使用==操作符检查“参数是否为这个对象的引用”,如果是,返回true。

2、使用instanceof操作符检查参数是否为正确的类型,如果不是,返回false。

3、把参数转换成正确的类型。

4、对于该类中的每个关键域,检查参数中的域是否与该对象中对应的域相匹配。

5、检查是否对称的(当x.equals(y)返回true时,y.equals(x)也必须返回true)、传递的(如果x.equals(y)返回true、y.equals(z)返回true、x.equals(z)也必须返回true)、一致的(参加比较的关键域没有被改变,x.equals(y)一直返回true)。

6、覆盖equals时总要覆盖hashCode,相等的对象必须具有相等的散列码。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1 目标检测的定义 目标检测(Object Detection)的任务是找出图像中所有感兴趣的目标(物体),确定它们的类别和位置,是计算机视觉领域的核心问题之一。由于各类物体有不同的外观、形状和姿态,加上成像时光照、遮挡等因素的干扰,目标检测一直是计算机视觉领域最具有挑战性的问题。 目标检测任务可分为两个关键的子任务,目标定位和目标分类。首先检测图像中目标的位置(目标定位),然后给出每个目标的具体类别(目标分类)。输出结果是一个边界框(称为Bounding-box,一般形式为(x1,y1,x2,y2),表示框的左上角坐标和右下角坐标),一个置信度分数(Confidence Score),表示边界框中是否包含检测对象的概率和各个类别的概率(首先得到类别概率,经过Softmax可得到类别标签)。 1.1 Two stage方法 目前主流的基于深度学习的目标检测算法主要分为两类:Two stage和One stage。Two stage方法将目标检测过程分为两个阶段。第一个阶段是 Region Proposal 生成阶段,主要用于生成潜在的目标候选框(Bounding-box proposals)。这个阶段通常使用卷积神经网络(CNN)从输入图像中提取特征,然后通过一些技巧(如选择性搜索)来生成候选框。第二个阶段是分类和位置精修阶段,将第一个阶段生成的候选框输入到另一个 CNN 中进行分类,并根据分类结果对候选框的位置进行微调。Two stage 方法的优点是准确度较高,缺点是速度相对较慢。 常见Tow stage目标检测算法有:R-CNN系列、SPPNet等。 1.2 One stage方法 One stage方法直接利用模型提取特征值,并利用这些特征值进行目标的分类和定位,不需要生成Region Proposal。这种方法的优点是速度快,因为省略了Region Proposal生成的过程。One stage方法的缺点是准确度相对较低,因为它没有对潜在的目标进行预先筛选。 常见的One stage目标检测算法有:YOLO系列、SSD系列和RetinaNet等。 2 常见名词解释 2.1 NMS(Non-Maximum Suppression) 目标检测模型一般会给出目标的多个预测边界框,对成百上千的预测边界框都进行调整肯定是不可行的,需要对这些结果先进行一个大体的挑选。NMS称为非极大值抑制,作用是从众多预测边界框中挑选出最具代表性的结果,这样可以加快算法效率,其主要流程如下: 设定一个置信度分数阈值,将置信度分数小于阈值的直接过滤掉 将剩下框的置信度分数从大到小排序,选中值最大的框 遍历其余的框,如果和当前框的重叠面积(IOU)大于设定的阈值(一般为0.7),就将框删除(超过设定阈值,认为两个框的里面的物体属于同一个类别) 从未处理的框中继续选一个置信度分数最大的,重复上述过程,直至所有框处理完毕 2.2 IoU(Intersection over Union) 定义了两个边界框的重叠度,当预测边界框和真实边界框差异很小时,或重叠度很大时,表示模型产生的预测边界框很准确。边界框A、B的IOU计算公式为: 2.3 mAP(mean Average Precision) mAP即均值平均精度,是评估目标检测模型效果的最重要指标,这个值介于0到1之间,且越大越好。mAP是AP(Average Precision)的平均值,那么首先需要了解AP的概念。想要了解AP的概念,还要首先了解目标检测中Precision和Recall的概念。 首先我们设置置信度阈值(Confidence Threshold)和IoU阈值(一般设置为0.5,也会衡量0.75以及0.9的mAP值): 当一个预测边界框被认为是True Positive(TP)时,需要同时满足下面三个条件: Confidence Score > Confidence Threshold 预测类别匹配真实值(Ground truth)的类别 预测边界框的IoU大于设定的IoU阈值 不满足条件2或条件3,则认为是False Positive(FP)。当对应同一个真值有多个预测结果时,只有最高置信度分数的预测结果被认为是True Positive,其余被认为是False Positive。 Precision和Recall的概念如下图所示: Precision表示TP与预测边界框数量的比值 Recall表示TP与真实边界框数量的比值 改变不同的置信度阈值,可以获得多组Precision和Recall,Recall放X轴,Precision放Y轴,可以画出一个Precision-Recall曲线,简称P-R
1 目标检测的定义 目标检测(Object Detection)的任务是找出图像中所有感兴趣的目标(物体),确定它们的类别和位置,是计算机视觉领域的核心问题之一。由于各类物体有不同的外观、形状和姿态,加上成像时光照、遮挡等因素的干扰,目标检测一直是计算机视觉领域最具有挑战性的问题。 目标检测任务可分为两个关键的子任务,目标定位和目标分类。首先检测图像中目标的位置(目标定位),然后给出每个目标的具体类别(目标分类)。输出结果是一个边界框(称为Bounding-box,一般形式为(x1,y1,x2,y2),表示框的左上角坐标和右下角坐标),一个置信度分数(Confidence Score),表示边界框中是否包含检测对象的概率和各个类别的概率(首先得到类别概率,经过Softmax可得到类别标签)。 1.1 Two stage方法 目前主流的基于深度学习的目标检测算法主要分为两类:Two stage和One stage。Two stage方法将目标检测过程分为两个阶段。第一个阶段是 Region Proposal 生成阶段,主要用于生成潜在的目标候选框(Bounding-box proposals)。这个阶段通常使用卷积神经网络(CNN)从输入图像中提取特征,然后通过一些技巧(如选择性搜索)来生成候选框。第二个阶段是分类和位置精修阶段,将第一个阶段生成的候选框输入到另一个 CNN 中进行分类,并根据分类结果对候选框的位置进行微调。Two stage 方法的优点是准确度较高,缺点是速度相对较慢。 常见Tow stage目标检测算法有:R-CNN系列、SPPNet等。 1.2 One stage方法 One stage方法直接利用模型提取特征值,并利用这些特征值进行目标的分类和定位,不需要生成Region Proposal。这种方法的优点是速度快,因为省略了Region Proposal生成的过程。One stage方法的缺点是准确度相对较低,因为它没有对潜在的目标进行预先筛选。 常见的One stage目标检测算法有:YOLO系列、SSD系列和RetinaNet等。 2 常见名词解释 2.1 NMS(Non-Maximum Suppression) 目标检测模型一般会给出目标的多个预测边界框,对成百上千的预测边界框都进行调整肯定是不可行的,需要对这些结果先进行一个大体的挑选。NMS称为非极大值抑制,作用是从众多预测边界框中挑选出最具代表性的结果,这样可以加快算法效率,其主要流程如下: 设定一个置信度分数阈值,将置信度分数小于阈值的直接过滤掉 将剩下框的置信度分数从大到小排序,选中值最大的框 遍历其余的框,如果和当前框的重叠面积(IOU)大于设定的阈值(一般为0.7),就将框删除(超过设定阈值,认为两个框的里面的物体属于同一个类别) 从未处理的框中继续选一个置信度分数最大的,重复上述过程,直至所有框处理完毕 2.2 IoU(Intersection over Union) 定义了两个边界框的重叠度,当预测边界框和真实边界框差异很小时,或重叠度很大时,表示模型产生的预测边界框很准确。边界框A、B的IOU计算公式为: 2.3 mAP(mean Average Precision) mAP即均值平均精度,是评估目标检测模型效果的最重要指标,这个值介于0到1之间,且越大越好。mAP是AP(Average Precision)的平均值,那么首先需要了解AP的概念。想要了解AP的概念,还要首先了解目标检测中Precision和Recall的概念。 首先我们设置置信度阈值(Confidence Threshold)和IoU阈值(一般设置为0.5,也会衡量0.75以及0.9的mAP值): 当一个预测边界框被认为是True Positive(TP)时,需要同时满足下面三个条件: Confidence Score > Confidence Threshold 预测类别匹配真实值(Ground truth)的类别 预测边界框的IoU大于设定的IoU阈值 不满足条件2或条件3,则认为是False Positive(FP)。当对应同一个真值有多个预测结果时,只有最高置信度分数的预测结果被认为是True Positive,其余被认为是False Positive。 Precision和Recall的概念如下图所示: Precision表示TP与预测边界框数量的比值 Recall表示TP与真实边界框数量的比值 改变不同的置信度阈值,可以获得多组Precision和Recall,Recall放X轴,Precision放Y轴,可以画出一个Precision-Recall曲线,简称P-R
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值