快手测开面试

一、算法题

1.最长回文子串

给你一个字符串 s,找到 s 中最长的回文子串

示例 1:

输入:s = "babad"
输出:"bab"
解释:"aba" 同样是符合题意的答案。
class Solution:
    def longestPalindrome(self, s: str) -> str:
        def isHuiWenStr(subStr:str):#判断当前子串是不是回文字符
            start = 0
            end = len(subStr) - 1
            while(start < end):
                if(subStr[start] != subStr[end]):
                    return False
                start = start + 1
                end = end - 1
            return True
        if(len(s) < 2):
            return s
        maxLen = 1#记录最大回文字符长度
        begin = 0#记录最大回文字符的起点
        for i in range(len(s)-1):
            for j in range(i + 1, len(s)):
                if((j - i + 1) > maxLen and isHuiWenStr(s[i:j+1])):
                    maxLen = j - i + 1
                    begin = i
        return s[begin:begin + maxLen]

2. 最长公共子序列

class Solution(object):
    def longestCommonSubsequence(self, text1, text2):
        M, N = len(text1), len(text2)
        dp = [[0] * (N + 1) for _ in range(M + 1)]
        for i in range(1, M + 1):
            for j in range(1, N + 1):
                if text1[i - 1] == text2[j - 1]:
                    dp[i][j] = dp[i - 1][j - 1] + 1
                else:
                    dp[i][j] = max(dp[i - 1][j], dp[i][j - 1])
        return dp[M][N]

3. 最长递增子序列

# Dynamic programming.
class Solution:
    def lengthOfLIS(self, nums: List[int]) -> int:
        if not nums: return 0
        dp = [1] * len(nums)
        for i in range(len(nums)):
            for j in range(i):
                if nums[j] < nums[i]: # 如果要求非严格递增,将此行 '<' 改为 '<=' 即可。
                    dp[i] = max(dp[i], dp[j] + 1)
        return max(dp)

 最长递增子序列II:

class Solution:
    def lengthOfLIS(self, nums: List[int], k: int) -> int:
        n=len(nums)
        e=max(nums)
        lst=[0]*(4*e)
        def query(l,r,s,t,p):
            if l<=s and r>=t:
                return lst[p]
            mid=(s+t)//2
            cmax=0
            if l<=mid:
                cmax=max(cmax,query(l,r,s,mid,2*p))
            if r>mid:
                cmax=max(cmax,query(l,r,mid+1,t,2*p+1))
            return cmax
        def update(key,val,l,r,p):
            if l==r and l==key:
                lst[p]=max(lst[p],val)
                return
            if l<=key and r>=key:
                lst[p]=max(lst[p],val)
                mid=(l+r)//2
                if key<=mid:
                    update(key,val,l,mid,2*p)
                else:
                    update(key,val,mid+1,r,2*p+1)
        ans=1
        update(nums[0],1,0,e,1)
        for i in range(1,n):
            cur=nums[i]
            t=query(cur-k,cur-1,0,e,1)
            ans=max(ans,t+1)
            update(cur,t+1,0,e,1)
        return ans

4. 前K个高频元素

class Solution:
    def topKFrequent(self, nums: List[int], k: int) -> List[int]:
        n = len(nums)
        dic = {}
        for i in range(n):
            if nums[i] not in dic:
                dic[nums[i]] = 1
            else:
                dic[nums[i]] += 1
        
        res = []
        while k > 0:
            tmp = 0
            for num in dic:
                if dic[num] > tmp:
                    tmp = dic[num]
                    cur = num
            dic[cur] = -1
            res.append(cur)
            k -= 1
        return res

5. 合并两个有序数组

给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2,另有两个整数 m 和 n ,分别表示 nums1 和 nums2 中的元素数目。请你 合并 nums2 到 nums1 中,使合并后的数组同样按 非递减顺序 排列。

算法思路:

采用归并排序的思想,将每次num1和num2较大的值归并入num1末端(递增排序),如果num1里的元素先归并完了,就直接将num2剩余元素直接放入num1(num1和num2都递增)

class Solution:
    def merge(self, nums1: List[int], m: int, nums2: List[int], n: int) -> None:
        """
        Do not return anything, modify nums1 in-place instead.
        """
 
        while(m > 0 and n >0):
            if(nums1[m-1] > nums2[n-1]):
                nums1[m+n-1] = nums1[m-1]
                m -= 1
            else:
                nums1[m+n-1] = nums2[n-1]
                n -= 1
        if(n > 0):#num1先归并完了,将num2剩余元素直接放入num1
            nums1[:n] = nums2[:n]
    

