第二次面试外包,HR小姐姐让我看看这几个题,之前被问过

背景

外包就外包吧, 好歹也是一个面试机会, 还是认真对待吧.

前置说明

不一定是标准答案, 都是自己此时此刻的一些思考和理解. 请谅解~

八股文:

如何设计一个高并发对外的接口

下面是我自己的思考, 不一定是标准答案:
换一句复杂的话说, 也是自己对问题的理解: 也就是系统/接口设计的初期, 业务方/需求方已经可以预测这个接口可能会有大量的请求去访问, 如何保证接口的高可用?
更多可能是系统和架构方面的设计.
缓存: 首先分析这个接口返回的数据, 修改的频率时候会很高. 这些数据数据是否适合做缓存. 如果适合被缓存, DB的压力接回被缓解很多.
单一责任链: 设计这个接口应该让它处理的事情尽量简单. 一些不太重要的事情, 是否可以通过异步的方式去处理.
消息队列: 消息队列核心的用途大概就是, 解耦, 削峰, 限流. 上面异步的方式, 也可以接入消息队列, 达到解耦的目的.
架构方面: 用微服务架构, 有完善的熔断, 降级策略.
测试: 做好接口的压测.

Reidis数据类型和使用场景

数据类型: String, List, Hash, Sorted Set …
使用场景: 用户就是缓存和分布式锁(SetNX) set if not exit

MySQL索引区别

感觉知道索引是什么, 列举几个常用的索引就差不多了. 网上的分类有点乱.
主键索引: 就InnoDB而言, 主键索引, 叶子节点上包含了每一行的全部数据.
唯一索引: 就是约定某一个字段不能有重复值, 主键索引其实就是天然的唯一索引.
覆盖索引: 就是几个字段联合起来去建立一个索引. 如果用覆盖索引, 就尽量让查询的字段都是索引字段, 避免去回表查询.

项目用了哪种垃圾回收

看过项目的服务启动脚本, 用得是G1垃圾回收器.
G1垃圾回收器相比其他垃圾回收器最大的变化就是将堆分为了很多个Region,有一种分而治之的感觉. 但是核心的原理还是差不多. 也是分为: 年轻代, 老年代. 可以是任何一个Region扮演. 还分配了一个区域存储超大对象. Young Region经过几轮回收后, 如果依然存活, 就会晋升为老年代.

项目介绍

交代项目的背景: 乱说吧, 想到什么说什么吧.
之前有一个项目用到了这个模式: 状态模式
在这里插入图片描述
模板方法模式: 就是在抽象层定义一个顺序, 抽象层可以不用实现具体的方法. 让子类自己去实现.

策略模式:
// TODO 这里有空自己画一下, 研究一下.
在这里插入图片描述

垃圾回收器有哪些(有哪些区别)

Serile
Parillen
CMS(Corrent Mark Sweep)
G1

怎么判断是垃圾

通过GCRoot对象去做可达性分析.

垃圾清理的过程

之前看过一个jConsole的动态的垃圾回收的图.
Eden From To Old

内存模型

就是JMM. 为了解决多线程的程序, 操作共享变量的问题.

类加载机制

双亲委派, 向上委托. 用这个图记忆一下吧:
// TODO 有空自己画一下, 加深印象.
在这里插入图片描述
类加载的顺序:
// TODO 有空自己画
在这里插入图片描述

Mybatis底层原理

就是一个数据层的框架, 感觉会用就可以, 要自己底层原理干啥呢? 学习的意义真的不大.
为了面试, 找资料学习一下吧
我感觉就是对SQL的封装啊
// TODO 是一款优秀的框架, 可以读一读里面的源码. 有空再说吧.

synchronized ReentrantLock底层原理

synchronized 是Java内置的锁, 是Java的一个关键字, 通常用于修饰方法和类. 使用javap 命令可以查看对应的字节码文件信息, 底层是通过 monitorenter 和 monitorexit 实现的.
ReentrantLock 是并发包里面有一个Lock接口, JDK为我们提供的一种具体实现. 这个实现是基于AQS(AbstractQueuedSynchronizer)实现的.
synchronized使用起来更加方便一点, 并且不需要我们自己去解锁操作. 但是在高并发场景ReentrantLock性能会更好一些.

锁升级过程

无锁 -> 偏向锁 -> 轻量级锁 -> 重量级锁

如何处理分布式事务

最好是能通过合理的拆分微服务, 去规避分布式事务的问题.
常见的解决方案: Seata, 2PC, 3PC, TCC
// TODO 对于成熟的解决方案, 其实也可以分析一下底层原理. 理论支撑 -> 具体代码实现.

设计模式:

手写一个单例模式

public class Singleton4 implements Serializable {
    // 懒加载
    private static volatile Singleton4 INSTANCE = null;

