天眼查面试-算法题
2021-01-20下午参加天眼查的视频面试,首先是来了两道算法题目和一道SQL建立索引题目。
努力了不一定会成功,但是不努力一定会失败!!!
一、将两个升序或降序未知的有序链表合并成指定升序或降序的链表
该题算是一个多考查点的题目。
考查点:
(1)判断有序链表是升序还是降序;
(2)反转链表;
(3)合并两个有序链表(同为升序或降序);Leetcode_88;
该题目按照上面三个考查点分别实现三个子函数,即可顺序完成该题目,平时的积累还是很重要的哦。
/**
* 将两个升序或降序未知的有序链表合并成指定升序或降序的链表
* 属于Leetcode_21的变式题
* 网上搜索:https://www.jianshu.com/p/dceced82ad90
* 2021-01-20
* 2021年第一次面试,天眼查,第一道面试题;
* 大体思路完成,但是没有封装listIsAsc方法,欠缺一点点。
*
* 示例:
* 链表A:1->3->4->11
* 链表B:9->3->0
* 指定:升序
* 结果:0->1->3->3->4->9->11
* <p>
* 解题思路:
* 指定升序:两个链表需要转变成升序;
* 指定降序:两个链表要转变成降序;
*/
/**
* 将两个升序降序未知的有序链表合并成指定升序或降序的链表
*/
public ListNode mergeTwoSortedList(ListNode node1, ListNode node2, boolean isAsc) {
//1、将两个链表转变成isAsc顺序一致的链表
if (isAsc) {//两个链表均需要置为升序
if (!listIsAsc(node1)) node1 = reverseList(node1);
if (!listIsAsc(node2)) node2 = reverseList(node2);
} else {//两个链表均需要置为降序
if (listIsAsc(node1)) node1 = reverseList(node1);
if (listIsAsc(node2)) node2 = reverseList(node2);
}
return mergeTwoSameSortedList(node1, node2, isAsc);
}
/**
* 判断链表是否是升序
*/
public boolean listIsAsc(ListNode head) {
if (head == null) return true;
ListNode pre = head;
head = head.next;
while (head != null) {
if (head.val < pre.val) return false;
pre = head;
head = head.next;
}
return true;
}
/**
* 反转链表
*/
public ListNode reverseList(ListNode head) {
if (head == null || head.next == null) return head;
ListNode pre = head;
ListNode curr = head.next;
head.next = null;
while (curr != null) {
ListNode next = curr.next;
curr.next = pre;
pre = curr;
curr = next;
}
return pre;
}
/**
* head1和head2已经按照isAsc排序
* isAsc=true,则head1和head2均升序;
* isAsc=false,则head1和head2均降序;
*/
public ListNode mergeTwoSameSortedList(ListNode head1, ListNode head2, boolean isAsc) {
if (head1 == null) return head2;
if (head2 == null) return head1;
//是否head1优先:isAsc=true,小值优先,反之,大值优先
boolean node1First = isAsc ? (head1.val < head2.val) : (head1.val > head2.val);
if (node1First) {
head1.next = mergeTwoSameSortedList(head1.next, head2, isAsc);
return head1;
} else {
head2.next = mergeTwoSameSortedList(head1, head2.next, isAsc);
return head2;
}
}
class ListNode {
public ListNode next;
public int val;
public ListNode(int val) {
this.val = val;
}
}
/******************测试*********************/
@Test
public void test() {
boolean[] isAsc = new boolean[]{true, false};
for (int i = 0; i < 2; i++) {
ListNode head1 = new ListNode(1);
ListNode node1_2 = new ListNode(3);
ListNode node1_3 = new ListNode(4);
ListNode node1_4 = new ListNode(11);
head1.next = node1_2;
node1_2.next = node1_3;
node1_3.next = node1_4;
ListNode head2 = new ListNode(9);
ListNode node2_2 = new ListNode(3);
ListNode node2_3 = new ListNode(0);
head2.next = node2_2;
node2_2.next = node2_3;
LinkedListUtils.print(mergeTwoSortedList(head1, head2, isAsc[i]));//打印函数自己实现吧
}
}
二、反序列化完全二叉树
/**
* 2021-01-20下午面试第二题(简单)完成
* 完全二叉树序列化后:ABCDEFGHIJKLMNOPQ;
* 将其转换成树结构。
* A
* B C
* D E F G
* H I J K L M N O
* P Q
*/
public TreeNode transferToBinaryTree(char[] chars) {
if (chars == null || chars.length == 0) return null;
TreeNode root = new TreeNode(chars[0]);
Deque<TreeNode> deque = new LinkedList<>();
deque.add(root);
int i = 1;
while (!deque.isEmpty() && i < chars.length) {
TreeNode node = deque.poll();
if (i < chars.length) {
node.left = new TreeNode(chars[i++]);
deque.add(node.left);
}
if (i < chars.length) {
node.right = new TreeNode(chars[i++]);
deque.add(node.right);
}
}
return root;
}
@Test
public void test() {
TreeNode root = transferToBinaryTree("ABCDEFGHIJKLMNOPQ".toCharArray());
List<ArrayList<Integer>> arrayLists = new TraversalByLevelOrZigZag().traversalByEveryLevel(root);
for (ArrayList<Integer> arrayList : arrayLists) {
List<Character> charList = new ArrayList<>();
arrayList.forEach(item -> charList.add((char)item.intValue()));
System.out.println(JSON.toJSONString(charList));
}
}
三、如何建立索引更高效
select e,f from table_1 where a = 3 and b=4 and c != 5 sorted by e limit 100
回答:建立联合索引 a,b,e,f 。 (并没有明确是否正确,如果有更好方式,请指正。)
因为查询a、b都是固定值,e是排序字段,c是不等于无法走索引,查询字段e和f,因此建立a,b,e,f联合索引最高效。
知识点:前缀索引,覆盖索引。
紧接着问了:底层的B+树,聚簇索引、二级索引等。