某家宠物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);
}
}
人生在勤,不索何获,坚持自有收获
浙公网安备 33010602011771号