今日头条机试题

//描述:具体的文字已经没法还原,大概意思是:二维坐标里有N个点,从任意一点出发,只能向上向下向左向右四个方向走,碰到其他点才可以改变方向,请问至少要补充多少点可以跑遍所有点。

//分析:图的遍历!!当时机试时没想到,脑子短路了!直接上代码!
package shangjiceshi.jinritoutiao;

import java.util.*;

//8:35起做题, 9:40结束,仅仅是编码,思考和测试的时间没有算入!!!!一个半小时最多做一道题!!!后来又花了一些时间修改了几个关键点,之前漏掉了,表示绝望!!!
//现在想想不难,其实就是图的遍历,但是实现起来非常复杂!!!!


public class JinRiTouTiaoTest2 {

    public static void main(String[] args) {
        @SuppressWarnings("resource")
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        HashMap<String, Point> points = new HashMap<>();
        for(int i = 0; i < n; i++) {
            int x = sc.nextInt();
            int y = sc.nextInt();
            String key = x + "_" + y;
            points.put(key, new Point(x,y,key));
        }
        solve(points);
    }
    
    private static void solve(HashMap<String, Point> points) {
        HashMap<String, Boolean> isTo = new HashMap<>();  //标记是否经历过该点,key为点的key
        for(String key: points.keySet()) {
            isTo.put(key, false);
        }
        int num = 0; //外层遍历的次数
        HashMap<Integer, HashSet<Point> > xMap = constructXMap(points);  //从横坐标能拿到的点的集合的Map
        HashMap<Integer, HashSet<Point> > yMap = constructYMap(points);  //类似上面
        for(String key: isTo.keySet()) {
            if(isTo.get(key) == true) {
                continue;
            }
            num++;
            traverse(points, isTo, xMap, yMap, points.get(key));  //内层遍历
        }
        System.out.println(num-1);
    }

    private static HashMap<Integer, HashSet<Point>> constructXMap(HashMap<String, Point> points) {
        HashMap<Integer, HashSet<Point>> result = new HashMap<>();
        for(Point value: points.values()) {
            int x = value.x;
            HashSet<Point> set = null;
            if(!result.containsKey(x)) {
                set = new HashSet<>();
                result.put(x, set);
            } else {
                set = result.get(x);
            }
            set.add(value);
        }
        return result;
    }

    private static HashMap<Integer, HashSet<Point>> constructYMap(HashMap<String, Point> points) {
        HashMap<Integer, HashSet<Point>> result = new HashMap<>();
        for(Point value: points.values()) {
            int y = value.y;
            HashSet<Point> set = null;
            if(!result.containsKey(y)) {
                set = new HashSet<>();
                result.put(y, set);
            } else {
                set = result.get(y);
            }
            set.add(value);
        }
        return result;
    }
    
    private static void traverse(HashMap<String, Point> points, HashMap<String, Boolean> isTo,
            HashMap<Integer, HashSet<Point>> xMap, HashMap<Integer, HashSet<Point>> yMap, Point point) {
        //这几个参数都是非常重要的数据结构!!!!能快速拿到想要的数据!!!!
        HashSet<Integer> xset = new HashSet<>();   //已经到达的x坐标的集合,内部遍历很重要的数据结构
        HashSet<Integer> yset = new HashSet<>();   //已经到达的y坐标的集合,内部遍历很重要的数据结构
        LinkedList<Point> list = new LinkedList<>(); //尚未遍历的点,包括一些已经遍历过的,重复没关系,会有一种机制会去除
        list.add(point);
        while(!list.isEmpty()) {
            Point p = list.removeFirst();
            if(isTo.get(p.key) == true) {    //开始漏掉了,这个地方很重要!!!!否则非常耗性能!!
                continue;
            }
            isTo.put(p.key, true);    //标记已经经过,很重要!内部遍历重复没关系
            if(!xset.contains(p.x)) {
                list.addAll(xMap.get(p.x));    //加入了一些遍历过的点,所有没遍历的点也在其中
                xset.add(p.x);     //这个地方开始也漏掉了。。。。。。也是很伤!!!!!
            }
            if(!yset.contains(p.y)) {    
                list.addAll(yMap.get(p.y));   //同上
                yset.add(p.y);                //同上
            }
        }
    }
    
    public static class Point {
        int x;
        int y;
        String key;  //key由x_y组成
        public Point(int x, int y, String key) {
            this.x = x;
            this.y = y;
            this.key = key;
        }
    }
}

 

  

posted @ 2018-01-28 10:32  torypprop  阅读(301)  评论(0)    收藏  举报