币安面经(1)

一些基本概念介绍
  • https://www.binance.com/en/square/post/391229
面试问题
  1. Mysql 分库分表
  • 高并发、数据量大

  • 一般我们认为,单表行数超过 500 万行或者单表容量超过 2GB之后,才需要考虑做分库分表了,小于这个数据量,遇到性能问题先建议大家通过其他优化来解决。

  • 横向拆分(水平拆分)和纵向拆分(垂直拆分)。假如我们有一张表,如果把这张表中某一条记录的多个字段,拆分到多张表中,这种就是纵向拆分。那如果把一张表中的不同的记录分别放到不同的表中,这种就是横向拆分。

  • 分表算法

    • 直接取模
    • Hash取模
    • 一致性Hash
  • 全局ID

    • UUID
    • 多个单表+步长做自增主键
    • 雪花算法
  • 分库分表框架

    • Sharding-JDBC
    • TDDL
    • Mycat
  1. B+树
  • N叉排序树
  • 数据库和操作系统的文件系统
  • B+树的定义

B+树是应文件系统所需而出的一种B-树的变型树。一棵m阶B+树和m阶的B-树的差异在于:

1) 有n棵子树的节点中含有n个关键字(即每个关键字对应一棵子树);

2) 所有叶子节点中包含了全部关键字的信息, 及指向含这些关键字记录的指针,且叶子节点本身依关键字的大小自小而大顺序链接;

3) 所有的非终端节点可以看成是索引部分,节点中仅含有其子树(根节点)中的最大(或最小)关键字

4) 除根节点外,其他所有节点中所含关键字的个数必须>=⌈m/2⌉(注意: B-树是除根以外的所有非终端节点至少有⌈m/2⌉棵子树)

下图是所示为一棵3阶的B+树,通常在B+树上有两个指针头, 一个指向根节点,另一个指向关键字最小的叶子节点。因此,可以对B+树进行两种查找运算: 一种是从最小关键字起顺序查找,另一种是从根节点开始,进行随机查找。

ds-bplus-tree1

  • 与B树的比较

    • 所有的叶子节点中包含了全部关键字的信息,即指向含有这些关键字记录的指针,且叶子节点本身依关键字的大小自小而大的顺序链接。(而B-树的叶子节点并没有包括全部需要查找的信息)
    • 所有的非终端节点可以看成是索引部分,节点中仅含有其子树根节点中最大(或最小)关键字。(而B-树的非终节点也包含需要查找的有效信息)
  • B+树用途-主要适用于索引操作

    • B+树的磁盘读写代价更低
    • B+树的查询效率更加稳定: 由于非终节点并不是最终指向文件内容的节点,而只是叶子节点中关键字的索引。所以任何关键字的查找必须走一条从根节点到叶子节点的路。所有关键字查询的路径长度相同,导致每一个数据的查询效率相当。
  • MySQL中的B+树

    • MyISAMInnoDB两种引擎
    • MyISAM中有两种索引,分别是主索引和辅助索引.MyISAM分别会存在一个索引文件和数据文件,它的主索引是非聚集索引。当我们查询的时候,我们找到叶子节点中保存的地址,然后通过地址我们找到对应的信息。
    • 在InnoDB存储引擎中,表数据文件本身就是按B+树组织的一个索引结构,这棵树的叶节点数据保存了完整的数据记录,所以我们把它的主索引叫做聚集索引
    • 对聚簇索引的解释是: 聚簇索引的顺序就是数据的物理存储顺序; 而对非聚簇索引的解释是: 索引顺序与数据物理排列无关。正是因为如此,所以一个表最多只能有一个聚簇索引。直观上来说,聚簇索引的叶子节点就是数据节点; 而非聚簇索引的叶子节点仍然是索引节点,只不过是指向对应数据块的指针。
  1. Mysql clustered 和 index
