给定两个整数数组,X 和 Y 表示 XY 平面中的点。计算由每个可能的坐标对形成的相交线段对的数量。
Example:
Input: X = [0, 1, 0, 1], Y = [0, 1, 3, 2]
Output: 14
Explanation:
For simplicity let’s denote A = [0, 0], B = [1, 1], C = [1, 2], D = [0, 3].
- Line segment between point (A, B) and point (A, C) intersects.
- Line segment between point (A, B) and point (A, D) intersects.
- Line segment between point (A, B) and point (B, D) intersects.
- Line segment between point (A, B) and point (C, D) intersects.
- Line segment between point (A, B) and point (B, C) intersects.
- Line segment between point (A, C) and point (C, D) intersects.
- Line segment between point (A, C) and point (B, D) intersects
- Line segment between point (A, C) and point (A, D) intersects.
- Line segment between point (A, C) and point (B, C) intersects..
- Line segment between point (A, D) and point (B, D) intersects.
- Line segment between point (A, D) and point (C, D) intersects.
- Line segment between point (B, C) and point (B, D) intersects.
- Line segment between point (B, C) and point (C, D) intersects.
- Line segment between point (B, D) and point (C, D) intersects.
Input: X = [0, 0, 0, 2], Y = [0, 2, 4, 0]
Output: 6
天真的方法:
- 将所有坐标对存储在数据结构中。
- 对于每对坐标对检查是否有平行。如果它们不平行,那么这条线必须相交。将答案加 1。
时间复杂度: O(N^4)
有效的方法:
- 对于每对坐标,存储一条直线的这些参数(斜率、x 轴或 y 轴上的截距)。
- 对于平行于 X 轴的线:
- 斜率 = 0,截距 = Y[i]
- 对于平行于 Y 轴的线:
- 斜率 = INF,截距 = X[i]
- 对于所有其他线路:
- 斜率 = (dy/dx = (y2 – y1)/(x2 – x1)
- 为了计算截距,我们知道一条线的一般形式,即 y = (dy/dx)*x + c
- 当线本身通过 (x1, y1) 时,用 y1 代替 y 和 x1 代替 x。
- 经过上述步骤,我们得到Intercept = (y1*dx – x1*dy)/dx
- 那么对于每一行,我们有三种情况:
- 一条线可以与其他一些线具有相同的斜率和相同的截距。这些线不会相交,因为它们基本上是同一条线。
- 一条线可以与另一条线具有相同的斜率和不同的截距。这些线也不会相交,因为它们是平行的。
- 一条线可以与其他线有不同的斜率。无论它们的截距如何,这些线肯定会相交。
- 存储相同斜率线的频率 根据上述条件维护一张地图并固定线段的类型并计算与剩余线相交的线段数。
笔记:
在下面的实现中,我们避免了使用双精度来避免由于精度错误引起的错误。
下面是上述方法的实现:
C++
// C++ program for the above approach
#include
using namespace std;
// Function to calculate total pairs
// of intersecting lines
int totalPairsOfIntersectineLines(
int X[], int Y[], int N)
{
// Set to check the occurences
// of slope and intercept
// It will store the slope dy/dx
// as {dy, dx} and intercept as {c1, c2}
set, pair > > st;
// Map to keep track of count of slopes
map, int> mp;
for (int i = 0; i < N; i++) {
for (int j = i + 1; j < N; j++) {
// Numerator of the slope
int dx = X[j] - X[i];
// Denominator of the slope
int dy = Y[j] - Y[i];
// Making dx and dy coprime
// so that we do not repeat
int g = __gcd(dx, dy);
dx /= g, dy /= g;
// Checking for lines parallel to y axis
if (dx == 0) {
// Intercepts of the line
int c1, c2;
c1 = X[i];
c2 = INT_MAX;
// pair to check the previous occurence of
// the line parameters
pair, pair > pr
= { { dx, dy }, { c1, c2 } };
if (st.find(pr) != st.end()) {
// Do nothing as this line is same just
// an etenstion to some line with same
// slope and intercept
}
else {
// Insert this line to the set
st.insert(pr);
// increase the count of the slope of
// this line
mp[pr.first]++;
}
}
// Checking for lines parallel to x- axis
else if (dy == 0) {
int c1, c2;
c2 = Y[i];
c1 = INT_MAX;
pair, pair > pr
= { { dx, dy }, { c1, c2 } };
if (st.find(pr) != st.end()) {
// Do nothing as this line is same just
// an etenstion to some line with same
// slope and intercept
}
else {
// Insert this line to the set
st.insert(pr);
// increase the count of the slope of
// this line
mp[pr.first]++;
}
}
else {
int c1, c2;
// c1 = y*dx - dy*dx
// If one of them is negative, then
// generalising that dx is negative and dy
// is positive so that we don't repeat
if (dx > 0 && dy < 0) {
dx *= -1, dy *= -1;
}
// Calculating the intercepts
c1 = Y[i] * dx - dy * X[i];
c2 = dx;
// Normalising the intercepts
int g2 = __gcd(c1, c2);
c1 /= g2, c2 /= g2;
pair, pair > pr
= { { dx, dy }, { c1, c2 } };
if (st.find(pr) != st.end()) {
// Do nothing as this line is same just
// an etenstion to some line with same
// slope and intercept
}
else {
// Insert this line to the set
st.insert(pr);
// increase the count of the slope of
// this line
mp[pr.first]++;
}
}
}
}
// vector for storing all the counts
// of the lines with different parameters
vector v;
for (auto count : mp) {
v.push_back(count.second);
}
// Counting all different line segments
int cnt = accumulate(v.begin(), v.end(), 0);
// Variable to store the count
int ans = 0;
for (int i = 0; i < v.size(); i++) {
// Decreasing the count by current line segments
// which will be parallel to each other
cnt -= v[i];
// Intersecting all other line
// segments with this line segment
ans += cnt * v[i];
}
return ans;
}
// Driver Code
int main()
{
// Given Input
int N = 4;
int X[] = { 0, 1, 0, 1 };
int Y[] = { 0, 1, 3, 2 };
// Function call
cout << totalPairsOfIntersectineLines(X, Y, N);
return 0;
}
输出
14
时间复杂度:O(N*N*logN)
空间复杂度:O(N)
如果您希望与专家一起参加现场课程,请参阅DSA 现场工作专业课程和学生竞争性编程现场课程。