    // 无参构造私有化
    private Singleton4() {
        if (INSTANCE != null) {
            throw new RuntimeException("单例对象不能重复创建");
        }
    }

    /**
     * 对外提供获取该单例对象的方法
     *
     * @return 单例对象
     */
    public static Singleton4 getInstance() {
        if (INSTANCE == null) { // 第一次检查
            synchronized (Singleton4.class) { 
                if (INSTANCE == null) { // 第二次检查
                    INSTANCE = new Singleton4();
                }
            }
        }
        return INSTANCE;
    }
}

算法:

数组查找3个组相加为0的元素(3sum)

原理就是用两个指针去处理, 代码实现如下:
在这里插入图片描述

class Solution {
    public static List<List<Integer>> threeSum(int[] nums) {
        // 返回值
        List<List<Integer>> res = new ArrayList<>();
        // 参数校验: 为空或长度不足3个, 直接返回空数组
        if (nums == null || nums.length < 3) {
            return res;
        }
        int len = nums.length;
        // 排序
        Arrays.sort(nums);
        // 遍历数组
        for (int i = 0; i < len; i++) {
            if (nums[i] > 0) { // 如果第一个数都大于0, 那么三数之和一定大于0
                break;
            }
            if (i > 0 && nums[i] == nums[i-1]) {
                continue;
            }
            int left = i + 1;
            int right = len - 1;
            while (left < right) {
                int sum = nums[i] + nums[left] + nums[right];
                if (sum == 0) {
                    res.add(Arrays.asList(nums[i], nums[left], nums[right]));
                    // 重复元素的跳过
                    while (left < right && nums[left] == nums[left + 1]) {
                        left++;
                    }
                    while (left < right && nums[right] == nums[right - 1]) {
                        right--;
                    }
                    // 继续移动
                    left++;
                    right--;
                }
                // 左指针右移
                if (sum < 0) {
                    left++;
                }
                // 右指针左移
                if (sum > 0) {
                    right--;
                }
            }
        }
        return res;
    }
}

二分查找算法

我也不知道是什么思维, 就是二分查找的算法, 学校感觉都学习过, 可以画一个简答的图:
在这里插入图片描述

    public static int search(int[] nums, int target) {
        // 参数校验
        if (nums == null || nums.length == 0) {
            return -1;
        }
        int len = nums.length; // 数组长度
        int left = 0; // 左边界
        int right = len - 1; // 右边界
        while (left <= right) {
            int mid = left + (right - left) / 2; // 防止溢出
            if (nums[mid] == target) {
                return mid;
            }
            if (nums[mid] > target) { // target在左边区间
                right = mid - 1;
            }
            if (nums[mid] < target) { // target在右边区间
                left = mid + 1;
            }
        }
        return -1;
    }

算法如何判断一个链表中是否有环

设置快慢指针, 示意图和代码实现如下:
在这里插入图片描述

    public boolean hasCycle(ListNode head) {
        if (head == null || head.next == null) {
            return false;
        }
        ListNode slow = head;
        ListNode fast = head.next;
        while (slow != fast) {
            if (fast == null || fast.next == null) {
                return false;
            }
            slow = slow.next;
            fast = fast.next.next;
        }
        return true;
    }

LC2两数相加

有点躁动了, 还没看完
// TODO 后面再看吧

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        ListNode head = null, tail = null;
        int carry = 0;
        while (l1 != null || l2 != null) {
            int n1 = l1 != null ? l1.val : 0;
            int n2 = l2 != null ? l2.val : 0;
            int sum = n1 + n2 + carry;
            if (head == null) {
                head = tail = new ListNode(sum % 10);
            } else {
                tail.next = new ListNode(sum % 10);
                tail = tail.next;
            }
            carry = sum / 10;
            if (l1 != null) {
                l1 = l1.next;
            }
            if (l2 != null) {
                l2 = l2.next;
            }
        }
        if (carry > 0) {
            tail.next = new ListNode(carry);
        }
        return head;
    }
}

输入一个string转化为数字,如果不是数字就输出0

先完成吧, 应该不是这个答案:

    public static int stringToNumber(String str) {
        try {
            // 尝试将字符串转换为整数
            return Integer.parseInt(str);
        } catch (NumberFormatException e) {
            // 如果转换失败,返回0
            return 0;
        }
    }

字符串反转

感觉不可能直接让你调用API, 算了先这样吧:

    public static String reverseString(String str) {
        return new StringBuilder(str).reverse().toString();
    }

有一个密文,解析出来是每一行的最后一个数字。

// TODO
大概是这样,比如有1,2,3,4,5,6,7,8,9,10,这10个数,第一排是1,第二排是2,3,4,第三排是5,6,7,8,9,第四排是10。那么密文就是1,4,9,10
让你实现并说出时间服杂度是多少要循环多少次

