• 【面试记录】0 平均分割线段


    记一次之前一个游戏大厂引擎组的面试,由于面试时间有限没有答完这个题,在此做一个记录。

    题目:给出多个 (x, y) 点组成的相连的线段(点的顺序决定连接顺序),以及一个数字 n。返回一组 (x,y)将之前的相连线段平均分成 n 份长度相等的线段。

    思路:
    (1)将所有的点集合所得到的总线段长度算出来。为了方便称呼叫输入的点组成的线叫原线。

    (2)将总长度平分 n 份后算出每段平分的长度。

    (3)然后按原线长度分段截取:若在原线线段上未超出原线两点长度则在该线段上计算新点,如超过了则从下一个原线上的点开始截取(去掉之前截取的部分)

    // NetEaseEngineSecondInterview.cpp : This file contains the 'main' function. Program execution begins and ends there.
    //
    #include <cmath>
    #include <iostream>
    #include <vector>
    
    #define PI 3.1415926
    
    using namespace std;
    
    struct Point {
        float _x;
        float _y;
    };
    
    float CalculateSegmentLength(Point& p1, Point& p2) {
        return sqrt(pow((p2._y - p1._y), 2.0f) + pow((p2._x - p1._x), 2.0f));
    }
    
    // 利用三角函数算出新的点
    // p1, p2: 原线上两点
    // segmentLen: 原先线段上两点
    // targetlen: 新线段需要达到的长度
    Point CreateNewPoint(Point& p1, Point& p2, float targetLen) {
        float slope = (p2._y - p1._y) / (p2._x - p1._x);
        float angle = atan(slope);
        float sinAngle = sin(angle);
        float cosAngle = cos(angle);
        float yIncrement = targetLen * sinAngle;
        float xIncrement = targetLen * cosAngle;
        Point result = { p1._x + xIncrement, p1._y + yIncrement };
        return result;
    }
    
    vector<Point> SegmentSpliter(vector<Point>& input, int n) {
        vector<Point> result;
    
        // 将所有的点集合所得到的总线段长度算出来
        float length = 0.0f;
        vector<float> segmentsLength;
        for (int i = 1; i < input.size(); ++i) {
            float segmentLength = CalculateSegmentLength(input[i - 1], input[i]);
            length += segmentLength;
            segmentsLength.push_back(segmentLength);
        }
    
        // 平分长度
        float newSegmentLength = length / n;
        cout << "new segment length = " << newSegmentLength << endl;
    
        int originSegmentIndex = 0; // 原线段
        int originPointIndex = 0;   // 原线上点的索引
    
        // 使用 n-1 个点分割原线至 n 等分
        while (result.size() < n - 1) {
            float nextSegmentLength = newSegmentLength;
            // 若第一次生成新点(起点为原线的第一个点)
            if (result.empty()) {
                // 若在原线线段上超出原线两点长度,则更新线段长度,并前移起始点
                while (segmentsLength[originSegmentIndex] < nextSegmentLength) {
                    nextSegmentLength -= segmentsLength[originSegmentIndex];
                    originSegmentIndex++;
                    originPointIndex++;
                }
                Point newPoint = CreateNewPoint(input[originPointIndex], input[originPointIndex + 1], nextSegmentLength);
                result.push_back(newPoint);
                // 这里进位原线点索引,因为下一次终点索引是这个指针开始的
                originPointIndex++;
            }
            // 若之前的新生成点集不为空的话,则以最后一个新生成的点索引作为起点
            else {
                Point start = result[result.size() - 1];
                Point end = input[originPointIndex];
                // 计算新点到下一个原线点的距离
                float remainLength = CalculateSegmentLength(start, end);
                while (remainLength < nextSegmentLength) {
                    nextSegmentLength -= remainLength;
                    start = input[originPointIndex];
                    originPointIndex++;
                    end = input[originPointIndex];
                    remainLength = CalculateSegmentLength(start, end);
                }
                Point newPoint = CreateNewPoint(start, end, remainLength);
                result.push_back(newPoint);
            }
        }
    
        return result;
    }
    
    int main()
    {
        // 每条线分割段数
        int n = 3;
    
        Point p1 = { 0.0f, 0.0f };
        Point p2 = { 1.0f, 0.0f };
        Point p3 = { 4.0f, 0.0f };
        Point p4 = { 6.0f, 0.0f };
        vector<Point> test1{ p1, p2, p3, p4 };
        
    
        Point p5 = { -1.0f, -1.0f };
        Point p6 = { 1.0f, 1.0f };
        Point p7 = { 3.0f, 1.0f };
        Point p8 = { 4.0f, -3.0f };
        Point p9 = { 2.0f, -5.0f };
        vector<Point> test2{ p5, p6, p7, p8, p9 };
    
        vector<Point> ans1 = SegmentSpliter(test1, n);
        for (Point p : ans1) {
            cout << p._x << "    " << p._y << endl;
        }
        vector<Point> ans2 = SegmentSpliter(test2, n);
        for (Point p : ans2) {
            cout << p._x << "    " << p._y << endl;
        }
    
        return 0;
    }

    由于第一个 testcase 比较简单,我又加了一个 testcase2。通过 Debug 模式证明是对的。

    运行结果如下:

     欢迎各位提供新的 testcase 或提供更好的解法,不胜感激。

  • 相关阅读:
    NodeJS笔记:处理非utf8编码
    SQL Server存储过程中的异常处理
    "岛主" 同学给我出的算法题
    学 Win32 汇编[18]: 关于压栈(PUSH)与出栈(POP) 之二
    如何在数据表中存取图片 回复 "三足乌" 的问题
    学 Win32 汇编[19]: 查看二进制等相关函数
    如何删除动态数组的指定元素 回复 "Splendour" 的部分问题
    学 Win32 汇编[17]: 关于压栈(PUSH)与出栈(POP) 之一
    学 Win32 汇编[22] 逻辑运算指令: AND、OR、XOR、NOT、TEST
    学 Win32 汇编[20]: 洞察标志寄存器
  • 原文地址:https://www.cnblogs.com/thdt/p/13838814.html
Copyright © 2020-2023  润新知