6. 买卖股票最佳时机III

class Solution:
    def maxProfit(self, prices: List[int]) -> int:
        n = len(prices)
        buy1 = buy2 = -prices[0]
        sell1 = sell2 = 0
        for i in range(1, n):
            buy1 = max(buy1, -prices[i])
            sell1 = max(sell1, buy1 + prices[i])
            buy2 = max(buy2, sell1 - prices[i])
            sell2 = max(sell2, buy2 + prices[i])
        return sell2

7. 链表删除倒数第n个节点

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next

class Solution:
    def removeNthFromEnd(self, head, n):
        left = right = head
        count = 0 
        while count < n:
            right = right.next
            count += 1
        if not right:
            return head.next
        while right.next:
            left = left.next
            right = right.next
        left.next = left.next.next
        return head

8. 搜索二维矩阵,二分查找

class Solution:
    def searchMatrix(self, matrix: List[List[int]], target: int) -> bool:
        for row in matrix:
            for element in row:
                if element == target:
                    return True
        return False
class Solution:
    def findNumberIn2DArray(self, matrix: List[List[int]], target: int) -> bool:
        i, j = len(matrix) - 1, 0
        while i >= 0 and j < len(matrix[0]):
            if matrix[i][j] > target: i -= 1
            elif matrix[i][j] < target: j += 1
            else: return True
        return False

9. 括号匹配

class Solution:
    def isValid(self, s: str) -> bool:
        dic = {')':'(',']':'[','}':'{'}
        stack = []
        for i in s:
            if stack and i in dic:
                if stack[-1] == dic[i]: stack.pop()
                else: return False
            else: stack.append(i)
            
        return not stack
class Solution:
    def checkValidString(self, s: str) -> bool:
        def help(a):
            cnt = 0
            for c in s if a == 1 else reversed(s):
                if c == '(': cnt += a 
                if c == ')': cnt += -a
                if c == '*': cnt += 1
                if cnt < 0:
                    return False
            return True
        return help(1) and help(-1)

9. 数组中出现次数超过数组长度一半的数字

class Solution:
    def majorityElement(self, nums: List[int]) -> int:
        votes = 0
        for num in nums:
            if votes == 0: x = num
            votes += 1 if num == x else -1
        return x

10. 手撕单例模式

(1)饿汉式单例:(立即加载)

// 饿汉式单例
public class Singleton1 {
 
    // 指向自己实例的私有静态引用,主动创建
    private static Singleton1 singleton1 = new Singleton1();
 
    // 私有的构造方法
    private Singleton1(){}
 
    // 以自己实例为返回值的静态的公有方法,静态工厂方法
    public static Singleton1 getSingleton1(){
        return singleton1;
    }
}

(2)懒汉式单例:(延迟加载)

// 懒汉式单例
public class Singleton2 {
 
    // 指向自己实例的私有静态引用
    private static Singleton2 singleton2;
 
    // 私有的构造方法
    private Singleton2(){}
 
    // 以自己实例为返回值的静态的公有方法,静态工厂方法
    public static Singleton2 getSingleton2(){
        // 被动创建,在真正需要使用时才去创建
        if (singleton2 == null) {
            singleton2 = new Singleton2();
        }
        return singleton2;
    }
}

11. 层序二叉树

class Solution:
    def levelOrder(self, root: Optional[TreeNode]) -> List[List[int]]:
        if not root: return []
        res, queue = [], collections.deque()
        queue.append(root)
        while queue:
            tmp = []
            for _ in range(len(queue)):
                node = queue.popleft()
                tmp.append(node.val)
                if node.left: queue.append(node.left)
                if node.right: queue.append(node.right)
            res.append(tmp)
        return res

12. 一副扑克牌54张,判断(包含大小王)随机取5张牌,判断是不是顺子

class Solution:
    def isStraight(self, nums: List[int]) -> bool:
        repeat = set()
        ma, mi = 0, 14
        for num in nums:
            if num == 0: continue # 跳过大小王
            ma = max(ma, num) # 最大牌
            mi = min(mi, num) # 最小牌
            if num in repeat: return False # 若有重复,提前返回 false
            repeat.add(num) # 添加牌至 Set
        return ma - mi < 5 # 最大牌 - 最小牌 < 5 则可构成顺子 

13. 数组中第k个大的数的索引,并追问如何设计测试用例,你写的代码有什么问题没有,问时间复杂度

def find_kth_largest_index(nums, k):
    sorted_nums = sorted(range(len(nums)), key=lambda x: nums[x], reverse=True)
    return sorted_nums[k-1]

