Skip to content

feat(graph): add DSU-based account merge algorithm#7377

Open
nickzerjeski wants to merge 4 commits intoTheAlgorithms:masterfrom
nickzerjeski:feat-graph-account-merge-dsu-6831
Open

feat(graph): add DSU-based account merge algorithm#7377
nickzerjeski wants to merge 4 commits intoTheAlgorithms:masterfrom
nickzerjeski:feat-graph-account-merge-dsu-6831

Conversation

@nickzerjeski
Copy link
Copy Markdown
Contributor

Description

Add an account merge implementation using Disjoint Set Union (Union-Find).

Fixes #6831

Changes

  • Added AccountMerge.mergeAccounts(List<List<String>>) in com.thealgorithms.graph.
  • Uses path compression + union by rank to merge accounts sharing at least one email.
  • Added tests for:
    • merging shared-email accounts
    • same-name accounts without shared email staying separate
    • empty input

Validation

  • mvn -q -Dtest=AccountMergeTest test

Copilot AI review requested due to automatic review settings April 13, 2026 08:41
@codecov-commenter
Copy link
Copy Markdown

codecov-commenter commented Apr 13, 2026

Codecov Report

❌ Patch coverage is 94.82759% with 3 lines in your changes missing coverage. Please review.
✅ Project coverage is 79.55%. Comparing base (1edf319) to head (fc851fb).

Files with missing lines Patch % Lines
...ain/java/com/thealgorithms/graph/AccountMerge.java 94.82% 1 Missing and 2 partials ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##             master    #7377      +/-   ##
============================================
+ Coverage     79.50%   79.55%   +0.05%     
- Complexity     7142     7161      +19     
============================================
  Files           796      797       +1     
  Lines         23368    23426      +58     
  Branches       4596     4610      +14     
============================================
+ Hits          18578    18636      +58     
- Misses         4050     4051       +1     
+ Partials        740      739       -1     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a Disjoint Set Union (Union-Find) based solution for the “merge accounts by shared email” problem under com.thealgorithms.graph, along with JUnit tests. The PR also introduces a new geometry utility for 2D line segment intersection (with tests) and extends binary search test coverage for null inputs.

Changes:

  • Added AccountMerge.mergeAccounts(...) implementing account merging via DSU (path compression + union by rank).
  • Added AccountMergeTest covering shared-email merges, same-name/no-shared-email separation, and empty input.
  • Added LineIntersection + LineIntersectionTest, and extended IterativeBinarySearchTest for null array/key cases.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
src/main/java/com/thealgorithms/graph/AccountMerge.java New DSU-based account merging implementation.
src/test/java/com/thealgorithms/graph/AccountMergeTest.java Tests for account merging behavior and ordering.
src/main/java/com/thealgorithms/geometry/LineIntersection.java New geometry utility for segment intersection + intersection point computation.
src/test/java/com/thealgorithms/geometry/LineIntersectionTest.java Tests for segment intersection and computed intersection point.
src/test/java/com/thealgorithms/searches/IterativeBinarySearchTest.java Added tests for null array and null key behavior.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +39 to +43
Map<Integer, List<String>> rootToEmails = new LinkedHashMap<>();
for (Map.Entry<String, Integer> entry : emailToAccount.entrySet()) {
int root = dsu.find(entry.getValue());
rootToEmails.computeIfAbsent(root, ignored -> new ArrayList<>()).add(entry.getKey());
}
Copy link

Copilot AI Apr 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Accounts that contain only a name (i.e., no emails) are currently omitted from the output. rootToEmails is populated only by iterating emailToAccount, so accounts with an empty email list never become a root entry and are dropped. Consider explicitly handling accounts with account.size() <= 1 (or no emails after filtering) so they are returned as standalone merged accounts, and add a test for this case.

Copilot uses AI. Check for mistakes.
Comment on lines +65 to +86
double x1 = p1.x();
double y1 = p1.y();
double x2 = p2.x();
double y2 = p2.y();
double x3 = q1.x();
double y3 = q1.y();
double x4 = q2.x();
double y4 = q2.y();

