一:SpringMVC处理一个请求的流程是怎样的?
- tomcat服务器接受到一个请求后,会交给DispatcherServlet进行处理
- DispatcherServlet会根据请求的path找到对应的Handler
- Handler就是一个加了@RequestMapping方法,然后通过反射执行该方法
- 执行该方法之前会去解析方法参数,比如解析@RequestParam、@RequestHeader、@PathVariable等注解
- 解析这些注解就是从请求中获取相对应的数据,比如请求头、请求parameters,然后把数据传给对应的参数
- 有了参数后就开始执行方法
- 执行方法后,就会得到方法的返回值,SpringMVC会对返回值进行解析
- 如果方法上加上@ResponseBody,那么就把返回值直接返回给浏览器
- 在这个过程中可能需要把一个对象转成JSON字符串才能返回给浏览器
- 如果方法上没有加@ResponseBody,那么就会进行视图解析,然后把解析之后的html数据返回给浏览器
二:SpringMVC工作流程
-
用户发起请求到前端控制器(DispatcherServlet)
-
前端控制器收到请求调用处理器映射器(HandlerMapping)
-
处理器映射器根据请求的URL找到具体的处理器 生成处理器对象及处理器拦截器 一并返回给DispatcherServlet
-
前端控制器调用处理器适配器(HandlerAdapter)去执行处理器(Handler)
-
处理器适配器去执行Handler
-
Handler执行完给处理器适配器返回ModelAndView
-
处理器适配器向前端控制器返回ModelAndView
-
前端控制器请求视图解析器(ViewResolver)去执行视图解析
-
视图解析器向前端控制器返回视图View
-
前端控制器对视图View进行渲染
-
前端控制器向用户响应结果
三:ArrayList扩容机制
四:归并排序(分治和合并)
4399笔试一
package com.huhu.sort;
import java.util.Arrays;
//归并排序
public class MergeSort {
public static void main(String[] args) {
// int[] arr = {8, 4, 5, 7, 1, 3, 6, 2};
int[] arr = {100,5,7,20,97,18,39,50,72};
int[] temp = new int[arr.length];//归并排序需要一个额外空间
mergeSort(arr, 0, arr.length - 1, temp);
System.out.println("归并排序后数组:" + Arrays.toString(arr));
}
//分+合方法
public static void mergeSort(int[] arr, int left, int right, int[] temp) {
if (left < right) {
int mid = (left + right) / 2;//中间索引
//向左递归进行分解
mergeSort(arr, left, mid, temp);
//向右递归进行分解
mergeSort(arr, mid + 1, right, temp);
//到合并
merge(arr, left, mid, right, temp);
}
}
//合并方法
/**
* @param arr 排序的原始数组
* @param left 左边有序序列的索引
* @param mid 中间索引
* @param right 右边索引
* @param temp 做中转的数组
*/
public static void merge(int[] arr, int left, int mid, int right, int[] temp) {
//System.out.println("xxxx");
int i = left;//初始化i,左边有序序列的初始索引
int j = mid + 1;//初始化j,右边有序序列的初始索引
int t = 0;//指向temp数组的当前索引
//(一)
//先把左右两边(有序)的数据按照规则填充到temp数组
//直到左右两边的有序序列,有一边处理完毕为止
while (i <= mid && j <= right) {
//如果左边的有序序列的当前元素,小于等于右边有序序列的当前元素
//则把左边有序序列的当前元素放到temp数组
//然后t++,i++
if (arr[i] <= arr[j]) {
temp[t] = arr[i];
t += 1;
i += 1;
} else {
//反之
//如果左边的有序序列的当前元素,大于右边有序序列的当前元素
//则把右边有序序列的当前元素放到temp数组
//然后t++,i++
temp[t] = arr[j];
t += 1;
j += 1;
}
}
//(二)
//把有剩余数据的一边的数据依次全部填充到temp
while (i <= mid) {//左边的有序序列还有剩余的元素,就全部填充到temp
temp[t] = arr[i];
t += 1;
i += 1;
}
while (j <= right) {//右边的有序序列还有剩余的元素,就全部填充到temp
temp[t] = arr[j];
t += 1;
j += 1;
}
//(三)
//将temp数组拷贝到arr
//注意:并不是每次都拷贝所有
t = 0;
int tempLeft = left;//
//System.out.println("tempLeft=" + tempLeft + ",right=" + right);
while (tempLeft <= right) {//第一次合并 tempLeft=0 right=1 第二次合并 tempLeft=2 right=3 第三次合并 tempLeft=0 right=3
//第四次合并 tempLeft=4 right=5 第五次合并 tempLeft=6 right=7 第六次合并 tempLeft=4 right=7
//最后一次合并 tempLeft=0 right=7
arr[tempLeft] = temp[t];
t += 1;
tempLeft += 1;
}
}
}
五:动态规划
4399笔试二
有 n 个气球,编号为0 到 n - 1,每个气球上都标有一个数字,这些数字存在数组 nums 中。
现在要求你戳破所有的气球。戳破第 i 个气球,你可以获得 nums[i - 1] * nums[i] * nums[i + 1] 枚硬币。 这里的 i - 1 和 i + 1 代表和 i 相邻的两个气球的序号。如果 i - 1或 i + 1 超出了数组的边界,那么就当它是一个数字为 1 的气球。
求所能获得硬币的最大数量。
示例 1:
输入:nums = [3,1,5,8]
输出:167
解释:
nums = [3,1,5,8] --> [3,5,8] --> [3,8] --> [8] --> []
coins = 3*1*5 + 3*5*8 + 1*3*8 + 1*8*1 = 167
示例 2:输入:nums = [1,5]
输出:10
n == nums.length
1 <= n <= 300
0 <= nums[i] <= 100
题解:求解戳破所有气球之和最大硬币数量,换思路来说假设第k个气球为最后一个戳破的,那么maxCoin=Math.max(dp[i][j],dp[i,k]+dp[k,j]+nums[0]*nums[nums.length]*nums[k])(nums数组原来气球基础上首尾加上虚拟气球值1,方便计算,注意区间都是左开右开)
重要技巧:我们初始一维数组所有值都为-1
import java.util.Arrays;
public class BiShi3 {
public static void main(String[] args) {
int[] a = {3, 1, 5, 8};
ChuoQiQiu c = new ChuoQiQiu();
System.out.println(c.maxCoins(a));
}
}
class ChuoQiQiu {
int[][] dp;
public int maxCoins(int[] a) {
int n = a.length;
int[] temp = new int[n + 2];
temp[0] = 1;
temp[n + 1] = 1;
for (int i = 0; i < n; i++) {
temp[i + 1] = a[i];
}
dp = new int[n + 2][n + 2];
for (int i = 0; i < n + 2; i++) {
Arrays.fill(dp[i], -1);//标记位dp[i]下一维数组都为-1
}
return solve(temp, 0, n + 1);
}
// 开区间(l,r)
private int solve(int[] temp, int l, int r) {
if (l + 2 > r) {// 区间内没有气球
return 0;
}
if (l + 2 == r) {// 区间刚好有1个气球
return temp[l] * temp[l + 1] * temp[r];
}
if (dp[l][r] != -1) {
return dp[l][r];
}
int k = l + 1;//戳第k个气球
int res=0;
// k的范围是[1,n]
while (k <= r - 1) {
int left = solve(temp, l, k);//第k个气球左区间最大硬币值
int right = solve(temp, k, r);//第k个气球右区间最大硬币值
res=Math.max(res,left+right+temp[l]*temp[k]*temp[r]);
k++;
}
dp[l][r]=res;
return res;
}
}
招聘笔试
输入一个字符串,在其中寻找长度最长的,不含重复字符的字符串,如果有多个长度相同的最长子字符串,则全部输出
注意:子字符串应由输入的字符串中的连续字符组成
输入:abcdabcde
输出:abcde
输入:abcdabcde
输出:abcd,bcda,cdab,dabc,abcd
package 滑动窗口;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
public class Main {
public static void main(String[] args) {
String str="abcdabcd";
HashMap<Object, ArrayList<Object>> map = new HashMap<>();
for (int i=0;i<str.length();i++){
//第一次从a开始 第二次从b开始
ArrayList<Object> array = new ArrayList<>();
for (int j=i;j<str.length();j++){
char c = str.charAt(j);
if (!array.contains(c)){
array.add(c);
//处理边界 当i==5的时候 到遍历结束都不会进入到else代码块里面 所以需要判断一下
if (j==str.length()-1){
map.put(i,array);
}
}else {
map.put(i,array);
//结束循环
break;
}
}
}
ArrayList<ArrayList<Object>> arrayList = new ArrayList<>();
//将map转为collection集合,放到List里面去
arrayList.addAll(map.values());
//保存最大长度数字
int maxCount=0;
//获取最大长度
for (ArrayList<Object> obj:arrayList){
int size = obj.size();
if (size>maxCount){
maxCount=size;
}
}
StringBuilder stringBuilder = new StringBuilder();
for (ArrayList<Object> obj:arrayList){
if (obj.size()==maxCount){
//遍历
for (Object o:obj){
stringBuilder.append(o);
}
stringBuilder.append(",");
}
}
System.out.println(stringBuilder);
//获取最后一个字符
char c = stringBuilder.toString().charAt(stringBuilder.length() - 1);
if (c==','){
//去掉最后一个 ,
String substring = stringBuilder.substring(0, stringBuilder.length() - 1);
System.out.println(substring);
}
System.out.println();
//输出map进行查看
map.forEach((key,value)->{
System.out.println(Arrays.toString(value.toArray()));
});
}
}
题目:美味度之和最大值 输入参数n ai bi n代表天数 零食a:每天对应的美味度 零食b:每天对应的美味度 且零食a和零食b不能连续吃2天即一天得换一种口味,也可以选择不吃
import java.util.Scanner;
public class BiShi1 {
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
int n=sc.nextInt();
int[] a=new int[n];
int[] b=new int[n];
for (int i = 0; i < n; i++) {
a[i]=sc.nextInt();
}
for (int i = 0; i < n; i++) {
b[i]=sc.nextInt();
}
System.out.println(maxHappy(a,b,n,0));
}
public static int maxHappy(int[] a, int[] b,int n,int choice){
if(n == 0){
return 0;
}
int c = maxHappy(a,b,n-1,0);
// 回溯
int a1 = a[a.length - n] + maxHappy(a,b,n-1,1);
int b1 = b[b.length - n] + maxHappy(a,b,n-1,2);
//0代表上一天没吃零食 可以选择吃a或b
if(choice == 0){
return Math.max(Math.max(a1,b1),c);
}
//1代表上一天吃的a零食,只能选择不吃或者吃b
if(choice == 1){
return Math.max(c,b1);
}else {
return Math.max(c,a1);//2代表上一天吃的b零食,只能选择不吃或者吃a
}
}
}
吃法:2->3->3->4>5 结果相加为17
六:OSI七层协议模型中各层作用及其有关的网络协议
- 物理层:利用传输介质为数据链路层提供物理连接,实现比特流的透明传输。
- 数据链路层:在物理层提供的比特流的基础上,通过差错控制、流量控制方法,使有差错的物理线路变为无差错的数据链路,即提供可靠的通过物理介质传输数据的方法。
- 网络层:通过路由将数据从源地址转发到目的地址,实现ip跳转(IP、ICMP、ARP、RARP)
- 传输层:向网络层提供可靠的端到端的差错和流量控制,保证报文的正确传输;同时向高层屏蔽下层数据通信的细节,保证上层(应用层)提供数据正确、无误(TCP、UDP)
- 会话层:管理和协调不同主机上各种进程之间的通信(对话),即负责建立、管理和终止应用程序之间的会话建立、管理和维护会话(SMTP、DNS)
- 表示层:处理用户信息的表示问题,如编码、数据格式转换和加密解密等
- 应用层:直接向用户提供服务,完成用户希望在网络上完成的各种工作(HTTP、TFTP)
OSI下3层的任务是数据通信,上3层的任务是数据处理。而传输层是OSI模型的第4层。该层提供建立、维护和拆除传输连接的功能,起到承上启下的作用。
MAC地址即物理地址(不可变)
IP地址即逻辑地址 (可变)