关于测试用例的设计,你可以考虑以下几种情况:

  • 正常情况下的输入测试,包括不同长度的数组和不同范围的整数。
  • 边界情况,例如数组只有一个元素或者只有两个元素。
  • 特殊情况,例如数组中存在相同的元素。

关于代码的问题,上述代码的问题在于使用了sorted函数对数组进行排序,它的时间复杂度为O(nlogn)。如果数组很大,可能会影响性能。可以使用快速选择算法来优化时间复杂度。

快速选择算法的时间复杂度为O(n),它的实现方式类似于快速排序。你可以通过将数组分成两部分来确定第k个大的数所在的位置,从而减少排序的时间复杂度。

14. sql  现在有一张学生表abc  ,有三个字段id  name score,请查询出成绩排名为第二的学生姓名

SELECT name FROM abc ORDER BY score DESC LIMIT 1 OFFSET 1;

二、八股

1.在运行项目之前,Springboot底层原理,有哪些类,以什么顺序执行

(1)SpringApplication: 是启动Spring Boot应用的起始点。当运行 SpringApplication.run 方法时,它会执行以下操作:
推断应用类型(是否是Web应用)。
设置默认属性。
加载所有的 Spring 配置属性。
配置日志。
创建并返回一个 Spring 的 ApplicationContext 实例。

(2)SpringFactoriesLoader: 这个类用于从 classpath 下的 META-INF/spring.factories 文件中加载配置。这是 Spring Boot 扩展自动配置、提供其他 Spring Boot 初始器的主要机制。

(3)@SpringBootApplication: 这个注解实际上是一个组合注解,它组合了以下三个注解:
@SpringBootConfiguration: 表明该类是配置类。
@EnableAutoConfiguration: 启用 Spring Boot 的自动配置。
@ComponentScan: 启用组件扫描。

(4)AutoConfigurationImportSelector: 这个类读取 META-INF/spring.factories 中配置的所有自动配置类,并基于条件评估决定哪些自动配置需要被激活。

(5)ApplicationContext:Spring的上下文对象,所有的Bean都是在这里被管理。
Spring Boot在启动过程中创建了特定类型的ApplicationContext(基于应用类型,例如Web应用会创建AnnotationConfigServletWebServerApplicationContext)。

(6)内嵌 Servlet 容器:如 Tomcat、Jetty 或 Undertow。
Spring Boot 的一个特点是它可以打包为一个独立的JAR,这个JAR包含了一个内嵌的Servlet容器。所以,当应用启动时,这个内嵌的容器也会被启动。

执行顺序简述:
主类(通常带有 public static void main 方法)调用 SpringApplication.run。
创建 SpringApplication 对象。
应用 SpringFactoriesLoader 加载 META-INF/spring.factories 中的配置。
初始化 ApplicationContext。
调用 @EnableAutoConfiguration 加载自动配置。
初始化内嵌的 Servlet 容器。
启动容器并开始监听请求。

2. 白盒黑盒测试说一下,分别是怎样的

(1)白盒测试(White Box Testing)

  • 定义:白盒测试,又称为结构测试、逻辑驱动测试或代码级测试,它是基于程序代码的结构或算法来设计测试用例的。

  • 测试内容

    • 检查代码的分支、循环等逻辑结构是否都被执行。
    • 路径测试,确保所有的路径都被测试。
    • 函数测试,确保函数、方法或类按照预期工作。
  • 工具:可能会使用代码覆盖工具来检查代码的哪些部分被测试,哪些部分没有。

  • 优点

    • 可以发现代码中的隐藏错误。
    • 提供了代码覆盖率的明确指标。
  • 缺点

    • 可能漏掉对一些系统功能的测试。
    • 通常比较耗时。

(2) 黑盒测试(Black Box Testing)

  • 定义:黑盒测试,又称功能测试,主要关注程序功能,而不考虑其内部结构或工作原理。测试是基于输入和预期输出。

  • 测试内容

    • 用户界面和用户体验。
    • 数据库功能。
    • 对输入的处理和对应的输出。
    • 系统功能。
  • 工具:可能会使用自动测试工具,如 Selenium 或 QTP,来模拟用户操作并检查结果。

  • 优点

    • 更接近真实用户的使用情境。
    • 可以发现和用户交互相关的问题。
    • 测试人员不需要知道代码或内部结构。
  • 缺点

    • 不能发现代码的隐藏问题。
    • 有可能遗漏某些不明显的功能性问题。

3. http和https区别,http请求什么结构,请求头的作用是什么

