综述:其中两道算法+一道mysql题目【没合适的,投递了测开,哈哈哈】全A
算法1
数组中的逆序对【剑指Offer 51. 数组中的逆序对】
题目描述:在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。
思路:按照归并排序的思想去处理;
「归并排序」与「逆序对」是息息相关的。归并排序体现了 “分而治之” 的算法思想,具体为:
分: 不断将数组从中点位置划分开(即二分法),将整个数组的排序问题转化为子数组的排序问题;
治: 划分到子数组长度为 1 时,开始向上合并,不断将 较短排序数组 合并为 较长排序数组,直至合并至原数组时完成排序;
合并阶段 本质上是 合并两个排序数组 的过程,而每当遇到 左子数组当前元素 > 右子数组当前元素 时,意味着 「左子数组当前元素 至 末尾元素」 与 「右子数组当前元素」 构成了若干 「逆序对」
下面是一个数组归并排序的示例:
class Solution {
int[] nums, tmp;
public int reversePairs(int[] nums) {
this.nums = nums;
tmp = new int[nums.length];
return mergeSort(0, nums.length - 1);
}
private int mergeSort(int l, int r) {
// 终止条件
if (l >= r) return 0;
// 递归划分
int m = (l + r) / 2;
int res = mergeSort(l, m) + mergeSort(m + 1, r);
// 合并阶段
int i = l, j = m + 1;
for (int k = l; k <= r; k++)
tmp[k] = nums[k];
for (int k = l; k <= r; k++) {
if (i == m + 1)
nums[k] = tmp[j++];
else if (j == r + 1 || tmp[i] <= tmp[j])
nums[k] = tmp[i++];
else {
nums[k] = tmp[j++];
res += m - i + 1; // 统计逆序对
}
}
return res;
}
}
问题2
问题描述:
有一棵二叉树,树上每个点标有权值,权值各不相同,请设计一个算法算出权值最大的叶节点到权值最小的叶节点的距离。二叉树每条边的距离为1,一个节点经过多少条边到达另一个节点为这两个节点之间的距离。
思路 来源
思路1:典型的二进制编码题,算出叶子节点二进制编码,再比编码,计算后缀长度和
思路2:先找到最大最小节点位置,在找出最近的公共祖先,在分别计算到公共祖先的距离,在求和,虽然麻烦,但很通俗易懂
代码1
//典型的二进制编码题,算出叶子节点二进制编码,再比编码,计算后缀长度和
import java.util.*;
/*
public class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val) {
this.val = val;
}
}*/
public class Tree {
private int max=0;
private int min=99999;
private StringBuilder maxcodec;
private StringBuilder mincodec;
void PreOrder(TreeNode T,char code,StringBuilder codec){
if(T!=null){
codec.append(code);
if(T.left==null && T.right==null)
{
if(max<T.val)
{
max=T.val;
maxcodec = codec;
}
if(min>T.val)
{
min=T.val;
mincodec = codec;
}
}
PreOrder(T.left,'0',new StringBuilder(codec));
PreOrder(T.right,'1',new StringBuilder(codec));
}
}
public int getDis(TreeNode root) {
PreOrder(root,'0',new StringBuilder());
int index=0;
for(index=0; index<(maxcodec.length()>mincodec.length()?maxcodec.length():mincodec.length());index++)
{
if(maxcodec.charAt(index)!=mincodec.charAt(index))
break;
}
return (maxcodec.substring(index).length()+mincodec.substring(index).length());
// write code here
}
}
代码2
import java.util.*;
/*
public class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val) {
this.val = val;
}
}*/
public class Tree {
private TreeNode maxNode = new TreeNode(Integer.MIN_VALUE);
private TreeNode minNode = new TreeNode(Integer.MAX_VALUE);
public int getDis(TreeNode root) {
// write code here
getMaxMin(root);//找到最大最小叶子节点
TreeNode lcaNode = getLCA(root);//找LCA
int a = getNodeDis(lcaNode, maxNode);//最大值叶子节点到LCA的距离;
int b = getNodeDis(lcaNode, minNode);//最小值叶子节点到LCA的距离;
return a+b;
}
// 先找到最大最小叶子节点
public void getMaxMin(TreeNode root) {
if (root == null) {
return;
}
if (root.left == null && root.right == null) {
if (root.val > maxNode.val) {
maxNode = root;
} else if (root.val < minNode.val) {
minNode = root;
}
}
getMaxMin(root.left);
getMaxMin(root.right);
}
// LCA最近公共祖先
public TreeNode getLCA(TreeNode root) {
if (root == null) {// 说明是空树
return null;
}
if (root.val == maxNode.val || root.val == minNode.val) {// 在当前树的根节点上找到两个节点之一
return root;
}
TreeNode leftNode = getLCA(root.left);// 左子树中的查找两个节点并返回查找结果
TreeNode rightNode = getLCA(root.right);// 右子树中查找两个节点并返回查找结果
if (leftNode == null) {// 左子树中没找到,则一定在右子树上
return rightNode;
} else if (rightNode == null) {// 右子树没找到一定在左子树上
return leftNode;
} else {// 左右子树均找到一个节点,则根节点为最近公共祖先
return root;
}
}
//获取叶子节点到LCA距离
public int getNodeDis(TreeNode lcaNode, TreeNode node){
if(lcaNode==null){
return -1;
}
if(lcaNode.val==node.val){
return 0;
}
//三种情况:两个均在左子树;两个均在右子树;一左一右,所以不能用if-elseif结构
int distance = getNodeDis(lcaNode.left, node);//左子树未找到两个节点之一
if(distance==-1){
distance = getNodeDis(lcaNode.right, node);
}
if(distance!=-1){
return distance+1;
}
return -1;
}
}