• 2018.09.07阿里巴巴笔试题


    一、有多少种划分方式

    给定一个长度为N的数组,数组中每一项都是[1,10000]且没有重复元素,现在把它划分为若干个子序列,要求:

    • 每个子序列都是等差数列或者等比数列
    • 每个子序列的长度不小于3
    • 子序列中的元素在原数组中可以不相邻,但是下标一定是升序

    问有多少种划分方式?

    这题我能想到的就是暴力。三重for循环确定一个子序列的基调,然后尽量长地扩展出一个长数组,对长数组外的元素递归求解。

    import java.util.LinkedList;
    import java.util.List;
    import java.util.Scanner;
    
    public class Main {
    int[] how = new int[(int) 1e4 + 7];
    
    //获取i,j,k三个首项确定的子序列,用a减去这些元素即得下次需要处理的元素
    List<Integer> get(int i, int j, int k, List<Integer> a) {
        List<Integer> b = new LinkedList<>();
        boolean dengbi = (a.get(j) * a.get(j) == a.get(i) * a.get(k));
        double a0 = a.get(i), d;
        if (dengbi) {
            d = ((double) a.get(j)) / a.get(i);
        } else {
            d = a.get(j) - a.get(i);
        }
        for (int t = k + 1; t < a.size(); t++) {
            if (t == i || t == j || t == k) continue;
            if (dengbi) {
                if (a.get(t) != Math.pow(d, a.size()) * a0) {
                    b.add(a.get(t));
                }
            } else {
                if (a.get(t) != a0 + b.size() * d) {
                    b.add(a.get(t));
                }
            }
        }
        return b;
    }
    
    
    int go(List<Integer> a) {
        if (a.size() < 3) return 0;
        int s = 0;
        //三重for循环遍历首项
        for (int i = 0; i < a.size(); i++) {
            for (int j = i + 1; j < a.size(); j++) {
                for (int k = j + 1; k < a.size(); k++) {
                    if (a.get(j) * 2 == a.get(i) + a.get(k) || a.get(j) * a.get(j) == a.get(i) * a.get(k)) {
                        List<Integer> next = get(i, j, k, a);
                        int sz = a.size() - next.size();
                        if (sz == a.size()) {
                            s += how[sz];
                        } else {
                            s += how[sz] * go(next);
                        }
                    }
                }
            }
        }
        return s;
    }
    
    Main() {
        //初始化how数组,它表示一个尽量等比数列或者等差数列有多少种划分方法
        how[0] = how[1] = how[2] = 0;
        how[3] = 1;
        for (int i = 4; i < how.length; i++) {
            int s = 0;
            for (int j = 3; j < i; j++) {
                s += how[i - j];
            }
            how[i] = s;
        }
        Scanner cin = new Scanner(System.in);
        int n = cin.nextInt();
        int[] a = new int[n];
        for (int i = 0; i < a.length; i++) a[i] = cin.nextInt();
        List<Integer> alink = new LinkedList<>();
        for (int i = 0; i < a.length; i++) alink.add(a[i]);
        System.out.println(go(alink));
    }
    
    public static void main(String[] args) {
        new Main();
    }
    }
    
    
    

    二、计算几何

    给定一个点,一个多边形(可能非凸),问点是否在多边形内,距离多边形的最短距离是多少?

    这道题基本上是套路题。但是只对了80%,不知何故。
    首先,判断点是否在多边形内部,使用射线法,从当前点向一个方向发出一条射线,求射线跟多边形边的交点的个数,如果为奇数个说明在多边形内部。
    其次,求点到多边形的最短距离,直接求点到多边形所有线段的最短距离即可。

    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.List;
    import java.util.Scanner;
    
    public class Main {
    class Point {
        double x, y;
    
        Point(double x, double y) {
            this.x = x;
            this.y = y;
        }
    }
    
    public static boolean IsPtInPoly(Point point, List<Point> pts) {
    
        int N = pts.size();
        boolean boundOrVertex = true; //如果点位于多边形的顶点或边上,也算做点在多边形内,直接返回true
        int intersectCount = 0;//cross points count of x
        double precision = 2e-10; //浮点类型计算时候与0比较时候的容差
        Point p1, p2;//neighbour bound vertices
        Point p = point; //当前点
    
        p1 = pts.get(0);//left vertex
        for (int i = 1; i <= N; ++i) {//check all rays
            if (p.equals(p1)) {
                return boundOrVertex;//p is an vertex
            }
    
            p2 = pts.get(i % N);//right vertex
            if (p.x < Math.min(p1.x, p2.x) || p.x > Math.max(p1.x, p2.x)) {//ray is outside of our interests
                p1 = p2;
                continue;//next ray left point
            }
    
            if (p.x > Math.min(p1.x, p2.x) && p.x < Math.max(p1.x, p2.x)) {//ray is crossing over by the algorithm (common part of)
                if (p.y <= Math.max(p1.y, p2.y)) {//x is before of ray
                    if (p1.x == p2.x && p.y >= Math.min(p1.y, p2.y)) {//overlies on a horizontal ray
                        return boundOrVertex;
                    }
    
                    if (p1.y == p2.y) {//ray is vertical
                        if (p1.y == p.y) {//overlies on a vertical ray
                            return boundOrVertex;
                        } else {//before ray
                            ++intersectCount;
                        }
                    } else {//cross point on the left side
                        double xinters = (p.x - p1.x) * (p2.y - p1.y) / (p2.x - p1.x) + p1.y;//cross point of y
                        if (Math.abs(p.y - xinters) < precision) {//overlies on a ray
                            return boundOrVertex;
                        }
    
                        if (p.y < xinters) {//before ray
                            ++intersectCount;
                        }
                    }
                }
            } else {//special case when ray is crossing through the vertex
                if (p.x == p2.x && p.y <= p2.y) {//p crossing over p2
                    Point p3 = pts.get((i + 1) % N); //next vertex
                    if (p.x >= Math.min(p1.x, p3.x) && p.x <= Math.max(p1.x, p3.x)) {//p.x lies between p1.x & p3.x
                        ++intersectCount;
                    } else {
                        intersectCount += 2;
                    }
                }
            }
            p1 = p2;//next ray left point
        }
    
        if (intersectCount % 2 == 0) {//偶数在多边形外
            return false;
        } else { //奇数在多边形内
            return true;
        }
    
    }
    
    double dis(Point x, Point y) {
        return Math.hypot(x.x - y.x, x.y - y.y);
    }
    
    
    double dis(Point x, Point y, Point z) {//x到线段yz的距离
        double space = 0;
        double a, b, c;
        a = dis(y, z);// 线段的长度
        b = dis(x, y);// (x1,y1)到点的距离
        c = dis(x, z);// (x2,y2)到点的距离
        if (c <= 0.000001 || b <= 0.000001) {
            space = 0;
            return space;
        }
        if (a <= 0.000001) {
            space = b;
            return space;
        }
        if (c * c >= a * a + b * b) {
            space = b;
            return space;
        }
        if (b * b >= a * a + c * c) {
            space = c;
            return space;
        }
        double p = (a + b + c) / 2;// 半周长
        double s = Math.sqrt(p * (p - a) * (p - b) * (p - c));// 海伦公式求面积
        space = 2 * s / a;// 返回点到线的距离(利用三角形面积公式求高)
        return space;
    }
    
    long get(Point p, List<Point> a) {
        double ans = Double.MAX_VALUE;
        for (Point i : a) {
            ans = Math.min(dis(i, p), ans);
        }
        for (int i = 0; i < a.size(); i++) {
            ans = Math.min(ans, dis(p, a.get(i), a.get((i + 1) % a.size())));
        }
        return Math.round(ans);
    }
    
    Main() {
        Scanner cin = new Scanner(System.in);
        double mexy[] = Arrays.stream(cin.next().split(",")).mapToDouble(Double::parseDouble).toArray();
        Point me = new Point(mexy[0], mexy[1]);
        double aa[] = Arrays.stream(cin.next().split(",")).mapToDouble(Double::parseDouble).toArray();
        List<Point> a = new ArrayList<>(aa.length >> 1);
        for (int i = 0; i < aa.length / 2; i++) {
            a.add(new Point(aa[i * 2], aa[i * 2 + 1]));
        }
        boolean x = IsPtInPoly(me, a);
        if (x) {
            System.out.println("yes,0");
        } else {
            long ans = get(me, a);
            if (ans == 0) System.out.println("yes,0");
            else System.out.println("no," + ans);
        }
    }
    
    public static void main(String[] args) {
        new Main();
    }
    }
    
  • 相关阅读:
    定义一个Dog类,它和静态数据成员Dogs记录Dog的个体数目。静态成员函数GetDogs用来存取Dogs。设计并测试这个类--简单
    互联网无插件直播流媒体服务器方案EasyNVR下载新的软件执行程序,出现“invalid license”字样是什么意思?
    视频流媒体服务器RTSP拉流、RTMP推流方案EasyNVR如何实现视频转推其他直播间?
    视频流媒体服务器RTSP拉流、RTMP推流流媒体服务器授权方案之加密机运行后无法授权问题解决
    RTSP安防网络摄像头/海康大华硬盘录像机网页无插件直播之EasyNVR流媒体服务器系列产品直播延时问题解析
    海康大华网络摄像头RTSP_Onvif网页无插件直播流媒体服务器EasyNVR录像版设定录像文件存储位置的方法解析
    同一路摄像头视频流接入RTSP_Onvif网页无插件直播流媒体服务器EasyNVR与其他平台播放视频有差异的原因分析
    RTSP_Onvif安防摄像头直播流媒体服务器EasyNVR产品调用接口出现"Unauthorized"问题的解决方法
    安防摄像头RTSP/Onvif协议网页无插件直播视频流媒体服务器EasyNVR录像回看质量的影响因素有哪些?
    海康、大华等网络摄像头RTSP_Onvif网页无插件直播流媒体服务器EasyNVR在内网环境下,设备不在线问题处理
  • 原文地址:https://www.cnblogs.com/weiyinfu/p/9607131.html
Copyright © 2020-2023  润新知