(1)HTTP与HTTPS的区别

  • 安全性

    • HTTP:超文本传输协议,信息是明文传输,存在安全风险。
    • HTTPS:即HTTP加入SSL层,超文本传输安全协议。信息是经过加密的,更加安全。
  • 端口

    • HTTP:使用端口80。
    • HTTPS:使用端口443。
  • 性能

    • HTTP:因为没有加密,所以HTTP的速度比较快。
    • HTTPS:需要进行加密处理,因此相对较慢(但随着现代技术的发展,这种差异已经被最小化)。
  • 证书

    • HTTP:不需要证书。
    • HTTPS:需要SSL证书。如果网站使用的是自签名的SSL证书,浏览器会提示访问者。

(2) HTTP请求结构

一个HTTP请求主要包含以下部分:

  • 请求行:包括请求方法(如GET, POST, PUT, DELETE等)、请求URI以及HTTP版本。
  • 请求头(Headers):描述请求的元数据或其他信息,如User-Agent(浏览器类型)、Accept(可接受的回复类型)、Host(请求的服务器)等。
  • 空行:请求头和请求体之间的分隔符。
  • 请求体(Body):POST或PUT请求中传送的数据。

(3) 请求头的作用

请求头在HTTP请求中扮演了重要的角色,它为服务器提供了关于客户端请求的一些信息。以下是请求头的一些常见用途:

  • 内容类型:通过Content-Type头部,客户端可以告诉服务器发送的数据是什么格式,如application/jsontext/html
  • 内容长度:通过Content-Length头部,指示请求或响应体的大小。
  • 认证:例如,Authorization头部用于包含凭据,通常用于API认证。
  • 缓存控制Cache-Control和其他相关的头部可以控制如何缓存响应内容。
  • 用户代理User-Agent头部描述了发出请求的客户端类型,如浏览器或其他客户端应用。
  • 接受的内容类型:通过Accept头部,客户端可以告诉服务器它希望收到哪种类型的响应。
  • CookiesCookie头部可以包含服务器设置的任何cookie,它们在每个请求中发送回服务器。
  • 跨域请求Origin头部表示请求来自哪个源,与CORS(跨来源资源共享)策略相关。

4.TCP和UDP的区别,TCP三次握手,为什么不是两次握手

(1) TCP与UDP的区别

  • 连接的性质

    • TCP:是一个面向连接的协议。这意味着在数据传输前,两个通信端需要建立一个连接。
    • UDP:是一个无连接的协议。数据在发送前不需要建立连接。
  • 可靠性

    • TCP:提供了数据的可靠传输。它有确认、超时重传、错误检测、流量控制等机制来确保数据正确、完整地从发送端传输到接收端。
    • UDP:不保证数据的可靠传输。数据包在网络中可能会丢失、乱序或重复。
  • 数据的边界性

    • TCP:是字节流的形式,没有明确的边界。
    • UDP:是数据报文的形式,每个数据报文都有明确的边界。
  • 速度

    • TCP:由于其可靠性机制,相对较慢。
    • UDP:因为它缺少大部分的错误检测和校正机制,所以传输速度相对较快。
  • 用途

    • TCP:被广泛应用在需要数据可靠性的场合,如网页浏览、文件传输、电子邮件等。
    • UDP:通常用于广播和多播传输、视频会议、流媒体等,这些应用对数据的实时性有较高的要求。

(2)TCP三次握手为什么是三次握手而不是两次?

三次握手是TCP协议建立连接的过程,具体步骤如下:

  • SYN:客户端发送一个SYN包(同步序列编号)到服务器,请求建立连接。
  • SYN-ACK:服务器收到SYN包后,返回一个SYN-ACK包(同步应答)来确认客户端的SYN。
  • ACK:客户端再发送一个ACK包(确认)给服务器,确认服务器的SYN-ACK。

三次握手原因:

  • 防止已失效的连接请求报文段突然传到了服务端:考虑一个场景,客户端发送了第一个连接请求,但是由于网络原因这个请求被延迟了,于是TCP又发送了一个连接请求。当网络好转时,两个连接请求几乎同时到达服务端,如果此时是两次握手,服务端就会建立两个连接,但客户端只建立了一个连接,这就造成了服务端资源的浪费。

  • 更为可靠地确认双方的接收与发送能力:三次握手可以确保双方都有接收和发送消息的能力。两次握手无法保证这一点。

  • 设定序列号:三次握手还可以使得双方都能为TCP连接初始的序列号达成一致

