网易2016研发工程师编程题--完全解析

前言

之前做公司的真题,碰到动态规划,还有一些数学性质的题目比较多一点。网易2016研发工程师编程题跟之前做的题目有很大的不同,不仅涉及到二叉树的编码,还涉及到图的广度遍历,最后还有一个快排。可以说这次的三个题目含金量非常的高,因此做了一下总结和分析。


1.比较重量

题目描述:小明陪小红去看钻石,他们从一堆钻石中随机抽取两颗并比较她们的重量。这些钻石的重量各不相同。在他们们比较了一段时间后,它们看中了两颗钻石g1和g2。现在请你根据之前比较的信息判断这两颗钻石的哪颗更重。

给定两颗钻石的编号g1,g2,编号从1开始,同时给定关系数组vector,其中元素为一些二元组,第一个元素为一次比较中较重的钻石的编号,第二个元素为较轻的钻石的编号。最后给定之前的比较次数n。请返回这两颗钻石的关系,若g1更重返回1,g2更重返回-1,无法判断返回0。输入数据保证合法,不会有矛盾情况出现。
测试样例:
2 , 3,[ [1 , 2 ] , [ 2 , 4 ] , [ 1 , 3 ] , [ 4 , 3 ] ] , 4
返回: 1

题目分析

其实这个题目就是有向图的问题,如果 g1 比 g2大那么有向图中从g1到g2一定有一条路径,反之如果g2比g1大那么有向图中g2到g1一定有一条路径。样例中的有向图如下:

这里写图片描述
上图中2到3存在有向边因此 编号2 比 编号3 重。题目给出的二维数组构成一个图,如果要比较a b的大小,可以从a开始遍历其子节点,如果能够找到从a到b的通路就证明 a比b大。下面就可以用广度优先遍历,来求图中两个节点之间是否存在通路。

 public static int cmp(int g1, int g2, int[][] records, int n) {

         HashMap<Integer, ArrayList<Integer>> map=new HashMap<Integer, ArrayList<Integer>>();

         //hashmap中key对应的是节点值,value里面存放该节点的所有相邻连通子节点。这样便于广度遍历。

         for(int i=0;i<n;i++)
         {
           //对于每一个头节点加入所有相邻连通子节点

             if(map.containsKey(records[i][0]))
             {
                map.get(records[i][0]).add(records[i][1]);

             }
             else {
                ArrayList<Integer> list=new ArrayList<Integer>();
                list.add(records[i][1]);
                map.put(records[i][0], list);                
            }
         }
         if(judge(map, g1, g2))
         {
             return 1;
             //judge函数用于判断是否存在连通路径。
         }
         else if(judge(map, g2, g1))
         {
             return -1;
         }
         return 0;
     }
     public static boolean judge(HashMap<Integer, ArrayList<Integer>> map,int head,int next)
     {
         Queue<Integer> queue=new LinkedList<Integer>();
         ArrayList<Integer> list=new ArrayList<Integer>();//list用于去重,遍历过的节点不再遍历。
         queue.add(head);//广度遍历
         while(!queue.isEmpty())
         {
             int val=queue.poll();
             if(val==next)
                 return true;//如果next是head连通路径中的,则可知next<head 
             list.add(val);
             ArrayList<Integer> list2=map.get(val);//将val的所有子节点加入到queue中,广度遍历。
             if(list2!=null)//此处null判断的原因是有的节点没有指向其他节点的有向边。              
             for(int i=0;i<list2.size();i++)
             {
                 if(!list.contains(list2.get(i)))
                 {
                     queue.add(list2.get(i));
                 }
             }

         }       
         return false;
     }

2.二叉树

题目描述:有一棵二叉树,树上每个点标有权值,权值各不相同,请设计一个算法算出权值最大的叶节点到权值最小的叶节点的距离。二叉树每条边的距离为1,一个节点经过多少条边到达另一个节点为这两个节点之间的距离。给定二叉树的根节点root,请返回所求距离。

