某家宠物SAAS平台JAVA面试题
package com; // 注意: 题目有四道, 请认真仔细读题, // 如果有不理解的地方, 请联系 HR 或面试官, // 如果有不会的, 请留空, 不要求做完, 不要盲目答题. import java.util.*; import java.util.concurrent.*; import java.util.function.Function; import java.util.function.Supplier; /** * Q1: 加权随机函数生成器 * <p> * 给定一个正整数数组 input, 构造一个加权随机类实例, * 该实例的 {@link #next()} 方法被调用时, 随机返回一个该数组的下标, 下标 i 被返回的概率 * 为该下标对应的元素的值 / 所有元素之和. * <p> * 要求: {@link #next()} 方法的时间复杂度不超过 O(log(N)) */ class WeightedRandom { public WeightedRandom(int[] input) { //show me your code } public int next() { return 0; } } /** * Q2: 字符跳动 * <p> * 给定一个由不重复的小写字母组成的字符串,通过一系列跳动指令变换成一个新的字符串。 * 跳动指令有: * * Move(移动),简写:M,例如:M:7 表示将字符串向右移动7位。 * * eXchange(交换),简写:X,例如:X:a/c 表示将字符串中的 a c 位置交换。 * * IndexChange(按位置交换),简写:I,例如:I:2/4 表示将位置2和位置4的字符交换,位置的索引从0开始计数。 * 示例: * 给定初始字符串为:wosjgncxyakdbefh * 给定如下指令: * M:3 则变换后的新字符串为:efhwosjgncxyakdb * I:7/2 则变换后的新字符串为:efgwosjhncxyakdb * X:o/h 则变换后的新字符串为:efgwhsjoncxyakdb * 因此给定初始字符串:wosjgncxyakdbefh,在经过指令 M:3,I:7/2,X:o/h 的变换后得到新的字符串:efgwhsjoncxyakdb。 */ class CharDance { /** * 题目1: * 给定一个随机的初始字符串: src,给定一组随机的指令: ops,(src 和 ops 一定是合法的),求经过转换后得到的新字符串。 * 思路 * 1、根据指令前缀做不同的操作,将操作结果返回 * 2、封装不同的指令操作方法 */ public String transfer(String src, String ops) { //show me your code return src; } /** * 题目2: * 将上一次转换后得到的新字符串作为初始字符串,使用相同的跳动指令集再进行转换,如此重复执行 count 次,求得到的最终字符串是什么? * 注意: count 足够大, 比如可能超过 2^32. */ public String transferMultipleTimes(String src, String ops, long count) { //show me your code return src; } } /** * Q3: 并发任务控制器 * <p> * 注意: 不可使用 java 提供的线程池相关接口 */ class AsyncWorker { /** * 构造函数 * * @param capacity 最大并发数量 */ public AsyncWorker(int capacity) { // show me your code } /** * 任务提交函数: 当前正在执行的任务数小于 capacity 时, 立即异步执行, 否则 * 等到任意一个任务执行完成后立即执行. * * @param task 任务函数 * @param <T> 返回值类型 * @return 返回由 Future 包装的任务函数的返回值, 其状态应该和 task 的执行结果一致 */ public <T> Future<T> submit(Callable<T> task) { // show me your code } } /* ----------------- 以下是测试用例 -----------------*/ class TestWeightedRandom { public static void testWeightedRandom(Function<int[], WeightedRandom> factory) { //0--4--6--7--10--13 // 4 -2 - 1- 3 - 3 int[] input = {4, 2, 1, 3, 3}; WeightedRandom random = factory.apply(input); int[] count = new int[input.length]; for (int i = 0; i < 10000; i++) { int v = random.next(); if (v < 0 || v >= input.length) { throw new RuntimeException("invalid random value: " + v); } count[v]++; } int sum = Arrays.stream(input).sum(); for (int i = 0; i < input.length; i++) { double expectedWeight = (double) input[i] / (double) sum; double realWeight = (double) count[i] / 10000D; if (Math.abs(expectedWeight - realWeight) > 0.01) { throw new RuntimeException( "invalid weight " + realWeight + " for index " + i + ", expected is " + expectedWeight ); } } } } class TestCharDance { public static void testCharDance(Supplier<CharDance> factory) { CharDance charDance = factory.get(); String src = "wosjgncxyakdbefh"; String ops = "M:3,I:7/2,X:o/h"; String dst = "efgwhsjoncxyakdb"; String realDst = charDance.transfer(src, ops); if (!dst.equals(realDst)) { throw new RuntimeException("invalid transfer result " + realDst + ", expected is " + dst); } String dst100 = src; for (int i = 0; i < 100; i++) { dst100 = charDance.transfer(dst100, ops); } String realDst100 = charDance.transferMultipleTimes(src, ops, 100); if (!dst100.equals(realDst100)) { throw new RuntimeException("invalid transfer result " + realDst100 + " after 100 times, expected is " + dst100); } } } class TestAsyncWorker { private static AsyncWorker worker; private static List<Task> tasks; public static void testAsyncWorker(Function<Integer, AsyncWorker> factory) { worker = factory.apply(2); tasks = new ArrayList<>(); runTask(1, 100, 100, false); runTask(2, 200, 200, true); runTask(3, 300, 400, false); runTask(4, 400, 600, true); runTask(5, 100, 500, false); runTask(6, 200, 700, true); runTask(7, 100, 700, false); runTask(8, 200, 900, false); for (Task task : tasks) { check(task); } } private static void runTask(int id, int delay, int expectedDelay, boolean fail) { Task task = new Task(); task.id = id; task.expectedDelay = expectedDelay; task.fail = fail; long now = System.currentTimeMillis(); task.value = worker.submit(() -> { try { Thread.sleep(delay); } catch (InterruptedException ignored) { } long realDelay = System.currentTimeMillis() - now; if (fail) { throw new RuntimeException(String.valueOf(realDelay)); } else { return (int) realDelay; } }); tasks.add(task); } private static class Task { private int id; private int expectedDelay; private boolean fail; private Future<Integer> value; } private static void check(Task task) { int realDelay; boolean realFail = false; try { realDelay = task.value.get(); } catch (Exception e) { realDelay = Integer.parseInt(e.getCause().getMessage()); realFail = true; } if (realFail != task.fail) { throw new RuntimeException( "status of task " + task.id + " should be " + (task.fail ? "failed" : "succeeded") + ", rather than " + (realFail ? "failed" : "succeeded") ); } // 忽略延时误差 if (realDelay / 100 != task.expectedDelay / 100) { throw new RuntimeException( "delay of task " + task.id + " should be " + task.expectedDelay + ", rather than " + realDelay ); } } } public class ShowMeBug { public static void main(String[] args) { TestWeightedRandom.testWeightedRandom(WeightedRandom::new); TestCharDance.testCharDance(CharDance::new); TestAsyncWorker.testAsyncWorker(AsyncWorker::new); } }
人生在勤,不索何获,坚持自有收获