5.URL输入到网页展示

  • 地址解析

    • 浏览器检查URL是否在本地缓存中有对应的IP地址。
    • 如果没有,浏览器会向系统的默认DNS服务器请求解析该URL对应的IP地址。
    • DNS服务器响应请求,返回对应的IP地址。
  • 建立TCP连接

    • 浏览器与远程服务器通过三次握手建立TCP连接。
  • 发送HTTP请求

    • 浏览器发送HTTP请求到服务器。
  • 服务器处理请求并返回HTTP响应

    • 服务器处理接收到的请求。
    • 服务器返回一个HTTP响应给浏览器。
  • 浏览器解析并渲染页面

    • 浏览器首先解析HTML来构建DOM树。
    • 浏览器解析CSS样式信息,与DOM树结合,形成渲染树。
    • 浏览器布局渲染树(进行布局计算)。
    • 浏览器绘制渲染树,展示页面内容。
  • 加载嵌套的资源

    • HTML页面中可能包含嵌套的资源,如图片、CSS、JavaScript等。浏览器会对这些资源进行上述相同的过程:解析地址、建立连接、请求资源、获取响应、处理和渲染。
  • 执行JavaScript

    • 浏览器解析和执行JavaScript代码。这可能会修改页面内容。
  • 关闭连接

    • 如果HTTP/1.1的“Keep-Alive”参数没有被使用,浏览器会关闭TCP连接。若使用了HTTP/2,则连接在多个请求中可能被重用。

6. where和having区别

  • “Where” 是一个约束声明,是在查询结果集返回之前约束来自数据库的数据,且Where中不能使用聚合函数。
  • Having”是一个过滤声明,是在查询结果集返回以后对查询结果进行的过滤操作,在Having中可以使用聚合函数。

7. MySQL聚合函数的关键字

AVG、COUNT、MAX、MIN、SUM

8. 如何解决读写冲突

  • 锁定

    • 互斥锁(Mutex):确保任何时候只有一个线程可以访问资源。
    • 读写锁(ReadWriteLock):允许多个线程同时读,但只允许一个线程写入。这比全互斥锁更加灵活,因为它只在写入时阻止其他线程/进程访问。
    • 乐观锁:基于数据版本控制,读取数据时记录其版本,写入时检查版本是否改变,若未改变则写入,否则重试。
  • 原子操作

    • 使用硬件或软件提供的原子操作来确保读写的一致性,例如compare-and-swap
  • 隔离级别

    • 在数据库中,事务的隔离级别可以定义多个事务之间的可见性和冲突解决策略,例如“读已提交”或“可重复读”。
  • 序列化访问

    • 确保一次只有一个请求可以访问数据,例如使用消息队列。
  • 分布式锁

    • 在分布式系统中,可以使用分布式锁来确保多个节点上的进程不会同时写入。。
  • 冲突检测与回滚

    • 当检测到冲突时,可以选择回滚操作,并在合适的时机重试。

9. 多表冲突怎么解决

  • 事务

    • 使用事务可以确保一组操作作为一个单元执行,即它们要么全部成功,要么全部失败。这有助于确保数据的完整性和一致性。
  • 锁定策略

    • 表级锁:当操作需要访问整个表时,可以使用表级锁。
    • 行级锁:只锁定被操作的特定行,从而允许多个事务可以并发访问同一个表的不同行。
    • 页级锁:介于表级锁和行级锁之间,锁定数据页。
  • 死锁检测与预防

    • 数据库系统通常都有死锁检测机制。当检测到死锁时,数据库会选择一个事务进行回滚,从而解除死锁。
    • 为了预防死锁,可以尝试让所有的事务都按相同的顺序访问表。
  • 优化查询

    • 通过优化查询,减少所需的锁的数量和持续时间,从而降低冲突的可能性。
  • 乐观并发控制

    • 通过版本号或时间戳等机制,在提交更改时检查数据是否已被其他事务修改。如果数据已更改,事务会失败并需要重试。
  • 减少事务持续时间

    • 通过减少事务的持续时间,可以减少冲突的机会。例如,尽可能快地提交事务或将长事务分解为多个短事务。
  • 隔离级别

    • 调整数据库的事务隔离级别可以影响锁的行为。例如,READ COMMITTEDSERIALIZABLE在锁定策略上有很大的不同。
  • 分区

    • 将数据分区到不同的物理存储区域可以减少锁定的竞争。

10. JVM内存模型、垃圾回收机制、进入老年代的阈值、JVM可调整的参数

(1)JVM内存模型

