I've written a java program which which uses the divide and conquer algorithm to find the convex hull of a polygon in a cartesian coordination.
I have a class Coord which has two "double" fields X and y and "this" which I'm using the method on, is a collection of coordinates (set).
my method should return the hull (Collection) of the polygon
My code is like this:
public Collection<Coord> territoire()
{
Collection<Coord> sommets = new ArrayList<Coord>();
ArrayList<Coord> thisToArrList = new ArrayList<Coord>();
for(Coord c : this)
thisToArrList.add(c);
ArrayList<Coord> sortedPointsByX = new ArrayList<Coord>();
int n = this.size();
if (n <= 2)
return this;
//sorting the points by their X coordinates
sortedPointsByX = sortedArrayByX(thisToArrList);
//>>>>>>>>>>>>>>>>>> works good till here <<<<<<<<<<<<<<<<<<<<<<<<
// now sortedPointsByX array contains the points with increasing X
// splitting the sortedPointsByX into two arrays
ArrayList<Coord> firstPart = new ArrayList<Coord>();
ArrayList<Coord> secondPart = new ArrayList<Coord>();
// if the number of the points is prime, the leftmost and the rightmost half
// both have same number of points
if(sortedPointsByX.size() % 2 == 0)
{
for(int i = 0; i < sortedPointsByX.size()/2; i++)
{
firstPart.add(sortedPointsByX.get(i));
}
for(int i = sortedPointsByX.size()/2; i < sortedPointsByX.size(); i++)
{
secondPart.add(sortedPointsByX.get(i));
}
}
//>>>>>>>>>>>>>>>>>>>>>works good till here<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
// if the number of points is odd, the leftmost half have the extra points
else
{
for(int i = 0; i < sortedPointsByX.size()/2+1; i++)
{
firstPart.add(sortedPointsByX.get(i));
}
for(int i = sortedPointsByX.size()/2+1; i < sortedPointsByX.size(); i++)
{
secondPart.add(sortedPointsByX.get(i));
}
}
//>>>>>>>>>>>>>>>>>>>>>>>works good till here<<<<<<<<<<<<<<<<<<<<<<<<<
CoordSet firstSet = new CoordSet(firstPart);
CoordSet secondSet = new CoordSet(secondPart);
// converting the arrays to list of coordinates in order to use recursion over them
//recursion for sub coordsets
Collection<Coord> firstSetSommet = firstSet.territoire();
Collection<Coord> secondSetSommet = secondSet.territoire();
ArrayList<Coord> firstHull = new ArrayList<Coord>(firstSetSommet);
ArrayList<Coord> secondHull = new ArrayList<Coord>(secondSetSommet);
sommets = mergeHulls(firstHull, secondHull);
return sommets;
}
public Collection<Coord> mergeHulls(ArrayList<Coord> firstHull, ArrayList<Coord> secondHull)
{
Collection<Coord> pointsInside = new ArrayList<Coord>();
Collection<Coord> sommets = new ArrayList<Coord>();
//********************upper tangent***************
//find the highest point of the leftmost part
Coord firstPartHighestPoint = getMaxY(firstHull);
//find the highest point of the rightmost part
Coord secondPartHighestPoint = getMaxY(secondHull);
for(int i = 0; i< firstHull.size(); i++)
{
// check if the points lie on the line between highest point in leftmost and in rightmost
// if true, the current point is above the line
if(isCollinear(firstPartHighestPoint, secondPartHighestPoint, firstHull.get(i))>0)
{
// the current point is above the line
firstPartHighestPoint = firstHull.get(i);
}
pointsInside.add(firstPartHighestPoint);
}
for(int i = 0; i < secondHull.size(); i++)
{
if(isCollinear(firstPartHighestPoint, secondPartHighestPoint, secondHull.get(i))>0)
{
// the current point is above the line
secondPartHighestPoint = secondHull.get(i);
}
pointsInside.add(secondPartHighestPoint);
}
//******************lower tangent***************
//find the lowest point of the leftmost part
Coord firstPartLowestPoint = getMinY(firstHull);
// find the lowest point of the rightmost part
Coord secondPartLowestPoint = getMinY(secondHull);
for(int i = 0; i< firstHull.size(); i++)
{
// check if the points lie on the line between highest point in leftmost and in rightmost
// if true, the current point is above the line
if(isCollinear(firstPartLowestPoint, secondPartLowestPoint, firstHull.get(i)) < 0)
{
// the current point is above the line
firstPartLowestPoint = firstHull.get(i);
}
pointsInside.add(firstPartLowestPoint);
}
for(int i = 0; i < secondHull.size(); i++)
{
if(isCollinear(firstPartLowestPoint, secondPartLowestPoint, secondHull.get(i)) < 0)
{
// the current point is above the line
secondPartLowestPoint = secondHull.get(i);
}
pointsInside.add(firstPartLowestPoint);
}
sommets.addAll(firstHull);
sommets.addAll(secondHull);
sommets.removeAll(pointsInside);
return sommets;
}
//**********************************Auxiliary méthods****************************************************
// if the equation is equal to 0, the points are collinear
// the method returns the determinant of the point matrix
// This determinant tells how far point 'c' is from vector ab and on which side
// it is
// < 0 if the point 'c' is below the line (assumption : horizontal line)
// > 0 if the point 'c' is above the line
public double isCollinear(Coord a, Coord b, Coord c)
{
return ((b.x - a.x)*(c.y - a.y) - (b.y - a.y)*(c.x - a.x));
}
//************************************** line equation ************************************************
// find the slope of the line between two points
public static double findSlope(Coord point1, Coord point2)
{
return (point2.y - point1.y)/(point2.x-point1.x);
}
// finding the constant 'b' of the line equation y = xm + b
public static double constantB(Double slope, Coord point)
{
return point.y - slope* point.x;
}
//*************************************** Minimum and Maximum "Y" *****************************************
// the point with maximum Y
public static Coord getMaxY(ArrayList<Coord> points)
{
double maxY = points.get(0).y; // start with the first value
Coord maxPoint = points.get(0);
for (int i=1; i<points.size(); i++) {
if (points.get(i).y > maxY)
{
maxY = points.get(i).y; // new maximum
maxPoint = points.get(i);
}
}
return maxPoint;
}
// a method to find the Point with the minimum y
public static Coord getMinY(ArrayList<Coord> points)
{
double minValue = points.get(0).y;
Coord minPoint = points.get(0);
for(int i=1;i<points.size();i++){
if(points.get(i).y < minValue)
{
minPoint = points.get(i);
minValue = points.get(i).y;
}
}
return minPoint;
}
//************************************** sorting the points ********************************************
//sorting the points by their x in ascending order
public static ArrayList<Coord> sortedArrayByX(ArrayList<Coord> arrayOfPoints)
{
//double minval = arrayOfPoints[0].x;
Coord temp = null;
for(int i = 0; i< arrayOfPoints.size(); i++)
{
for(int j = 0; j< arrayOfPoints.size()-1; j++)
{
if(arrayOfPoints.get(j+1).x < arrayOfPoints.get(j).x)
{
temp = arrayOfPoints.get(j+1);
arrayOfPoints.set(j+1, arrayOfPoints.get(j));
arrayOfPoints.set(j, temp);
}
}
}
return arrayOfPoints;
}
I can't get why when I run the program, the following message shows up:
Exception in thread "main" java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
at java.util.ArrayList.rangeCheck(ArrayList.java:604)
at java.util.ArrayList.get(ArrayList.java:382)
at miniprojet2.CoordSet.getMaxY(CoordSet.java:270)
at miniprojet2.CoordSet.mergeHulls(CoordSet.java:154)
at miniprojet2.CoordSet.territoire(CoordSet.java:139)
at miniprojet2.CalculeTerritoire.main(CalculeTerritoire.java:36)
I'll be so glad if you tell me where I've made a mistake
NOTE: I'm assuming your code fails at firstPart.add(sortedPointsByX.get(i)). If you post an SSCCE, I could provide better assistance.
sortedPointsByX has zero size.
Your code:
for(int i = 0; i < sortedPointsByX.size()/2+1; i++) {
firstPart.add(sortedPointsByX.get(i));
}
thus evaluates to:
for (int i=0; i<(0 / 2) + 1; i++) {
firstPart.add(sortedPointsByX.get(i));
}
which is:
for (int i=0; i<1; i++) {
firstPart.add(sortedPointsByX.get(i));
}
which is, in turn, equivalent to:
firstPart.add(sortedPointsByX.get(0));
However, you can't get the zeroeth element of sortedPointsByX because it is empty.
You can tell all this from your error:
Exception in thread "main" java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
at java.util.ArrayList.rangeCheck(ArrayList.java:604)
An IndexOutOfBoundsException means you tried to access some index i such that i < 0 or i >= size(). The error reports that the size is zero and that you tried to access index 0; thus, 0 ≥ 0 and your code fails.
Related
I'm trying to create two classes, one to define a point and another for array operations. I'm trying to create a method to sort an array of coordinates in ascending order based on y coordinates. I've tried following examples, but I keep running into a runtime error where the array is only partially sorted.
public class Point
{
private double x;
private double y;
public Point(double x_coord, double y_coord)
{
x = x_coord;
y = y_coord;
}
public boolean lessThan(Point anotherPoint)
{
if(y < anotherPoint.y)
{
if(x < anotherPoint.x)
{
return true;
}
}
return false;
}
}
public class PointArray
{
private Point[] points = new Point[count];
public PointArray(double[] doubleArray)
{
if(doubleArray.length % 2 == 0)
{
for(int i = 0, j = 0; i < 3; i++, j += 2)
{
double x = doubleArray[j];
double y = doubleArray[j + 1];
points[i] = new Point(x, y);
}
}
else
{
System.out.println("Error: The given array must be even.");
System.exit(0);
}
}
public void sort()
{
double x = 0;
double y = 0;
Point newPoint = new Point(x, y);
Point temp = new Point(x, y);
for (int i = 0; i < points.length - 1; i++)
{
for(int j = i + 1; j < points.length; j++)
{
int minIndex = i;
if(points[minIndex].lessThan(points[j]) == false)
{
temp = points[minIndex];
points[minIndex] = points[j];
points[j] = temp;
}
}
}
}
This code causes the array {5.6, 7.1, 4.9, 13.17, 9.3, 2.9} to first be stored as ordered pairs {(5.6, 7.1), (4.9, 13.17), (9.3, 2.9)}. but it does not sort them properly. After the first and third points are swapped, the second and third are not, even though the y coordinate of the third is smaller.
[(9.3, 2.9), (4.9, 13.17), (5.6, 7.1)]
EDIT: Another issue appeared related to the same assignment. This method is supposed to take two PointArray objects and compare them for equality by the x and y components. My idea was to sort both arrays and then compare the components using a method in the Point class, but I'm not sure how to define each PointArray in terms of an (x, y) point.
public boolean equals(Point anotherPoint)
{
if(x == anotherPoint.x && y == anotherPoint.y)
{
return true;
}
return false;
}
public boolean equals(PointArray anotherPointArray)
{
double x = 0;
double y = 0;
double xAnother = 0;
double yAnother = 0;
Point newPoint = new Point(x, y);
Point newAnotherPoint = new Point(xAnother, yAnother);
anotherPointArray.sort();
for(int i = 0; i < points.length; i++)
{
for(int j = 0; i < points.length; j++)
{
if(newPoint.equals(newAnotherPoint))
{
return true;
}
}
}
return false;
}
Your current lessThan method will give true only if both x and y are smaller. To sort by y alone use
public boolean lessThan(Point anotherPoint)
{
return y < anotherPoint.y;
}
I'm trying to create an algorithm that returns the closest pair from randomly generated points. I have finished the algorithm, however the divide and conquer method of the algorithm is not much faster than the brute-force method. What can I do to optimize the code so that it returns at (n log n) time?
import java.util.*;
import java.lang.*;
import static java.lang.Math.min;
import static java.lang.StrictMath.abs;
public class closestPair {
private static Random randomGenerator; // for random numbers
public static class Point implements Comparable<Point> {
public long x, y;
// Constructor
public Point(long x, long y) {
this.x = x;
this.y = y;
}
public int compareTo(Point p) {
// compare this and p and there are three results: >0, ==0, or <0
if (this.x == p.x) {
if (this.y == p.y)
return 0;
else
return (this.y > p.y)? 1 : -1;
}
else
return (this.x > p.x)? 1 : -1;
}
public String toString() {
return " ("+Long.toString(this.x)+","+Long.toString(this.y)+")";
}
public double distance(Point p) {
long dx = (this.x - p.x);
long dy = (this.y - p.y);
return Math.sqrt(dx*dx + dy*dy);
}
}
public static Point[] plane;
public static Point[] T;
public static Point[] Y;
public static int N; // number of points in the plane
public static void main(String[] args) {
// Read in the Size of a maze
Scanner scan = new Scanner(System.in);
try {
System.out.println("How many points in your plane? ");
N = scan.nextInt();
}
catch(Exception ex){
ex.printStackTrace();
}
scan.close();
// Create plane of N points.
plane = new Point[N];
Y = new Point[N];
T = new Point[N];
randomGenerator = new Random();
for (int i = 0; i < N; ++i) {
long x = randomGenerator.nextInt(N<<6);
long y = randomGenerator.nextInt(N<<6);
plane[i] = new Point(x, y);
}
Arrays.sort(plane); // sort points according to compareTo.
for (int i = 1; i < N; ++i) // make all x's distinct.
if (plane[i-1].x >= plane[i].x) plane[i].x = plane[i-1].x + 1;
//for (int i = 1; i < N; i++)
// if (plane[i-1].y >= plane[i].y) plane[i].y = plane[i-1].y + 1;
//
//
System.out.println(N + " points are randomly created.");
System.out.println("The first two points are"+plane[0]+" and"+plane[1]);
System.out.println("The distance of the first two points is "+plane[0].distance(plane[1]));
long start = System.currentTimeMillis();
// Compute the minimal distance of any pair of points by exhaustive search.
double min1 = minDisSimple();
long end = System.currentTimeMillis();
System.out.println("The distance of the two closest points by minDisSimple is "+min1);
System.out.println("The running time for minDisSimple is "+(end-start)+" mms");
// Compute the minimal distance of any pair of points by divide-and-conquer
long start1 = System.currentTimeMillis();
double min2 = minDisDivideConquer(0, N-1);
long end1 = System.currentTimeMillis();
System.out.println("The distance of the two closest points by misDisDivideConquer is "+min2);
System.out.println("The running time for misDisDivideConquer is "+(end1-start1)+" mms");
}
static double minDisSimple() {
// A straightforward method for computing the distance
// of the two closest points in plane[0..N-1].
// to be completed
double midDis = Double.POSITIVE_INFINITY;
for (int i = 0; i < N - 1; i++) {
for (int j = i + 1; j < N; j++) {
if (plane[i].distance(plane[j]) < midDis){
midDis = plane[i].distance(plane[j]);
}
}
}
return midDis;
}
static void exchange(int i, int j) {
Point x = plane[i];
plane[i] = plane[j];
plane[j] = x;
}
static double minDisDivideConquer(int low, int high) {
// Initialize necessary values
double minIntermediate;
double minmin;
double minDis;
if (high == low+1) { // two points
if (plane[low].y > plane[high].y) exchange(low, high);
return plane[low].distance(plane[high]);
}
else if (high == low+2) { // three points
// sort these points by y-coordinate
if (plane[low].y > plane[high].y) exchange(low, high);
if (plane[low].y > plane[low+1].y) exchange(low, low+1);
else if (plane[low+1].y > plane[high].y) exchange(low+1, high);
// compute pairwise distances
double d1 = plane[low].distance(plane[high]);
double d2 = plane[low].distance(plane[low+1]);
double d3 = plane[low+1].distance(plane[high]);
return ((d1 < d2)? ((d1 < d3)? d1 : d3) : (d2 < d3)? d2 : d3); // return min(d1, d2, d3)
} else { // 4 or more points: Divide and conquer
int mid = (high + low)/2;
double lowerPartMin = minDisDivideConquer(low,mid);
double upperPartMin = minDisDivideConquer(mid+1,high);
minIntermediate = min(lowerPartMin, upperPartMin);
int k = 0;
double x0 = plane[mid].x;
for(int i = 1; i < N; i++){
if(abs(plane[i].x-x0) <= minIntermediate){
k++;
T[k] = plane[i];
}
}
minmin = 2 * minIntermediate;
for (int i = 1; i < k-1; i++){
for(int j = i + 1; j < min(i+7,k);j++){
double distance0 = abs(T[i].distance(T[j]));
if(distance0 < minmin){
minmin = distance0;
}
}
}
minDis = min(minmin, minIntermediate);
}
return minDis;
}
}
Use the following method with the change for minDisSimple. You can get more performance.
static double minDisSimple() {
// A straightforward method for computing the distance
// of the two closest points in plane[0..N-1].
// to be completed
double midDis = Double.POSITIVE_INFINITY;
double temp;
for (int i = 0; i < N - 1; i++) {
for (int j = i + 1; j < N; j++) {
temp = plane[i].distance(plane[j]);
if (temp < midDis) {
midDis = temp;
}
}
}
return midDis;
}
Performance wise for small amount of points simple method is good but larger amount of points Divide and Conquer is good. Try number of points with 10, 100, 1000, 10000, 100000, 1000000.
One critical aspect in the minDisDivideConquer() is that the loop that constructs the auxiliary array T iterates through all the N points. Since there are O(N) recursive calls in total, making this pass through all the N points every time leads to a complexity of O(N^2), equivalent to that of the simple algorithm.
The loop should actually only consider the points with indices between low and high. Furthermore, it could be split into two separate loops that start from mid (forward and backward), and break when the checked distance is already too large.
Another possible improvement for the minDisDivideConquer() method, in the "4 or more points" situation is to prevent looking into pairs that were already considered in the recursive calls.
If my understanding is correct, the array T contains those points that are close enough on x axis to the mid point, so that there is a chance that a pair of points in T generates a distance smaller than those from the individual half sets.
However, it is not necessary to look into points that are both before mid, or both after mid (since these pairs were already considered in the recursive calls).
Thus, a possible optimization is to construct two lists T_left and T_right (instead of T) and check distances between pairs of points such that one is on the left of mid, and the other to the right.
This way, instead of computing |T| * (|T| - 1) / 2 distances, we would only look into |T_left| * |T_right| pairs, with |T_left| + |T_right| = |T|. This value is at most (|T| / 2) * (|T| / 2) = |T| ^ 2 / 4, i.e. around 2 times fewer distances than before (this is in the worst case, but the actual number of pairs can also be much smaller, inclusively zero).
I have an 2D array(matrix) and a Integer n.n is full square
for example if n equals 16 fill matrix like this.
1 2 3 4
12 13 14 5
11 16 15 6
10 9 8 7
what can I do?
public static void main(String args[]) {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
System.out.print("Enter the dimension of the matrix : ");
int dimension = Integer.parseInt(br.readLine());
System.out.print("Enter the number of elements : ");
int n = Integer.parseInt(br.readLine()); // total number of elements to be filled
n = n/dimension; // Get the number of rows and columns
if(n % dimension != 0){
// Not a Square matrix
}
int circularArray[][] = new int[n][n];
int k = 1, c1 = 0, c2 = n - 1, r1 = 0, r2 = n - 1;
while (k <= n * n) {
for (int i = c1; i <= c2; i++) {
circularArray[r1][i] = k++;
}
for (int j = r1 + 1; j <= r2; j++) {
circularArray[j][c2] = k++;
}
for (int i = c2 - 1; i >= c1; i--) {
circularArray[r2][i] = k++;
}
for (int j = r2 - 1; j >= r1 + 1; j--) {
circularArray[j][c1] = k++;
}
c1++;
c2--;
r1++;
r2--;
}
/* Printing the Circular matrix */
System.out.println("The Circular Matrix is:");
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
System.out.print(circularArray[i][j] + "\t");
}
System.out.println();
}
}
Here is a tiny example how this could look like.
What is actually happening is written as comments.
public class TestArray {
// A simple enum for each direction
public enum Mode {
right, down, left, up;
}
public static void main(String[] args) {
final int size = 4; // We set a fixed size for the square
int[][] arr = new int[size][size]; // create the array from the size
// Running vallues
// i and j to refer to the array.
// val holds the current value to be inserted
// circle holds how often we are going up. Each time we go up it´s increased by one
// In the end this should reduce the amount of steps we do to not override
// already assigned values.
int i = 0,j = 0, val = 1, circle = 0;
Mode runningMode = Mode.right; // We start by going to the right.
while(size*size >= val) { // loop until we reached the last value
arr[j][i] = val++; // Assign the value and increase the value by one afterwards.
// We go right.
if(runningMode == Mode.right) {
// we reached the last assignable item.
// subtract one to not get an index out of bound,
// subract the variable trips that is used to get the last item for the inner circle
if(i==arr.length-1-circle) {
// We are going down now and increase j
runningMode = Mode.down;
++j;
} else {
// go on going right.
++i;
}
} else if(runningMode == Mode.down){
// we reached the last assignable item.
// subtract one to not get an index out of bound,
// subract the variable trips that is used to get the last item for the inner circle
if(j==arr.length-1-circle) {
// We are going left now and decrease i
runningMode = Mode.left;
--i;
} else {
// go on going down.
++j;
}
} else if(runningMode == Mode.left){
// we reached the last assignable item.
// add the variable trips that is used to get the last item for the inner circle
if(i==0+circle) {
// We are going up now and decrease j
// Simultaniosly we are about to end our next circle, so we increase circle
runningMode = Mode.up;
++circle;
--j;
} else {
// go on going left.
--i;
}
} else if(runningMode == Mode.up){
// we reached the last assignable item.
// add the variable trips that is used to get the last item for the inner circle
if(j==0+circle) {
// We are going right now and increase i
runningMode = Mode.right;
++i;
} else {
// go on going up.
--j;
}
}
}
// Print the result
for(int[] a : arr) {
for(int b : a) {
System.out.print(b + "\t" );
}
System.out.println();
}
}
}
In the codility test NumberOfDiscIntersections I am getting perf 100% and correctness 87% with the one test failing being
overflow
arithmetic overflow tests
got -1 expected 2
I can't see what is causing that given that I am using long which is 64-bit. And even if I can get it to 100% perf 100% correctness I am wondering if there is a better way to do this that is not as verbose in Java.
edit: figured out a much better way to do with with two arrays rather than a pair class
// you can also use imports, for example:
import java.util.*;
// you can use System.out.println for debugging purposes, e.g.
// System.out.println("this is a debug message");
class Solution {
public int solution(int[] A) {
int j = 0;
Pair[] arr = new Pair[A.length * 2];
for (int i = 0; i < A.length; i++) {
Pair s = new Pair(i - A[i], true);
arr[j] = s;
j++;
Pair e = new Pair(i + A[i], false);
arr[j] = e;
j++;
}
Arrays.sort(arr, new Pair(0, true));
long numIntersect = 0;
long currentCount = 0;
for (Pair p: arr) {
if (p.start) {
numIntersect += currentCount;
if (numIntersect > 10000000) {
return -1;
}
currentCount++;
} else {
currentCount--;
}
}
return (int) numIntersect;
}
static private class Pair implements Comparator<Pair> {
private long x;
private boolean start;
public Pair(long x, boolean start) {
this.x = x;
this.start = start;
}
public int compare(Pair p1, Pair p2) {
if (p1.x < p2.x) {
return -1;
} else if (p1.x > p2.x) {
return 1;
} else {
if (p1.start && p2.start == false) {
return -1;
} else if (p1.start == false && p2.start) {
return 1;
} else {
return 0;
}
}
}
}
}
Look at this line:
Pair s = new Pair(i + A[i], true);
This is equivalent with Pair s = new Pair((long)(i + A[i]) , true);
As i is integer, and A[i] is also integer, so this can cause overflow, as value in A[i] can go up to Integer.MAX_VALUE, and the cast to long happened after add operation is completed.
To fix:
Pair s = new Pair((long)i + (long)A[i], true);
Note: I have submitted with my fixed and got 100%
https://codility.com/demo/results/demoRRBY3Q-UXH/
My todays solution. O(N) time complexity. Simple assumption that number of availble pairs in next point of the table is difference between total open circle to that moment (circle) and circles that have been processed before. Maybe it's to simple :)
public int solution04(int[] A) {
final int N = A.length;
final int M = N + 2;
int[] left = new int[M]; // values of nb of "left" edges of the circles in that point
int[] sleft = new int[M]; // prefix sum of left[]
int il, ir; // index of the "left" and of the "right" edge of the circle
for (int i = 0; i < N; i++) { // counting left edges
il = tl(i, A);
left[il]++;
}
sleft[0] = left[0];
for (int i = 1; i < M; i++) {// counting prefix sums for future use
sleft[i]=sleft[i-1]+left[i];
}
int o, pairs, total_p = 0, total_used=0;
for (int i = 0; i < N; i++) { // counting pairs
ir = tr(i, A, M);
o = sleft[ir]; // nb of open till right edge
pairs = o -1 - total_used;
total_used++;
total_p += pairs;
}
if(total_p > 10000000){
total_p = -1;
}
return total_p;
}
int tl(int i, int[] A){
int tl = i - A[i]; // index of "begin" of the circle
if (tl < 0) {
tl = 0;
} else {
tl = i - A[i] + 1;
}
return tl;
}
int tr(int i, int[] A, int M){
int tr; // index of "end" of the circle
if (Integer.MAX_VALUE - i < A[i] || i + A[i] >= M - 1) {
tr = M - 1;
} else {
tr = i + A[i] + 1;
}
return tr;
}
My take on this, O(n):
public int solution(int[] A) {
int[] startPoints = new int[A.length];
int[] endPoints = new int[A.length];
int tempPoint;
int currOpenCircles = 0;
long pairs = 0;
//sum of starting and end points - how many circles open and close at each index?
for(int i = 0; i < A.length; i++){
tempPoint = i - A[i];
startPoints[tempPoint < 0 ? 0 : tempPoint]++;
tempPoint = i + A[i];
if(A[i] < A.length && tempPoint < A.length) //first prevents int overflow, second chooses correct point
endPoints[tempPoint]++;
}
//find all pairs of new circles (combinations), then make pairs with exiting circles (multiplication)
for(int i = 0; i < A.length; i++){
if(startPoints[i] >= 2)
pairs += (startPoints[i] * (startPoints[i] - 1)) / 2;
pairs += currOpenCircles * startPoints[i];
currOpenCircles += startPoints[i];
currOpenCircles -= endPoints[i];
if(pairs > 10000000)
return -1;
}
return (int) pairs;
}
The explanation to Helsing's solution part:
if(startPoints[i] >= 2) pairs += (startPoints[i] * (startPoints[i] - 1)) / 2;
is based on mathematical combinations formula:
Cn,m = n! / ((n-m)!.m!
for pairs, m=2 then:
Cn,2 = n! / ((n-2)!.2
Equal to:
Cn,2 = n.(n-1).(n-2)! / ((n-2)!.2
By simplification:
Cn,2 = n.(n-1) / 2
Not a very good performance, but using streams.
List<Long> list = IntStream.range(0, A.length).mapToObj(i -> Arrays.asList((long) i - A[i], (long) i + A[i]))
.sorted((o1, o2) -> {
int f = o1.get(0).compareTo(o2.get(0));
return f == 0 ? o1.get(1).compareTo(o2.get(1)) : f;
})
.collect(ArrayList<Long>::new,
(acc, val) -> {
if (acc.isEmpty()) {
acc.add(0l);
acc.add(val.get(1));
} else {
Iterator it = acc.iterator();
it.next();
while (it.hasNext()) {
long el = (long) it.next();
if (val.get(0) <= el) {
long count = acc.get(0);
acc.set(0, ++count);
} else {
it.remove();
}
}
acc.add(val.get(1));
}
},
ArrayList::addAll);
return (int) (list.isEmpty() ? 0 : list.get(0) > 10000000 ? -1 : list.get(0));
This one in Python passed all "Correctness tests" and failed all "Performance tests" due to O(n²), so I got 50% score. But it is very simple to understand. I just used the right radius (maximum) and checked if it was bigger or equal to the left radius (minimum) of the next circles. I also avoided to use sort and did not check twice the same circle. Later I will try to improve performance, but the problem here for me was the algorithm. I tried to find a very easy solution to help explain the concept. Maybe this will help someone.
def solution(A):
n = len(A)
cnt = 0
for j in range(1,n):
for i in range(n-j):
if(i+A[i]>=i+j-A[i+j]):
cnt+=1
if(cnt>1e7):
return -1
return cnt
In my program, I am attempting to find the closest point from the starting position (0,0), then "move" again to the next point. The points are read in through a file. The next point I am trying to move to is the "closest" point. I use the Pythagorean Theorem to find the distance. But what can I do to "check" the point I am going to to determine if I have already have visited it. For instance, if the point is 0,0, and then it goes to 1,1, how do check to "tell" the program that 0,0 is no longer an option?
public class PointsNStuff {
public static void main(String [] args) {
final int P = StdIn.readInt();
double [] x = new double[P];
double [] y = new double[P];
double [] visit= new double[P]; //Set an array that stores points that have been visited already
double [] math= new double[P]; //Set an array that stores the distance to all the points
for( int i= 0; i< P; i++){ //Store the values from the text file
x[i] = StdIn.readDouble();
y[i] = StdIn.readDouble();
}
double lowX = x[0];
double lowY = y[0];
double highX = x[0];
double highY = y[0];
//Find the lowest X and the lowest Y values:
for (int i = 0; i < P; i++){
if (lowX > x[i])
lowX = x[i];
}for (int i = 0; i < P; i++){
if (lowY > y[i])
lowY = y[i];
}
for (int i = 0; i < P; i++){
if (highX < x[i])
highX = x[i];
}
for (int i = 0; i < P; i++){
if (highY < y[i])
highY = y[i];
}
System.out.println(lowX + " " + lowY);
System.out.println(highX + " " + highY);
System.out.println("");
System.out.println(P);
//Determine the closest point
double xCoord=0.0;
double yCoord=0.0;
double dist = -1.0;
for (int i= 0; i < P; i ++){ //Repeat entire section for all P (number of points)
for (int j = 0; j < P; j++){ //Find the distance between current point and all other points. Go through all points (do the math).
xCoord = x[j]; // # x point
yCoord = y[j]; // # y point
double save= Math.sqrt( ( (xCoord+x[j]) * (xCoord+x[j]) ) + ( (yCoord + y[j]) * (yCoord + y[j]) ) ); //Pythagorean theorem
save = math[j]; //store the distance in the array slot
}
for (int j = 0; j < P; j++){
if (dist < math[j]){
dist = math[j];
//What boolean check can I put here to double check whether I have visited this point already?
xCoord = x[j]; // set the two points to what number they should be at.
yCoord = y[j];
}
}
System.out.println(xCoord + " " + yCoord);
}
}
}
I have not used any points into the Array I named "visit". Any and all help is appreciated! Thanks!
Use ArrayList to Store points,
ArrayList<Double> x = new ArrayList<Double>();
ArrayList<Double> y = new ArrayList<Double>();
add points to arraylist,
for( int i= 0; i< P; i++){ //Store the values from the text file
x.add(StdIn.readDouble());
y.add(StdIn.readDouble());
}
select point from araylist,
x.get(i); insted of x[i];
y.get(i); insted of y[i];
and remove already used points,
x.remove(new Double(used_x_value));
y.remove(new Double(used_y_value));
see Class ArrayList
What you have here is a perfect candidate for encapsulation! I would start by thinking about another object to encapsulate the 'point' concept you keep referring to:
class Point {
private final double x;
private final double y;
public Point(double x, double y) {
this.x = x;
this.y = y;
}
public double getX() {
return x;
}
public double getY() {
return y;
}
}
One minor caveat: this assumes that you will not have duplicate x,y pairs in the input file. If you do, you may need to override hashcode and equals. But if not, this should do it. Then you can put these Points into a data structure ( see HashSet ) like this:
import java.util.Set;
import java.util.HashSet;
public class PointsNStuff {
public static void main(String args[]) {
Set<Point> pointsVisited = new HashSet<>();
//when you visit a point, put it in the set like this
//the numbers are just for example
Point currentPoint = new Point(10.0, 12.0);
pointsVisited.add(currentPoint);
//now in the future you can check if you 'visited' this point
if(!pointsVisited.contains(currentPoint)) {
System.out.println("Haven't been to current point yet...");
}
}
}