写在前面

今天舍友参加网易 2016 Java 实习生的网上笔试,一共 24 道题,我也跟着看了几题,整张卷要答得好确实不简单,深感自己基础太过薄弱。其中最后一道题为算法题,蛮写了一个,解法有点笨,不过也能凑活着跑。

题目

现在学校图书馆需要一套借书系统,每个人只需要在网上提交清单即可,一个人一个清单的借书数量上限为n,
每本书用户数字1-n来表示,同时可能有m个人在网上借书,现图书馆办公网中已经提交了一批借书清单在屏幕中,
每行表示一个清单,一行内不同书号以空格区分,最后一行输入n表示结束

请为屏幕中输入的所有借书清单重新排序排序要求:
1.如果两个清单没有交集,则按清单提交次序排序
2.如果两个清单有交集,要求有交集的清单尽量靠在一起,并且按照清单的提交次序排序

输出排序后的清单列表,允许使用JDK中的容器类。

样例输入:
2 3 11
4 8
5 3
2 6 9
5 7
n

样例输出:
2 3 11
5 3
2 6 9
4 8

思路

  • 题目要求的排序是:有交集的清单优先级高,先排;其次才是按清单的起始顺序。
  • 毫无疑问,第一个清单肯定是排第一个位置,那么下一个位置放的清单就从从剩余未排序的清单中找和上一个清单有交集的,并且按照顺序先找到的就能放在这个位置。
  • 如果没能找到跟上一个位置清单有交集的,就重新找和上上个清单有交集的,直到找到第一个清单为止。
  • 如果此时依然没有任何清单与上面已排序的所有清单有交集,那么未排序的第一个清单就放在这个位置,这样就符合题目的两个排序原则。

代码

public class NetEasy {

    //判断arr1和arr2数组是否有交集
    public static boolean isContains(int[] arr1,int[] arr2){
        for(int a : arr1){
            for(int b : arr2){
                if(a == b)  return true;
            }
        }
        return false;
    }

    public static void main(String[] args) {
        //创建原始数据二维数组
        int[][] arr = new int[][]
        {
            {2,3,11},
            {4,8},
            {5,3},
            {2,6,9},
            {5,7}
        };

        //用以保存排序后的清单顺序,保存的值为该清单在初始数组的位置,并为其初始化第一个清单
        List sequence = new ArrayList<Integer>();
        sequence.add(0);

        //用以保存待排序的清单,并为其初始化,除了第一个其他都是待排序
        List remain = new ArrayList<Integer>();
        for(int i = 1;i <= arr.length-1;i++){
            remain.add(i);
        }

        //每一次循环按顺序放置一个清单
        for(int time = 0;time < arr.length-1;time++){
            boolean stop = false;   //是否跳出双重循环的标志
            //从当前要放置清单位置的前一个位置清单进行匹配,如果匹配不到就匹配再前一个位置清单
            for(int i = sequence.size()-1;i>= 0;i--){
                if(stop){       //里层循环匹配到了,跳出当前循环
                    break;
                }
                //从剩余的清单里找进行匹配
                for(int j = 0;j < remain.size();j++){
                    if(isContains(arr[(int) sequence.get(i)], arr[(int) remain.get(j)])){
                        sequence.add(remain.get(j));        //有交集,加到顺序清单
                        remain.remove(j);   //剩余清单中删除该清单
                        stop = true;        
                        break;
                    }

                }
            }
            if(!stop){  //如果这个清单跟前面已排序的所有清单都没有交集,也把当前剩余清单中顺序最前面的加进去
                sequence.add(remain.get(0));
                remain.remove(0);
            }
            stop = true;
        }

        //打印排序后
        System.out.println("排序后:");
        for(int i = 0; i < arr.length; i++){
            for(int j = 0;j < arr[(int) sequence.get(i)].length;j++){       
                System.out.print(arr[(int) sequence.get(i)][j] + " ");
            }
            System.out.println();
        }

    }
}

补充

由于前面写的时候漏看题目要求,所以这里写的样例不是通过键盘输入的,而是用数组存放,但是后面需要判断数组有效长度,所以也没更改了。算法整体冗长但是相对好理解,题目本身不算难,不过说实话要在规定答卷时间解出来真是不容易。