JVM内存大致可以划分为以下几个部分:

  • 方法区(Method Area):存放类信息、静态变量、常量、即时编译器编译后的代码等。
  • 堆(Heap):是Java中最大的一块内存区域,主要用于存放对象实例。堆进一步可以细分为:
    • 新生代(Young Generation):新创建的对象首先进入新生代,它又可以分为:
      • Eden区
      • 两个Survivor区 (S0和S1)
    • 老年代(Old Generation/Tenured):长时间存活的对象会被移至老年代。
  • Java栈(Java Stack):每个线程创建时都会创建一个Java栈,用于存放局部变量、操作栈、动态链接、方法出入口等。
  • 本地方法栈(Native Method Stack):为JVM使用到的Native方法服务。
  • 程序计数器(Program Counter Register):当前线程所执行的字节码的行号指示器。

(2) 垃圾回收机制

主要回收对象存放的主内存区域:堆和方法区。主要算法:

  • 标记-清除(Mark-Sweep)
  • 复制算法(Copying):主要在新生代中使用,比如Eden区与两个Survivor区之间。
  • 标记-整理(Mark-Compact)
  • 分代收集算法(Generational Collection)

(3) 进入老年代的阈值

对象从新生代进入老年代通常是基于它们的年龄。如果对象在新生代中经过了特定次数的GC后仍然存活,它就会被移至老年代。这个“特定次数”就是阈值,通常可通过参数-XX:MaxTenuringThreshold来设置。

(4) JVM可调整的参数

JVM有许多可调整的参数。以下是一些常用的参数:

  • 堆的设置
    • -Xms:设置初始堆大小。
    • -Xmx:设置最大堆大小。
  • 新生代与老年代的比例
    • -XX:NewRatio:设置新生代与老年代的大小比例。
  • 调整Eden与Survivor区的大小
    • -XX:SurvivorRatio
  • 设置年龄阈值
    • -XX:MaxTenuringThreshold:设置对象进入老年代的年龄阈值。
  • 选择垃圾回收器
    • -XX:+UseSerialGC:选择串行回收器。
    • -XX:+UseParallelGC:选择并行回收器。
    • -XX:+UseConcMarkSweepGC:选择CMS回收器。
    • -XX:+UseG1GC:选择G1回收器。

11. 垃圾收集器有哪些,gc方式

Java的垃圾收集器有多种,每种都有其特定的应用场景和优势。以下是常见的垃圾收集器及其工作方式:

(1) Serial收集器(Serial GC)

  • 适用场景:单线程环境,如简单的命令行程序。
  • 工作方式:使用单个线程进行垃圾收集,因此在垃圾收集时,用户线程会被暂停。
  • 启用方式-XX:+UseSerialGC

(2) Parallel(或 Throughput)收集器

  • 适用场景:多线程应用,追求高吞吐量。
  • 工作方式:使用多个线程并行地执行垃圾收集,但在垃圾收集期间会停止所有用户线程。
  • 启用方式-XX:+UseParallelGC

(3) CMS(Concurrent Mark Sweep)收集器

  • 适用场景:低延迟应用,如Web服务器或交互式应用。
  • 工作方式
    • 初始标记:暂停所有线程,标记GC Roots能直接关联的对象。
    • 并发标记:与用户线程并发运行,标记从GC Roots可达的对象。
    • 重新标记:暂停所有线程,修正并发标记阶段因用户程序继续运行而导致的标记变动。
    • 并发清除:与用户线程并发运行,清除不再使用的对象。
  • 启用方式-XX:+UseConcMarkSweepGC

计算机网络,osi模型,模型各层功能介绍,排序算法,各个排序算法怎么实现,复杂度怎么样

Linux命令:一个文件追加到另一个文件,文件重命名,文件查找字符串

java反射、多线程、垃圾回收

post和get的区别

说一下java的数据结构

Java中的基本数据类型有哪些?

String、StringBuffer的区别

hashmap是线程安全的吗

什么情况下需要用到多线程

java线程的生命周期

如何强制结束一个线程

java创建线程有几种方式

使用乐观锁会不会出现脏读问题?

Mysql里的锁都有哪些?

MySQL主键是唯一索引吗

什么适合做索引,mysql底层数据结构,b+树,什么存储引擎底层用的b树

三、场景题

1. 超多数,一亿个量级的那种,找到最大的10个

  • 首先,遍历一次数组,将前10个数作为初始的最大数集合。
  • 遍历数组的剩余部分,对于每个数,如果它比当前最大数集合中的最小数大,则替换最小数,并重新调整最大数集合的顺序。
  • 最后,最大数集合中的10个数即为所需的最大的10个数。

2. 一张大表划分优化,分成为多个小表,怎么测试小表