import java.util.ArrayList;
import java.util.List;

public class DecodeCipher {
    public List<Integer> decode(int[] nums) {
        List<Integer> result = new ArrayList<>();
        if (nums == null || nums.length == 0) {
            return result;
        }

        int row = 0; // 当前行号
        int col = 0; // 当前列号
        int n = nums.length;

        for (int i = 0; i < n; i++) {
            // 如果当前列等于行号,说明是当前行的最后一个元素
            if (col == row) {
                result.add(nums[i]);
            }
            col++;

            // 准备进入下一行
            if (col > row) {
                row++;
                col = 0;
            }
        }

        return result;
    }

    // 测试方法
    public static void main(String[] args) {
        DecodeCipher decoder = new DecodeCipher();
        int[] nums = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
        List<Integer> result = decoder.decode(nums);
        System.out.println(result);  // 输出: [1, 4, 9, 10]
    }
}

功能:输入阿拉伯数字,翻译成符合中文阅读习惯的中文输出

// TODO
输入:1000
输出:一千
输入范围:0~一亿正整数,不用考虑异常情况
例子:12341234,123005

import java.util.HashMap;
import java.util.Map;

public class NumberToChinese {

    private static final String[] CHINESE_NUMS = {"零", "一", "二", "三", "四", "五", "六", "七", "八", "九"};
    private static final String[] LEVELS = {"", "十", "百", "千", "万", "十万", "百万", "千万", "亿"};

    public String numberToChinese(int num) {
        if (num == 0) return "零";
        return helper(num).replaceAll("亿万", "亿").replaceAll("一十", "十").replaceAll("(零)+", "零").replaceAll("零$", "");
    }

    private String helper(int num) {
        if (num == 0) return "";
        StringBuilder sb = new StringBuilder();
        int level = 0;

        while (num > 0) {
            int remainder = num % 10;
            if (remainder > 0 || sb.length() > 0) {
                if (level > 0 && num % 10 == 0 && sb.length() == 0) {
                    sb.insert(0, CHINESE_NUMS[0]);
                } else {
                    sb.insert(0, LEVELS[level]);
                    if (remainder > 0) {
                        sb.insert(0, CHINESE_NUMS[remainder]);
                    }
                }
            }
            num /= 10;
            level++;
            if (level == 4) {
                sb.insert(0, "亿");
                level = 0;
            } else if (level == 8) {
                sb.insert(0, "万");
            }
        }
        return sb.toString();
    }

    // 测试方法
    public static void main(String[] args) {
        NumberToChinese converter = new NumberToChinese();
        System.out.println(converter.numberToChinese(12345));   // 输出: "一万二千三百四十五"
        System.out.println(converter.numberToChinese(1000));    // 输出: "一千"
        System.out.println(converter.numberToChinese(10010));   // 输出: "一万零一十"
        System.out.println(converter.numberToChinese(10000000)); // 输出: "一百万"
        System.out.println(converter.numberToChinese(100000000)); // 输出: "一亿"
        System.out.println(converter.numberToChinese(10000010)); // 输出: "一十万零一十"
    }
}

米家5,1,4,米粉2,3,5,8,然后求米家米粉最近的距离

// TODO 毅力用完了, 后面再看吧

import java.util.Arrays;

public class MinDistance {
    public int findMinDistance(int[] miajia, int[] mifens) {
        if (miajia == null || mifens == null || miajia.length == 0 || mifens.length == 0) {
            throw new IllegalArgumentException("Input arrays cannot be null or empty.");
        }

        // 对两个数组进行排序
        Arrays.sort(miajia);
        Arrays.sort(mifens);

        int minDist = Integer.MAX_VALUE;
        int i = 0, j = 0;

        // 使用双指针遍历两个数组
        while (i < miajia.length && j < mifens.length) {
            minDist = Math.min(minDist, Math.abs(miajia[i] - mifens[j]));

            // 移动较小的指针以尝试缩小差距
            if (miajia[i] < mifens[j]) {
                i++;
            } else {
                j++;
            }

            // 如果已经找到最小可能的距离,则提前终止
            if (minDist == 0) break;
        }

        return minDist;
    }

    // 测试方法
    public static void main(String[] args) {
        MinDistance solver = new MinDistance();
        int[] miajia = {5, 1, 4};
        int[] mifens = {2, 3, 5, 8};
        System.out.println(solver.findMinDistance(miajia, mifens)); // 输出: 0
    }
}

其他:

binlog有几种数据类型
1、问我怎么看待ai发展,然后平时工作做什么内容,异常怎么解决,遇到了那些问题,幂等,消息一致性,es基本原理,kafaka基本原理
9、比较宽泛的架构类型
6、项目中的难点,怎么解决的

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值