属性聚簇索引(Clustered Index)普通索引(Secondary Index)
存储方式数据行存储在索引中,索引叶子节点包含完整数据行索引叶子节点存储指向数据行的指针
数量每个表只有一个一个表可以有多个普通索引
性能读取性能高,特别是范围查询查询时需要回表,性能稍低
物理存储顺序数据行按照聚簇索引顺序存储数据行的物理存储顺序与普通索引无关
维护成本插入或更新可能导致页分裂插入、更新时不会改变数据行的存储顺序
  1. Redis的删除策略,过期策略。
  • Redis 的过期策略是为了确保键在需要时可以自动失效,主要通过惰性删除和定期删除来实现。

    • 惰性删除(Lazy Deletion)

      • 原理:当一个键被访问时,Redis 会检查该键是否已经过期。如果过期,立即删除该键。

        定期删除(Periodic Deletion)

      • 原理:Redis 会每隔一段时间(默认 100 毫秒)随机抽取一部分设置了过期时间的键,检查并删除过期的键。

  • Redis 的删除策略是为了应对内存不足的场景,通过配置不同的回收策略来平衡性能、数据完整性和内存使用。

    • noeviction(默认策略) 行为:当内存不足时,拒绝写入操作,直接返回错误。
    • **allkeys-lru(最常用)**行为:在所有键中,移除最近最少使用的键(LRU)。
  1. 求无序数组 第K 大 (讲了partion算法,说的是O(N),但是面试官觉得是O(NlogN),当时给他证明复杂度没描述太明白)
import java.math.BigInteger;
class Solution {
    public String kthLargestNumber(String[] nums, int k) {
        Arrays.sort(nums, (a, b) -> {
            BigInteger  numA = new BigInteger(a);
            BigInteger  numB = new BigInteger(b);
            return numB.compareTo(numA);
        });        
        
        return nums[k-1];
        
    }
}
class Solution {
    public int findKthLargest(int[] nums, int k) {
        return quickSort(nums,nums.length - k,0,nums.length-1);
    }
    private int quickSort(int[] A,int k,int left,int right){
        int low=left,high=right;
        int pivot = A[low];
        while (low < high) {
            while (low < high && A[high] >= pivot) {
                high--;
            }
            A[low] = A[high];  // 比枢轴元素小的元素移动到左端
            while (low < high && A[low] <= pivot) {
                low++;
            }
            A[high] = A[low];  // 比枢轴元素大的元素移动到右端
        }
        A[low] = pivot;  // 枢轴元素放到最终位置
        if (low==k) return A[low];
        else if(low<k){
            return quickSort(A,k, low+1, right);
        } else {
            return quickSort(A,k, left, low-1);
        }
    }
}
  1. 输出二叉树最后一层的元素
    public List<Integer> getLastLevelElements(TreeNode root) {

        // 使用队列进行层序遍历
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        
        List<Integer> result = new ArrayList<>();
        
        while (!queue.isEmpty()) {
            int levelSize = queue.size();  // 当前层的节点个数
            List<Integer> currentLevel = new ArrayList<>();

            // 遍历当前层
            for (int i = 0; i < levelSize; i++) {
                TreeNode node = queue.poll();
                currentLevel.add(node.val);  // 将当前节点值添加到当前层的结果中

                // 将子节点加入队列
                if (node.left != null) {
                    queue.offer(node.left);
                }
                if (node.right != null) {
                    queue.offer(node.right);
                }
            }

            // 当前层遍历结束后,更新 result 为当前层
            result = currentLevel;
        }
        
        return result;  // 返回最后一层的元素
    }
  1. 求两个数组的重复部分
    public int[] findDuplicates(int[] nums1, int[] nums2) {
        // 使用 HashSet 存储 nums1 的元素
        Set<Integer> set1 = new HashSet<>();
        for (int num : nums1) {
            set1.add(num);
        }

        // 使用 HashSet 存储重复的元素
        Set<Integer> resultSet = new HashSet<>();
        
        // 遍历 nums2,检查重复的元素
        for (int num : nums2) {
            if (set1.contains(num)) {
                resultSet.add(num);
            }
        }

        // 将结果转化为 int[] 数组
        int[] result = new int[resultSet.size()];
        int index = 0;
        for (int num : resultSet) {
            result[index++] = num;
        }
        
        return result;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值