(1)数据完整性测试:
确保原始大表中的所有数据都出现在某个小表中。确保数据没有重复,也就是说,
一个数据行不应该出现在多个小表中。确保所有的约束和关系(如外键)都仍然成立。
(2)查询测试:
如果你对原始大表有预定义的查询,确保它们在小表上也能正确运行。
为了验证性能提升,对相同的查询进行基准测试,比较分片前后的执行时间。
(3)写入测试:
确保新数据可以正确地写入适当的小表。测试批量写入的性能,确保它符合或超过你的性能要求。
(4)故障恢复测试:
尝试模拟小表的故障并恢复,确保没有数据丢失。确保备份和恢复策略仍然有效。
(5)并发性测试:
用多个并发用户或进程测试小表,确保系统仍然稳定和响应。检查是否有任何的锁定或并发性问题。
(6) 应用集成测试:
如果你有依赖原始大表的应用程序,确保它们能够正确地与小表集成,并且所有的功能都正常工作。
(7)负载测试:
根据预期的工作负荷进行负载测试,确保系统的性能满足要求。监控系统资源使用情况,如CPU、内存和磁盘。
(8) 迁移测试:
如果你计划在生产环境中迁移到这些小表,考虑执行迁移测试,模拟真实的迁移过程。
(9) 验证工具:
使用数据库验证工具,检查数据的一致性和完整性。
(10) 安全性测试:
确保所有的小表都与原始大表具有相同的安全性标准和策略。
执行安全性测试以确保数据在分片后仍然安全。

3. 知名电商京东淘宝,怎么样测试用户的购物车

(1)基本功能测试:
添加商品到购物车:单个商品、多个商品、不同种类的商品。
从购物车中删除商品。
更改购物车中商品的数量。
选择/取消选择购物车中的商品。

(2) UI/UX测试:
购物车界面在不同设备和浏览器中的显示。
响应性测试,确保在移动设备上也有良好的体验。
购物车的加载速度。

(3) 数据一致性测试:
购物车显示的价格与商品页面显示的价格是否一致。
库存检查:当库存不足时,购物车应该有相应的提示。

(4) 购物车更新测试:
当商品价格或属性(如颜色、尺寸等)发生变化时,购物车中的商品信息是否会更新。

(5) 并发性测试:
多个用户同时操作购物车时的表现,如同时添加、删除商品。

(6) 持久性测试:
退出并重新登录后,购物车的商品是否仍然存在。
在不同设备和浏览器上登录,购物车的内容是否一致。

(7) 集成测试:
购物车与其他模块(如支付、优惠券、积分系统等)的集成。
购物车到结账流程的完整性测试。

(8) 安全性和隐私测试:
确保未登录或其他用户无法访问用户的购物车。
确保所有数据传输,特别是结账时,都是加密的。

(9) 异常和边界测试:
尝试添加库存超出的商品数量到购物车。
尝试在购物车中加入已下架的商品。
当购物车为空时的界面和提示。

(10) 性能测试:
加载含有大量商品的购物车时的性能。

(11)通知和提示测试
当商品缺货或价格变化时,用户是否会收到相应的通知。
购物车中的操作(如删除商品)是否有相应的确认提示。

4. 怎么测试登录页面, 请测试用例设计

(1) UI/UX测试:
检查所有元素(如文本框、标签、按钮、链接)是否正确显示。
确保错误提示清晰、友好并易于理解。
确保所有文本框、按钮、链接等都可点击且反应正常。
检查页面是否在各种屏幕尺寸和分辨率下响应正常。

(2) 功能测试:
使用有效的用户名和密码登录。
使用无效的用户名和密码登录。
使用有效的用户名和无效的密码登录。
使用无效的用户名和有效的密码登录。
使用空用户名和密码尝试登录。
确保“忘记密码”功能或链接可用。

(3) 输入验证测试:
在用户名/密码字段中输入特殊字符、空格等,检查应用的响应。
输入超长或超短的用户名和密码。
输入SQL注入、脚本注入等攻击向量,检查应用的响应。

(4)错误处理测试:
检查当提供错误的凭据时是否显示了合适的错误消息。
在多次尝试错误的登录凭据后,检查是否有锁定策略或验证码要求。

(5) 会话和安全性测试:
登录后,直接访问登录页面,确保应用将用户重定向到主页面或显示已登录状态。
登录后关闭浏览器或标签,再次打开,确保用户仍然登录。
登录后,修改URL地址到其他页面,然后再返回,确保用户仍然登录。
使用HTTP(非HTTPS)登录,确保密码不是明文传输。
检查cookies和session的安全设置,如httpOnly、secure等。

