帆软后端笔试(9.10~9.13)
下午参加了帆软后端的笔试,其中包含6道单选,4道多选,5道逻辑填空题,以及一道算法题。总体感觉偏难,以下印象比较深的一道逻辑题及算法题进行介绍。
-
有一道逻辑题比较有意思,大意是存在1000份水与1份无色试剂,提供若干可与该试剂反应的试纸,每次反应的时间为20分钟,如果需要在1个小时内找出该试剂,大致需要多少张试纸?
提示:每张试纸可以滴不受数量限制的样品,滴样品时间不受限制。
这道题分析有点类似于二分查找,但由于反应时间的限制,相对更加复杂,后来想想这点没分析好,填的结果并不对。。。
-
另一道是算法题:假设有n个链表,每个链表长度的不一,链表中每个的节点包含key与value。不同链表比较时,如果key值相同,则value相加,题目目标是将n个无序链表转化为单个有序链表。
链表数目 n与单个链表长度k1, k2, ..., kn,及每个节点信息需要通过控制台扫描输入,控制台中的节点形式为 1:2,因此需要对此字符串解析。这道题糅合了控制台输入解析,链表排序,链表合并,如果单个链表长度为50万到100万时,需要考虑如何优化链表排序与链表合并。
最开始打算 key与value保存在hashmap, 但感觉由hashmap构造链表不合适,其实节点类定义key与value也可以解决问题,这道题感觉还是挺难的,没a出来。。。
下面是提交后写的答案,参考了链表排序(leetcode 148)与合并k个升序链表(leetcode 23)
public class SortLinkedListDemo {
/*测试用例依次为 链表数目为3 单个链表长度分别为2、3、4,以及每个节点长度
3 2 3 4
1:2 2:3
3:4 2:7 4:3
7:3 9:1 4:3 12:2*/
public static void main(String[] args) throws IOException {
ListNode[] listNodes = scannrValue();
for (int i = 0; i < listNodes.length; i++) {
listNodes[i]=sortSingleList(listNodes[i]);
}
ListNode head = mergeKLists(listNodes);
//输出检验
int count = 0;
while (head != null) {
System.out.println("count: " + (++count) + " key: " + head.key + " val: " + head.val);
head = head.next;
}
}
//扫描输入
private static ListNode[] scannrValue() {
Scanner sc = new Scanner(System.in);
int linkedListNum = sc.nextInt();//链表数目
int[] linkedListLength = new int[linkedListNum];
for (int i = 0; i < linkedListNum; i++) {
//保存每个链表长度
linkedListLength[i] = sc.nextInt();
}
//节点解析,并将每个链表头结点保存在ListNode[]数组中
ListNode[] listNodes = new ListNode[linkedListNum];
for (int i = 0; i < linkedListNum; i++) {
ListNode dummy = new ListNode(0, 0);
ListNode cur = dummy;
dummy.next = cur;
for (int j = 0; j < linkedListLength[i]; j++) {
//节点解析
String[] str = sc.next().split(":");
ListNode temp = new ListNode(Integer.parseInt(str[0]), Integer.parseInt(str[1]));
cur.next = temp;
cur = temp;
}
//添加头结点
listNodes[i] = dummy.next;
}
return listNodes;
}
//采用归并进行链表排序
public static ListNode sortSingleList(ListNode head) {
if (head == null || head.next == null) return head;
ListNode slow = head, fast = head, pre = head;
while (fast != null && fast.next != null) {
pre = slow;//这两步顺序很重要
slow = slow.next;
fast = fast.next.next;
}
pre.next = null;
return merge(sortSingleList(head), sortSingleList(slow));
}
//输入两个链表头节点,返回合并后头节点
private static ListNode merge(ListNode l1, ListNode l2) {
if (l1 == null) return l2;
if (l2 == null) return l1;
ListNode cur = null;
if (l1.key == l2.key) {
l1.next = merge(l1.next, l2.next);
l1.val +=l2.val;
cur = l1;
}
if (l1.key < l2.key) {
l1.next = merge(l1.next, l2);
cur = l1;
}
if (l1.key > l2.key) {
l2.next = merge(l1, l2.next);
cur = l2;
}
return cur;
}
//n个链表合并
public static ListNode mergeKLists(ListNode[] lists) {
if (lists == null || lists.length == 0) return null;
if (lists.length == 1) return lists[0];
if (lists.length == 2) return merge(lists[0], lists[1]);
return merge(mergeKLists(Arrays.copyOfRange(lists, 0, lists.length / 2)),
mergeKLists(Arrays.copyOfRange(lists, lists.length / 2, lists.length)));
}
//节点定义
static class ListNode {
//模拟包含键值对类型链表
private int key;
private int val;
private ListNode next;
public ListNode(int key, int val) {
this.key = key;
this.val = val;
}
}
}