double denominator = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4);
if (denominator == 0.0) {
return Optional.empty();
}

double numeratorX = (x1 * y2 - y1 * x2) * (x3 - x4) - (x1 - x2) * (x3 * y4 - y3 * x4);
double numeratorY = (x1 * y2 - y1 * x2) * (y3 - y4) - (y1 - y2) * (x3 * y4 - y3 * x4);

return Optional.of(new Point2D.Double(numeratorX / denominator, numeratorY / denominator));
}

private static int orientation(Point a, Point b, Point c) {
long cross = (long) (b.x() - a.x()) * (c.y() - a.y()) - (long) (b.y() - a.y()) * (c.x() - a.x());
Copy link

Copilot AI Apr 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

intersectionPoint computes the line intersection using double intermediates derived from int coordinates. For large coordinate values, the products and subtractions in denominator/numerators can lose precision (catastrophic cancellation), which can incorrectly produce denominator == 0.0 or a significantly inaccurate intersection point. Consider performing the determinant arithmetic in long (or BigInteger if you want to be fully safe) and only converting to double at the final division step; also avoid exact == 0.0 checks in favor of an integer-zero check (if using long) or an epsilon (if staying with double).

Suggested change
double x1 = p1.x();
double y1 = p1.y();
double x2 = p2.x();
double y2 = p2.y();
double x3 = q1.x();
double y3 = q1.y();
double x4 = q2.x();
double y4 = q2.y();
double denominator = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4);
if (denominator == 0.0) {
return Optional.empty();
}
double numeratorX = (x1 * y2 - y1 * x2) * (x3 - x4) - (x1 - x2) * (x3 * y4 - y3 * x4);
double numeratorY = (x1 * y2 - y1 * x2) * (y3 - y4) - (y1 - y2) * (x3 * y4 - y3 * x4);
return Optional.of(new Point2D.Double(numeratorX / denominator, numeratorY / denominator));
}
private static int orientation(Point a, Point b, Point c) {
long cross = (long) (b.x() - a.x()) * (c.y() - a.y()) - (long) (b.y() - a.y()) * (c.x() - a.x());
long x1 = p1.x();
long y1 = p1.y();
long x2 = p2.x();
long y2 = p2.y();
long x3 = q1.x();
long y3 = q1.y();
long x4 = q2.x();
long y4 = q2.y();
long det1 = x1 * y2 - y1 * x2;
long det2 = x3 * y4 - y3 * x4;
long denominator = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4);
if (denominator == 0L) {
return Optional.empty();
}
long numeratorX = det1 * (x3 - x4) - (x1 - x2) * det2;
long numeratorY = det1 * (y3 - y4) - (y1 - y2) * det2;
return Optional.of(new Point2D.Double(numeratorX / (double) denominator, numeratorY / (double) denominator));
}
private static int orientation(Point a, Point b, Point c) {
long cross = ((long) b.x() - a.x()) * ((long) c.y() - a.y()) - ((long) b.y() - a.y()) * ((long) c.x() - a.x());

Copilot uses AI. Check for mistakes.
Comment on lines +1 to +12
package com.thealgorithms.geometry;

import java.awt.geom.Point2D;
import java.util.Optional;

/**
* Utility methods for checking and computing 2D line segment intersections.
*/
public final class LineIntersection {
private LineIntersection() {
}

Copy link

Copilot AI Apr 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PR title/description focus on adding a DSU-based account merge algorithm, but this PR also introduces a new geometry algorithm (LineIntersection) and its tests (and separately updates binary search tests). Please either update the PR description/title to reflect these additional changes or split these unrelated additions into separate PRs to keep review scope focused.

Copilot uses AI. Check for mistakes.
@nickzerjeski nickzerjeski force-pushed the feat-graph-account-merge-dsu-6831 branch from 7f0c002 to dbc9534 Compare April 13, 2026 09:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEATURE REQUEST] Add Disjoint Set (Union-Find) Implementation and Account Merge Problem in Graph Section

3 participants