(6) 多用户类型登录测试(如果适用):
尝试使用不同类型的用户(如管理员、普通用户、访客)登录,并确保他们被正确地重定向到他们的主页面。

(7) 浏览器兼容性测试:
在不同的浏览器和版本中测试登录页面。

(8) 性能测试:
模拟多用户同时登录,检查页面加载速度和服务器响应时间。

(9) 重置密码和验证码功能测试(如果适用):
尝试使用“忘记密码”功能重置密码。
在被要求时正确和错误地输入验证码。

(10) 多语言和多地区测试(如果适用):
切换不同的语言或地区,确保登录页面的内容和错误消息正确地翻译

5. 微信好友发送图片写测试用例

(1) 功能性测试:
从相册选择图片并成功发送。
使用相机拍摄新照片并成功发送。
选择并发送多张图片。
图片发送进度条显示并在发送完毕后消失。
在发送图片的过程中,能够成功取消发送。

(2) 文件大小和格式测试:
尝试发送大于微信允许的最大文件大小的图片。
尝试发送不同格式的图片文件(如JPG、PNG、GIF、BMP等)。
尝试发送损坏或不完整的图片文件。

(3) UI/UX测试:
在不同屏幕尺寸的设备上检查图片的显示效果。
长按已发送的图片,确保弹出菜单(如转发、保存、删除等)正常工作。
检查点击图片后的放大、缩小、左右滑动等查看功能。

(4) 网络和性能测试:
在不同的网络环境(如4G、5G、WiFi、慢速网络)下发送图片,确保发送速度和稳定性。
在网络信号不稳定或断开的情况下尝试发送图片。

(5) 安全性和隐私测试:
确保未授权的应用或用户无法访问发送的图片。
检查图片存储和传输是否有加密。

(6) 错误处理测试:
当发送大量或超大文件时,检查是否有合适的错误消息。
当磁盘空间不足时,尝试发送图片并检查是否有相应的提示。

(7) 集成测试:
发送图片后,尝试使用其他功能,如语音、视频、红包等,确保它们不受影响。
在聊天界面外,如朋友圈、微信群等,尝试发送图片。

(8) 其他测试:
旋转设备并在横屏模式下发送图片。
在应用后台运行时发送图片。
修改设备的系统日期和时间,然后尝试发送图片。

(9) 互通性测试:
从不同版本的微信发送图片,并确保接收方可以正确显示。

(10) 多语言和地区测试(如果适用):
在不同的语言设置下尝试发送图片,确保所有的提示、错误消息等都被正确翻译。

6. 快手商城购物车点开到页面渲染出来的时间怎么精确计算

(1) 前端性能监控工具:
使用前端性能监控工具,例如Google Chrome的内置开发者工具,可以提供详细的页面加载时间报告。
如何操作:
打开Chrome开发者工具(F12或右键页面选择“检查”)。
转到“网络”或“Performance”选项卡。
清空缓存并刷新页面或模拟点击操作。
你可以看到页面的详细加载时间线,并准确知道何时页面开始加载、何时DOM完成、何时所有资源(如图片、JS、CSS等)都被下载和执行完毕。

(2) 使用第三方性能监控服务:
有许多第三方服务,如New Relic, LogRocket, FullStory等,提供页面性能监控功能。
这些工具可以为你提供页面的加载和渲染时间,同时还提供其他有关页面性能的详细信息

(3)服务器日志:
尽管大部分的页面渲染时间发生在客户端,但你还可以检查服务器日志以确定服务器响应的时间。
这有助于分析页面加载时间中哪一部分是由服务器引起的

7. 4分钟+七分钟沙漏,得到9分钟

  • 步骤一:同时1号、2号两个沙漏正放计时,4分钟后,1号沙漏漏完,此时把一号倒放,再经过3分钟,2号沙漏漏完。(此时1号还剩下1分钟)历时:4+3=7分钟。
  • 步骤二:2号沙漏倒放,至1号沙漏的漏完,此时2号沙漏倒放已有一分钟沙漏流出。用时:1分钟。
  • 步骤三:再把2号沙漏正放,等到刚刚流出的沙漏流回来,正好1分钟。 用时:1分钟。

总时间为:7+1+1=9分钟。

8. 两个烧杯,一个放糖一个放盐,用勺子舀一勺糖到盐,搅拌均匀,然后舀一勺混合物会放糖的烧杯,问你两个烧杯哪个杂质多?

答:相同。设盐和a糖最初为x 取走一勺y 而后盐中有x+y 最后盐中含糖y-y*y/(x+y) 糖中含盐y*x/(x+y) 两式相等

  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

金州饿霸

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值