题目分析

看到这个题目,最直观的的感受是先求出最大叶节点,和最小叶节点,再求出它们共同最近的祖先节点,但是最近的祖先节点不好求,因为节点的指针是单向的。因此这种方法不行。一个比较巧妙的方法是对二叉树节点进行编码,然后对编码进行处理,如下图:
这里写图片描述
如上图max叶节点的编码为:1 1 1 1 。min叶节点的编码为1 1 0 0。max节点和min节点的距离为:max编码的长度-2+min编码的长度-2;其中2为min编码和max编码前面重叠部分的长度。了解了思路代码就比较好写了。

public class Main_2 {
    static int max=Integer.MIN_VALUE,min=Integer.MAX_VALUE;
    static String maxcode;
    static String mincode;
    public static void main(String[] args) {

    }
    public int getDis(TreeNode root) {
       if(root==null)
           return 0;
        preorder(root, "", '0');
        int i=0;
        while(i<maxcode.length()&&i<mincode.length()&&maxcode.charAt(i)==mincode.charAt(i))
            ++i;

        return maxcode.length()+mincode.length()-2*i;
    }
    public static void preorder(TreeNode root,String codes,char code)
    {
        codes=codes+code;
        if(root==null)
            return;
        if(root.left==null&&root.right==null)
        {
            if(max<root.val)
            {
                max=root.val;
                maxcode=codes;
            }
            if(min>root.val)
            {
                min=root.val;
                mincode=codes;
            }
            return;
        }
        preorder(root.left, codes, '0');
        preorder(root.right, codes, '1');
    }
}
 class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;
    public TreeNode(int val) {
        this.val = val;
    }
}

3寻找第k大的数

题目描述:有一个整数数组,请你根据快速排序的思路,找出数组中第K大的数。
给定一个整数数组a,同时给定它的大小n和要找的K(K在1到n之间),请返回第K大的数,保证答案存在。
测试样例:

[ 1 , 3 , 5 , 2 2 ] , 5 , 3

返回: 2

题目分析

这个题目就是快排的思想,快速排序以某个数为基点,比其小的数放在其左边,比其大的数放在其右边,一趟排序完成后,如果这个数恰好放在第k个位置,则左边的k个数是最小的k个数。如果把比其大的数放在其左边,比其小的数放在其右边,一趟排序完后,如果这个数恰好放在第k个位置,则左边的k个数是最大的k个数。
关于快排可以看看这篇博客:http://blog.csdn.net/u013309870/article/details/68921848

package 网易2016研发工程师编程题;

import java.util.Scanner;

public class Main_3 {

    public static void main(String[] args) {
        Scanner sc=new Scanner(System.in);
        while(sc.hasNext())
        {
            int n=sc.nextInt();
            int k=sc.nextInt();
            int []a=new int[n];
            for(int i=0;i<n;i++)
                a[i]=sc.nextInt();
            findKth(a, n, k);
        }
        sc.close();

    }
     public static  void findKth(int[] a, int n, int K) {         

         System.out.println(findKth(a, 0, n, K));       
     }
     public static int findKth(int[] a, int left,int right, int K) {
         if(left>=right)
             return 0;
         int val=a[left];
         int i=left,j=right-1;
         while(i<j)
         {
             while(i<j&&a[j]<val)
                 j--;
             a[i]=a[j];
             while(i<j&&a[i]>=val)
                 i++;
             a[j]=a[i];          
         }
         a[i]=val;
         if(i==K-1)
         {
             return a[i];
         }
         return findKth(a, left,i, K)+findKth(a, i+1,right, K);

     }
}

总结

网易2016研发工程师编程题中的这三道题目的含金量还是比较高的,特别是前面两道题目的那种思维也是之前刷题的时候没有碰到的,对于这种解法比较新颖的题目,有必要完全弄懂,并做记录。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值