Related
Given an array A of N integers we draw N discs in a 2D plane, such that i-th disc has center in (0,i) and a radius A[i]. We say that k-th disc and j-th disc intersect, if k-th and j-th discs have at least one common point.
Write a function
int number_of_disc_intersections(int[] A);
which given an array A describing N discs as explained above, returns the number of pairs of intersecting discs. For example, given N=6 and
A[0] = 1
A[1] = 5
A[2] = 2
A[3] = 1
A[4] = 4
A[5] = 0
there are 11 pairs of intersecting discs:
0th and 1st
0th and 2nd
0th and 4th
1st and 2nd
1st and 3rd
1st and 4th
1st and 5th
2nd and 3rd
2nd and 4th
3rd and 4th
4th and 5th
so the function should return 11.
The function should return -1 if the number of intersecting pairs exceeds 10,000,000. The function may assume that N does not exceed 10,000,000.
O(N) complexity and O(N) memory solution.
private static int Intersections(int[] a)
{
int result = 0;
int[] dps = new int[a.length];
int[] dpe = new int[a.length];
for (int i = 0, t = a.length - 1; i < a.length; i++)
{
int s = i > a[i]? i - a[i]: 0;
int e = t - i > a[i]? i + a[i]: t;
dps[s]++;
dpe[e]++;
}
int t = 0;
for (int i = 0; i < a.length; i++)
{
if (dps[i] > 0)
{
result += t * dps[i];
result += dps[i] * (dps[i] - 1) / 2;
if (10000000 < result) return -1;
t += dps[i];
}
t -= dpe[i];
}
return result;
}
So you want to find the number of intersections of the intervals [i-A[i], i+A[i]].
Maintain a sorted array (call it X) containing the i-A[i] (also have some extra space which has the value i+A[i] in there).
Now walk the array X, starting at the leftmost interval (i.e smallest i-A[i]).
For the current interval, do a binary search to see where the right end point of the interval (i.e. i+A[i]) will go (called the rank). Now you know that it intersects all the elements to the left.
Increment a counter with the rank and subtract current position (assuming one indexed) as we don't want to double count intervals and self intersections.
O(nlogn) time, O(n) space.
Python 100 / 100 (tested) on codility, with O(nlogn) time and O(n) space.
Here is #noisyboiler's python implementation of #Aryabhatta's method with comments and an example.
Full credit to original authors, any errors / poor wording are entirely my fault.
from bisect import bisect_right
def number_of_disc_intersections(A):
pairs = 0
# create an array of tuples, each containing the start and end indices of a disk
# some indices may be less than 0 or greater than len(A), this is fine!
# sort the array by the first entry of each tuple: the disk start indices
intervals = sorted( [(i-A[i], i+A[i]) for i in range(len(A))] )
# create an array of starting indices using tuples in intervals
starts = [i[0] for i in intervals]
# for each disk in order of the *starting* position of the disk, not the centre
for i in range(len(starts)):
# find the end position of that disk from the array of tuples
disk_end = intervals[i][1]
# find the index of the rightmost value less than or equal to the interval-end
# this finds the number of disks that have started before disk i ends
count = bisect_right(starts, disk_end )
# subtract current position to exclude previous matches
# this bit seemed 'magic' to me, so I think of it like this...
# for disk i, i disks that start to the left have already been dealt with
# subtract i from count to prevent double counting
# subtract one more to prevent counting the disk itsself
count -= (i+1)
pairs += count
if pairs > 10000000:
return -1
return pairs
Worked example: given [3, 0, 1, 6] the disk radii would look like this:
disk0 ------- start= -3, end= 3
disk1 . start= 1, end= 1
disk2 --- start= 1, end= 3
disk3 ------------- start= -3, end= 9
index 3210123456789 (digits left of zero are -ve)
intervals = [(-3, 3), (-3, 9), (1, 1), (1,3)]
starts = [-3, -3, 1, 1]
the loop order will be: disk0, disk3, disk1, disk2
0th loop:
by the end of disk0, 4 disks have started
one of which is disk0 itself
none of which could have already been counted
so add 3
1st loop:
by the end of disk3, 4 disks have started
one of which is disk3 itself
one of which has already started to the left so is either counted OR would not overlap
so add 2
2nd loop:
by the end of disk1, 4 disks have started
one of which is disk1 itself
two of which have already started to the left so are either counted OR would not overlap
so add 1
3rd loop:
by the end of disk2, 4 disks have started
one of which is disk2 itself
two of which have already started to the left so are either counted OR would not overlap
so add 0
pairs = 6
to check: these are (0,1), (0,2), (0,2), (1,2), (1,3), (2,3),
Well, I adapted Falk Hüffner's idea to c++, and made a change in the range.
Opposite to what is written above, there is no need to go beyond the scope of the array (no matter how large are the values in it).
On Codility this code received 100%.
Thank you Falk for your great idea!
int number_of_disc_intersections ( const vector<int> &A ) {
int sum=0;
vector<int> start(A.size(),0);
vector<int> end(A.size(),0);
for (unsigned int i=0;i<A.size();i++){
if ((int)i<A[i]) start[0]++;
else start[i-A[i]]++;
if (i+A[i]>=A.size()) end[A.size()-1]++;
else end[i+A[i]]++;
}
int active=0;
for (unsigned int i=0;i<A.size();i++){
sum+=active*start[i]+(start[i]*(start[i]-1))/2;
if (sum>10000000) return -1;
active+=start[i]-end[i];
}
return sum;
}
This can even be done in linear time [EDIT: this is not linear time, see comments]. In fact, it becomes easier if you ignore the fact that there is exactly one interval centered at each point, and just treat it as a set of start- and endpoints of intervals. You can then just scan it from the left (Python code for simplicity):
from collections import defaultdict
a = [1, 5, 2, 1, 4, 0]
start = defaultdict(int)
stop = defaultdict(int)
for i in range(len(a)):
start[i - a[i]] += 1
stop[i + a[i]] += 1
active = 0
intersections = 0
for i in range(-len(a), len(a)):
intersections += active * start[i] + (start[i] * (start[i] - 1)) / 2
active += start[i]
active -= stop[i]
print intersections
Here's a O(N) time, O(N) space algorithm requiring 3 runs across the array and no sorting, verified scoring 100%:
You're interested in pairs of discs. Each pair involves one side of one disc and the other side of the other disc. Therefore we won't have duplicate pairs if we handle one side of each disc. Let's call the sides right and left (I rotated the space while thinking about it).
An overlap is either due to a right side overlapping another disc directly at the center (so pairs equal to the radius with some care about the array length) or due to the number of left sides existing at the rightmost edge.
So we create an array that contains the number of left sides at each point and then it's a simple sum.
C code:
int solution(int A[], int N) {
int C[N];
int a, S=0, t=0;
// Mark left and middle of disks
for (int i=0; i<N; i++) {
C[i] = -1;
a = A[i];
if (a>=i) {
C[0]++;
} else {
C[i-a]++;
}
}
// Sum of left side of disks at location
for (int i=0; i<N; i++) {
t += C[i];
C[i] = t;
}
// Count pairs, right side only:
// 1. overlaps based on disk size
// 2. overlaps based on disks but not centers
for (int i=0; i<N; i++) {
a = A[i];
S += ((a<N-i) ? a: N-i-1);
if (i != N-1) {
S += C[((a<N-i) ? i+a: N-1)];
}
if (S>10000000) return -1;
}
return S;
}
I got 100 out of 100 with this C++ implementation:
#include <map>
#include <algorithm>
inline bool mySortFunction(pair<int,int> p1, pair<int,int> p2)
{
return ( p1.first < p2.first );
}
int number_of_disc_intersections ( const vector<int> &A ) {
int i, size = A.size();
if ( size <= 1 ) return 0;
// Compute lower boundary of all discs and sort them in ascending order
vector< pair<int,int> > lowBounds(size);
for(i=0; i<size; i++) lowBounds[i] = pair<int,int>(i-A[i],i+A[i]);
sort(lowBounds.begin(), lowBounds.end(), mySortFunction);
// Browse discs
int nbIntersect = 0;
for(i=0; i<size; i++)
{
int curBound = lowBounds[i].second;
for(int j=i+1; j<size && lowBounds[j].first<=curBound; j++)
{
nbIntersect++;
// Maximal number of intersections
if ( nbIntersect > 10000000 ) return -1;
}
}
return nbIntersect;
}
A Python answer
from bisect import bisect_right
def number_of_disc_intersections(li):
pairs = 0
# treat as a series of intervals on the y axis at x=0
intervals = sorted( [(i-li[i], i+li[i]) for i in range(len(li))] )
# do this by creating a list of start points of each interval
starts = [i[0] for i in intervals]
for i in range(len(starts)):
# find the index of the rightmost value less than or equal to the interval-end
count = bisect_right(starts, intervals[i][1])
# subtract current position to exclude previous matches, and subtract self
count -= (i+1)
pairs += count
if pairs > 10000000:
return -1
return pairs
100/100 c#
class Solution
{
class Interval
{
public long Left;
public long Right;
}
public int solution(int[] A)
{
if (A == null || A.Length < 1)
{
return 0;
}
var itervals = new Interval[A.Length];
for (int i = 0; i < A.Length; i++)
{
// use long to avoid data overflow (eg. int.MaxValue + 1)
long radius = A[i];
itervals[i] = new Interval()
{
Left = i - radius,
Right = i + radius
};
}
itervals = itervals.OrderBy(i => i.Left).ToArray();
int result = 0;
for (int i = 0; i < itervals.Length; i++)
{
var right = itervals[i].Right;
for (int j = i + 1; j < itervals.Length && itervals[j].Left <= right; j++)
{
result++;
if (result > 10000000)
{
return -1;
}
}
}
return result;
}
}
I'm offering one more solution because I did not find the counting principle of the previous solutions easy to follow. Though the results are the same, an explanation and more intuitive counting procedure seems worth presenting.
To begin, start by considering the O(N^2) solution that iterates over the discs in order of their center points, and counts the number of discs centered to the right of the current disc's that intersect the current disc, using the condition current_center + radius >= other_center - radius. Notice that we could get the same result counting discs centered to the left of the current disc using the condition current_center - radius <= other_center + radius.
def simple(A):
"""O(N^2) solution for validating more efficient solution."""
N = len(A)
unique_intersections = 0
# Iterate over discs in order of their center positions
for j in range(N):
# Iterate over discs whose center is to the right, to avoid double-counting.
for k in range(j+1, N):
# Increment cases where edge of current disk is at or right of the left edge of another disk.
if j + A[j] >= k - A[k]:
unique_intersections += 1
# Stop early if we have enough intersections.
# BUT: if the discs are small we still N^2 compare them all and time out.
if unique_intersections > 10000000:
return -1
return unique_intersections
We can go from O(N^2) to O(N) if we could only "look up" the number of discs to the right (or to the left!) that intersect the current disc. The key insight is to reinterpret the intersection condition as "the right edge of one disc overlaps the left edge of another disc", meaning (a ha!) the centers don't matter, only the edges.
The next insight is to try sorting the edges, taking O(N log N) time. Given a sorted array of the left edges and a sorted array of the right edges, as we scan our way from left to right along the number line, the number of left or right edges to the left of the current location point is simply the current index into left_edges and right_edges respectively: a constant-time deduction.
Finally, we use the "right edge > left edge" condition to deduce that the number of intersections between the current disc and discs that start only to the left of the current disc (to avoid duplicates) is the number of left edges to the left of the current edge, minus the number of right edges to the left of the current edge. That is, the number of discs starting to left of this one, minus the ones that closed already.
Now for this code, tested 100% on Codility:
def solution(A):
"""O(N log N) due to sorting, with O(N) pass over sorted arrays"""
N = len(A)
# Left edges of the discs, in increasing order of position.
left_edges = sorted([(p-r) for (p,r) in enumerate(A)])
# Right edges of the discs, in increasing order of position.
right_edges = sorted([(p+r) for (p,r) in enumerate(A)])
#print("left edges:", left_edges[:10])
#print("right edges:", right_edges[:10])
intersections = 0
right_i = 0
# Iterate over the discs in order of their leftmost edge position.
for left_i in range(N):
# Find the first right_edge that's right of or equal to the current left_edge, naively:
# right_i = bisect.bisect_left(right_edges, left_edges[left_i])
# Just scan from previous index until right edge is at or beyond current left:
while right_edges[right_i] < left_edges[left_i]:
right_i += 1
# Count number of discs starting left of current, minus the ones that already closed.
intersections += left_i - right_i
# Return early if we find more than 10 million intersections.
if intersections > 10000000:
return -1
#print("correct:", simple(A))
return intersections
Java 2*100%.
result is declared as long for a case codility doesn't test, namely 50k*50k intersections at one point.
class Solution {
public int solution(int[] A) {
int[] westEnding = new int[A.length];
int[] eastEnding = new int[A.length];
for (int i=0; i<A.length; i++) {
if (i-A[i]>=0) eastEnding[i-A[i]]++; else eastEnding[0]++;
if ((long)i+A[i]<A.length) westEnding[i+A[i]]++; else westEnding[A.length-1]++;
}
long result = 0; //long to contain the case of 50k*50k. codility doesn't test for this.
int wests = 0;
int easts = 0;
for (int i=0; i<A.length; i++) {
int balance = easts*wests; //these are calculated elsewhere
wests++;
easts+=eastEnding[i];
result += (long) easts*wests - balance - 1; // 1 stands for the self-intersection
if (result>10000000) return -1;
easts--;
wests-= westEnding[i];
}
return (int) result;
}
}
Swift 4 Solution 100% (Codility do not check the worst case for this solution)
public func solution(_ A : inout [Int]) -> Int {
// write your code in Swift 4.2.1 (Linux)
var count = 0
let sortedA = A.sorted(by: >)
if sortedA.isEmpty{ return 0 }
let maxVal = sortedA[0]
for i in 0..<A.count{
let maxIndex = min(i + A[i] + maxVal + 1,A.count)
for j in i + 1..<maxIndex{
if j - A[j] <= i + A[i]{
count += 1
}
}
if count > 10_000_000{
return -1
}
}
return count
}
Here my JavaScript solution, based in other solutions in this thread but implemented in other languages.
function solution(A) {
let circleEndpoints = [];
for(const [index, num] of Object.entries(A)) {
circleEndpoints.push([parseInt(index)-num, true]);
circleEndpoints.push([parseInt(index)+num, false]);
}
circleEndpoints = circleEndpoints.sort(([a, openA], [b, openB]) => {
if(a == b) return openA ? -1 : 1;
return a - b;
});
let openCircles = 0;
let intersections = 0;
for(const [endpoint, opening] of circleEndpoints) {
if(opening) {
intersections += openCircles;
openCircles ++;
} else {
openCircles --;
}
if(intersections > 10000000) return -1;
}
return intersections;
}
count = 0
for (int i = 0; i < N; i++) {
for (int j = i+1; j < N; j++) {
if (i + A[i] >= j - A[j]) count++;
}
}
It is O(N^2) so pretty slow, but it works.
This is a ruby solution that scored 100/100 on codility. I'm posting it now because I'm finding it difficult to follow the already posted ruby answer.
def solution(a)
end_points = []
a.each_with_index do |ai, i|
end_points << [i - ai, i + ai]
end
end_points = end_points.sort_by { |points| points[0]}
intersecting_pairs = 0
end_points.each_with_index do |point, index|
lep, hep = point
pairs = bsearch(end_points, index, end_points.size - 1, hep)
return -1 if 10000000 - pairs + index < intersecting_pairs
intersecting_pairs += (pairs - index)
end
return intersecting_pairs
end
# This method returns the maximally appropriate position
# where the higher end-point may have been inserted.
def bsearch(a, l, u, x)
if l == u
if x >= a[u][0]
return u
else
return l - 1
end
end
mid = (l + u)/2
# Notice that we are searching in higher range
# even if we have found equality.
if a[mid][0] <= x
return bsearch(a, mid+1, u, x)
else
return bsearch(a, l, mid, x)
end
end
Probably extremely fast. O(N). But you need to check it out. 100% on Codility.
Main idea:
1. At any point of the table, there are number of circles "opened" till the right edge of the circle, lets say "o".
2. So there are (o-1-used) possible pairs for the circle in that point. "used" means circle that have been processed and pairs for them counted.
public int solution(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;
}
private 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;
}
There are a lot of great answers here already, including the great explanation from the accepted answer. However, I wanted to point out a small observation about implementation details in the Python language.
Originally, I've came up with the solution shown below. I was expecting to get O(N*log(N)) time complexity as soon as we have a single for-loop with N iterations, and each iteration performs a binary search that takes at most log(N).
def solution(a):
import bisect
if len(a) <= 1:
return 0
cuts = [(c - r, c + r) for c, r in enumerate(a)]
cuts.sort(key=lambda pair: pair[0])
lefts, rights = zip(*cuts)
n = len(cuts)
total = 0
for i in range(n):
r = rights[i]
pos = bisect.bisect_right(lefts[i+1:], r)
total += pos
if total > 10e6:
return -1
return total
However, I've get O(N**2) and a timeout failure. Do you see what is wrong here? Right, this line:
pos = bisect.bisect_right(lefts[i+1:], r)
In this line, you are actually taking a copy of the original list to pass it into binary search function, and it totally ruins the efficiency of the proposed solution! It makes your code just a bit more consice (i.e., you don't need to write pos - i - 1) but heavily undermies the performance. So, as it was shown above, the solution should be:
def solution(a):
import bisect
if len(a) <= 1:
return 0
cuts = [(c - r, c + r) for c, r in enumerate(a)]
cuts.sort(key=lambda pair: pair[0])
lefts, rights = zip(*cuts)
n = len(cuts)
total = 0
for i in range(n):
r = rights[i]
pos = bisect.bisect_right(lefts, r)
total += (pos - i - 1)
if total > 10e6:
return -1
return total
It seems that sometimes one could be too eager about making slices and copies because Python allows you to do it so easily :) Probably not a great insight, but for me it was a good lesson to pay more attention to these "technical" moments when converting ideas and algorithms into real-word solutions.
I know that this is an old questions but it is still active on codility.
private int solution(int[] A)
{
int openedCircles = 0;
int intersectCount = 0;
We need circles with their start and end values. For that purpose I have used Tuple.
True/False indicates if we are adding Circle Starting or Circle Ending value.
List<Tuple<decimal, bool>> circles = new List<Tuple<decimal, bool>>();
for(int i = 0; i < A.Length; i ++)
{
// Circle start value
circles.Add(new Tuple<decimal, bool>((decimal)i - (decimal)A[i], true));
// Circle end value
circles.Add(new Tuple<decimal, bool>((decimal)i + (decimal)A[i], false));
}
Order "circles" by their values.
If one circle is ending at same value where other circle is starting, it should be counted as intersect (because of that "opening" should be in front of "closing" if in same point)
circles = circles.OrderBy(x => x.Item1).ThenByDescending(x => x.Item2).ToList();
Counting and returning counter
foreach (var circle in circles)
{
// We are opening new circle (within existing circles)
if(circle.Item2 == true)
{
intersectCount += openedCircles;
if (intersectCount > 10000000)
{
return -1;
}
openedCircles++;
}
else
{
// We are closing circle
openedCircles--;
}
}
return intersectCount;
}
Javascript solution 100/100 based on this video https://www.youtube.com/watch?v=HV8tzIiidSw
function sortArray(A) {
return A.sort((a, b) => a - b)
}
function getDiskPoints(A) {
const diskStarPoint = []
const diskEndPoint = []
for(i = 0; i < A.length; i++) {
diskStarPoint.push(i - A[i])
diskEndPoint.push(i + A[i])
}
return {
diskStarPoint: sortArray(diskStarPoint),
diskEndPoint: sortArray(diskEndPoint)
};
}
function solution(A) {
const { diskStarPoint, diskEndPoint } = getDiskPoints(A)
let index = 0;
let openDisks = 0;
let intersections = 0;
for(i = 0; i < diskStarPoint.length; i++) {
while(diskStarPoint[i] > diskEndPoint[index]) {
openDisks--
index++
}
intersections += openDisks
openDisks++
}
return intersections > 10000000 ? -1 : intersections
}
so, I was doing this test in Scala and I would like to share here my example. My idea to solve is:
Extract the limits to the left and right of each position on the array.
A[0] = 1 --> (0-1, 0+1) = A0(-1, 1)
A[1] = 5 --> (1-5, 1+5) = A1(-4, 6)
A[2] = 2 --> (2-2, 2+2) = A2(0, 4)
A[3] = 1 --> (3-1, 3+1) = A3(2, 4)
A[4] = 4 --> (4-4, 4+4) = A4(0, 8)
A[5] = 0 --> (5-0, 5+0) = A5(5, 5)
Check if there is intersections between any two positions
(A0_0 >= A1_0 AND A0_0 <= A1_1) OR // intersection
(A0_1 >= A1_0 AND A0_1 <= A1_1) OR // intersection
(A0_0 <= A1_0 AND A0_1 >= A1_1) // one circle contain inside the other
if any of these two checks is true count one intersection.
object NumberOfDiscIntersections {
def solution(a: Array[Int]): Int = {
var count: Long = 0
for (posI: Long <- 0L until a.size) {
for (posJ <- (posI + 1) until a.size) {
val tupleI = (posI - a(posI.toInt), posI + a(posI.toInt))
val tupleJ = (posJ - a(posJ.toInt), posJ + a(posJ.toInt))
if ((tupleI._1 >= tupleJ._1 && tupleI._1 <= tupleJ._2) ||
(tupleI._2 >= tupleJ._1 && tupleI._2 <= tupleJ._2) ||
(tupleI._1 <= tupleJ._1 && tupleI._2 >= tupleJ._2)) {
count += 1
}
}
}
count.toInt
}
}
This got 100/100 in c#
class CodilityDemo3
{
public static int GetIntersections(int[] A)
{
if (A == null)
{
return 0;
}
int size = A.Length;
if (size <= 1)
{
return 0;
}
List<Line> lines = new List<Line>();
for (int i = 0; i < size; i++)
{
if (A[i] >= 0)
{
lines.Add(new Line(i - A[i], i + A[i]));
}
}
lines.Sort(Line.CompareLines);
size = lines.Count;
int intersects = 0;
for (int i = 0; i < size; i++)
{
Line ln1 = lines[i];
for (int j = i + 1; j < size; j++)
{
Line ln2 = lines[j];
if (ln2.YStart <= ln1.YEnd)
{
intersects += 1;
if (intersects > 10000000)
{
return -1;
}
}
else
{
break;
}
}
}
return intersects;
}
}
public class Line
{
public Line(double ystart, double yend)
{
YStart = ystart;
YEnd = yend;
}
public double YStart { get; set; }
public double YEnd { get; set; }
public static int CompareLines(Line line1, Line line2)
{
return (line1.YStart.CompareTo(line2.YStart));
}
}
}
Thanks to Falk for the great idea! Here is a ruby implementation that takes advantage of sparseness.
def int(a)
event = Hash.new{|h,k| h[k] = {:start => 0, :stop => 0}}
a.each_index {|i|
event[i - a[i]][:start] += 1
event[i + a[i]][:stop ] += 1
}
sorted_events = (event.sort_by {|index, value| index}).map! {|n| n[1]}
past_start = 0
intersect = 0
sorted_events.each {|e|
intersect += e[:start] * (e[:start]-1) / 2 +
e[:start] * past_start
past_start += e[:start]
past_start -= e[:stop]
}
return intersect
end
puts int [1,1]
puts int [1,5,2,1,4,0]
#include <stdio.h>
#include <stdlib.h>
void sortPairs(int bounds[], int len){
int i,j, temp;
for(i=0;i<(len-1);i++){
for(j=i+1;j<len;j++){
if(bounds[i] > bounds[j]){
temp = bounds[i];
bounds[i] = bounds[j];
bounds[j] = temp;
temp = bounds[i+len];
bounds[i+len] = bounds[j+len];
bounds[j+len] = temp;
}
}
}
}
int adjacentPointPairsCount(int a[], int len){
int count=0,i,j;
int *bounds;
if(len<2) {
goto toend;
}
bounds = malloc(sizeof(int)*len *2);
for(i=0; i< len; i++){
bounds[i] = i-a[i];
bounds[i+len] = i+a[i];
}
sortPairs(bounds, len);
for(i=0;i<len;i++){
int currentBound = bounds[i+len];
for(j=i+1;a[j]<=currentBound;j++){
if(count>100000){
count=-1;
goto toend;
}
count++;
}
}
toend:
free(bounds);
return count;
}
An Implementation of Idea stated above in Java:
public class DiscIntersectionCount {
public int number_of_disc_intersections(int[] A) {
int[] leftPoints = new int[A.length];
for (int i = 0; i < A.length; i++) {
leftPoints[i] = i - A[i];
}
Arrays.sort(leftPoints);
// System.out.println(Arrays.toString(leftPoints));
int count = 0;
for (int i = 0; i < A.length - 1; i++) {
int rpoint = A[i] + i;
int rrank = getRank(leftPoints, rpoint);
//if disk has sifnificant radius, exclude own self
if (rpoint > i) rrank -= 1;
int rank = rrank;
// System.out.println(rpoint+" : "+rank);
rank -= i;
count += rank;
}
return count;
}
public int getRank(int A[], int num) {
if (A==null || A.length == 0) return -1;
int mid = A.length/2;
while ((mid >= 0) && (mid < A.length)) {
if (A[mid] == num) return mid;
if ((mid == 0) && (A[mid] > num)) return -1;
if ((mid == (A.length - 1)) && (A[mid] < num)) return A.length;
if (A[mid] < num && A[mid + 1] >= num) return mid + 1;
if (A[mid] > num && A[mid - 1] <= num) return mid - 1;
if (A[mid] < num) mid = (mid + A.length)/2;
else mid = (mid)/2;
}
return -1;
}
public static void main(String[] args) {
DiscIntersectionCount d = new DiscIntersectionCount();
int[] A =
//{1,5,2,1,4,0}
//{0,0,0,0,0,0}
// {1,1,2}
{3}
;
int count = d.number_of_disc_intersections(A);
System.out.println(count);
}
}
Here is the PHP code that scored 100 on codility:
$sum=0;
//One way of cloning the A:
$start = array();
$end = array();
foreach ($A as $key=>$value)
{
$start[]=0;
$end[]=0;
}
for ($i=0; $i<count($A); $i++)
{
if ($i<$A[$i])
$start[0]++;
else
$start[$i-$A[$i]]++;
if ($i+$A[$i] >= count($A))
$end[count($A)-1]++;
else
$end[$i+$A[$i]]++;
}
$active=0;
for ($i=0; $i<count($A);$i++)
{
$sum += $active*$start[$i]+($start[$i]*($start[$i]-1))/2;
if ($sum>10000000) return -1;
$active += $start[$i]-$end[$i];
}
return $sum;
However I dont understand the logic. This is just transformed C++ code from above. Folks, can you elaborate on what you were doing here, please?
A 100/100 C# implementation as described by Aryabhatta (the binary search solution).
using System;
class Solution {
public int solution(int[] A)
{
return IntersectingDiscs.Execute(A);
}
}
class IntersectingDiscs
{
public static int Execute(int[] data)
{
int counter = 0;
var intervals = Interval.GetIntervals(data);
Array.Sort(intervals); // sort by Left value
for (int i = 0; i < intervals.Length; i++)
{
counter += GetCoverage(intervals, i);
if(counter > 10000000)
{
return -1;
}
}
return counter;
}
private static int GetCoverage(Interval[] intervals, int i)
{
var currentInterval = intervals[i];
// search for an interval starting at currentInterval.Right
int j = Array.BinarySearch(intervals, new Interval { Left = currentInterval.Right });
if(j < 0)
{
// item not found
j = ~j; // bitwise complement (see Array.BinarySearch documentation)
// now j == index of the next item larger than the searched one
j = j - 1; // set index to the previous element
}
while(j + 1 < intervals.Length && intervals[j].Left == intervals[j + 1].Left)
{
j++; // get the rightmost interval starting from currentInterval.Righ
}
return j - i; // reduce already processed intervals (the left side from currentInterval)
}
}
class Interval : IComparable
{
public long Left { get; set; }
public long Right { get; set; }
// Implementation of IComparable interface
// which is used by Array.Sort().
public int CompareTo(object obj)
{
// elements will be sorted by Left value
var another = obj as Interval;
if (this.Left < another.Left)
{
return -1;
}
if (this.Left > another.Left)
{
return 1;
}
return 0;
}
/// <summary>
/// Transform array items into Intervals (eg. {1, 2, 4} -> {[-1,1], [-1,3], [-2,6]}).
/// </summary>
public static Interval[] GetIntervals(int[] data)
{
var intervals = new Interval[data.Length];
for (int i = 0; i < data.Length; i++)
{
// use long to avoid data overflow (eg. int.MaxValue + 1)
long radius = data[i];
intervals[i] = new Interval
{
Left = i - radius,
Right = i + radius
};
}
return intervals;
}
}
100% score in Codility.
Here is an adaptation to C# of Толя solution:
public int solution(int[] A)
{
long result = 0;
Dictionary<long, int> dps = new Dictionary<long, int>();
Dictionary<long, int> dpe = new Dictionary<long, int>();
for (int i = 0; i < A.Length; i++)
{
Inc(dps, Math.Max(0, i - A[i]));
Inc(dpe, Math.Min(A.Length - 1, i + A[i]));
}
long t = 0;
for (int i = 0; i < A.Length; i++)
{
int value;
if (dps.TryGetValue(i, out value))
{
result += t * value;
result += value * (value - 1) / 2;
t += value;
if (result > 10000000)
return -1;
}
dpe.TryGetValue(i, out value);
t -= value;
}
return (int)result;
}
private static void Inc(Dictionary<long, int> values, long index)
{
int value;
values.TryGetValue(index, out value);
values[index] = ++value;
}
Here's a two-pass C++ solution that doesn't require any libraries, binary searching, sorting, etc.
int solution(vector<int> &A) {
#define countmax 10000000
int count = 0;
// init lower edge array
vector<int> E(A.size());
for (int i = 0; i < (int) E.size(); i++)
E[i] = 0;
// first pass
// count all lower numbered discs inside this one
// mark lower edge of each disc
for (int i = 0; i < (int) A.size(); i++)
{
// if disc overlaps zero
if (i - A[i] <= 0)
count += i;
// doesn't overlap zero
else {
count += A[i];
E[i - A[i]]++;
}
if (count > countmax)
return -1;
}
// second pass
// count higher numbered discs with edge inside this one
for (int i = 0; i < (int) A.size(); i++)
{
// loop up inside this disc until top of vector
int jend = ((int) E.size() < (long long) i + A[i] + 1 ?
(int) E.size() : i + A[i] + 1);
// count all discs with edge inside this disc
// note: if higher disc is so big that edge is at or below
// this disc center, would count intersection in first pass
for (int j = i + 1; j < jend; j++)
count += E[j];
if (count > countmax)
return -1;
}
return count;
}
My answer in Swift; gets a 100% score.
import Glibc
struct Interval {
let start: Int
let end: Int
}
func bisectRight(intervals: [Interval], end: Int) -> Int {
var pos = -1
var startpos = 0
var endpos = intervals.count - 1
if intervals.count == 1 {
if intervals[0].start < end {
return 1
} else {
return 0
}
}
while true {
let currentLength = endpos - startpos
if currentLength == 1 {
pos = startpos
pos += 1
if intervals[pos].start <= end {
pos += 1
}
break
} else {
let middle = Int(ceil( Double((endpos - startpos)) / 2.0 ))
let middlepos = startpos + middle
if intervals[middlepos].start <= end {
startpos = middlepos
} else {
endpos = middlepos
}
}
}
return pos
}
public func solution(inout A: [Int]) -> Int {
let N = A.count
var nIntersections = 0
// Create array of intervals
var unsortedIntervals: [Interval] = []
for i in 0 ..< N {
let interval = Interval(start: i-A[i], end: i+A[i])
unsortedIntervals.append(interval)
}
// Sort array
let intervals = unsortedIntervals.sort {
$0.start < $1.start
}
for i in 0 ..< intervals.count {
let end = intervals[i].end
var count = bisectRight(intervals, end: end)
count -= (i + 1)
nIntersections += count
if nIntersections > Int(10E6) {
return -1
}
}
return nIntersections
}
C# solution 100/100
using System.Linq;
class Solution
{
private struct Interval
{
public Interval(long #from, long to)
{
From = #from;
To = to;
}
public long From { get; }
public long To { get; }
}
public int solution(int[] A)
{
int result = 0;
Interval[] intervals = A.Select((value, i) =>
{
long iL = i;
return new Interval(iL - value, iL + value);
})
.OrderBy(x => x.From)
.ToArray();
for (int i = 0; i < intervals.Length; i++)
{
for (int j = i + 1; j < intervals.Length && intervals[j].From <= intervals[i].To; j++)
result++;
if (result > 10000000)
return -1;
}
return result;
}
}
Given a set of numbers, divide the numbers into two subsets such that difference between the sum of numbers in two subsets is minimal.
This is the idea that I have, but I am not sure if this is a correct solution:
Sort the array
Take the first 2 elements. Consider them as 2 sets (each having 1 element)
Take the next element from the array.
Decide in which set should this element go (by computing the sum => it should be minimum)
Repeat
Is this the correct solution? Can we do better?
The decision version of the problem you are describing is an NP-complete problem and it is called the partition problem. There are a number of approximations which provide, in many cases, optimal or, at least, good enough solutions.
The simple algorithm you described is a way playground kids would pick teams. This greedy algorithm performs remarkably well if the numbers in the set are of similar orders of magnitude.
The article The Easiest Hardest Problem, by American Scientist, gives an excellent analysis of the problem. You should go through and read it!
No, that doesn't work. There is no polynomial time solution (unless P=NP). The best you can do is just look at all different subsets. Have a look at the subset sum problem.
Consider the list [0, 1, 5, 6]. You will claim {0, 5} and {1, 6}, when the best answer is actually {0, 1, 5} and {6}.
No, Your algorithm is wrong. Your algo follows a greedy approach.
I implemented your approach and it failed over this test case:
(You may try here)
A greedy algorithm:
#include<bits/stdc++.h>
#define rep(i,_n) for(int i=0;i<_n;i++)
using namespace std;
#define MXN 55
int a[MXN];
int main() {
//code
int t,n,c;
cin>>t;
while(t--){
cin>>n;
rep(i,n) cin>>a[i];
sort(a, a+n);
reverse(a, a+n);
ll sum1 = 0, sum2 = 0;
rep(i,n){
cout<<a[i]<<endl;
if(sum1<=sum2)
sum1 += a[i];
else
sum2 += a[i];
}
cout<<abs(sum1-sum2)<<endl;
}
return 0;
}
Test case:
1
8
16 14 13 13 12 10 9 3
Wrong Ans: 6
16 13 10 9
14 13 12 3
Correct Ans: 0
16 13 13 3
14 12 10 9
The reason greedy algorithm fails is that it does not consider cases when taking a larger element in current larger sum set and later a much smaller in the larger sum set may result much better results. It always try to minimize current difference without exploring or knowing further possibilities, while in a correct solution you might include an element in a larger set and include a much smaller element later to compensate this difference, same as in above test case.
Correct Solution:
To understand the solution, you will need to understand all below problems in order:
0/1 Knapsack with Dynamic Programming
Partition Equal Subset Sum with DP
Solution
My Code (Same logic as this):
#include<bits/stdc++.h>
#define rep(i,_n) for(int i=0;i<_n;i++)
using namespace std;
#define MXN 55
int arr[MXN];
int dp[MXN][MXN*MXN];
int main() {
//code
int t,N,c;
cin>>t;
while(t--){
rep(i,MXN) fill(dp[i], dp[i]+MXN*MXN, 0);
cin>>N;
rep(i,N) cin>>arr[i];
int sum = accumulate(arr, arr+N, 0);
dp[0][0] = 1;
for(int i=1; i<=N; i++)
for(int j=sum; j>=0; j--)
dp[i][j] |= (dp[i-1][j] | (j>=arr[i-1] ? dp[i-1][j-arr[i-1]] : 0));
int res = sum;
for(int i=0; i<=sum/2; i++)
if(dp[N][i]) res = min(res, abs(i - (sum-i)));
cout<<res<<endl;
}
return 0;
}
Combinations over combinations approach:
import itertools as it
def min_diff_sets(data):
"""
Parameters:
- `data`: input list.
Return:
- min diff between sum of numbers in two sets
"""
if len(data) == 1:
return data[0]
s = sum(data)
# `a` is list of all possible combinations of all possible lengths (from 1
# to len(data) )
a = []
for i in range(1, len(data)):
a.extend(list(it.combinations(data, i)))
# `b` is list of all possible pairs (combinations) of all elements from `a`
b = it.combinations(a, 2)
# `c` is going to be final correct list of combinations.
# Let's apply 2 filters:
# 1. leave only pairs where: sum of all elements == sum(data)
# 2. leave only pairs where: flat list from pairs == data
c = filter(lambda x: sum(x[0])+sum(x[1])==s, b)
c = filter(lambda x: sorted([i for sub in x for i in sub])==sorted(data), c)
# `res` = [min_diff_between_sum_of_numbers_in_two_sets,
# ((set_1), (set_2))
# ]
res = sorted([(abs(sum(i[0]) - sum(i[1])), i) for i in c],
key=lambda x: x[0])
return min([i[0] for i in res])
if __name__ == '__main__':
assert min_diff_sets([10, 10]) == 0, "1st example"
assert min_diff_sets([10]) == 10, "2nd example"
assert min_diff_sets([5, 8, 13, 27, 14]) == 3, "3rd example"
assert min_diff_sets([5, 5, 6, 5]) == 1, "4th example"
assert min_diff_sets([12, 30, 30, 32, 42, 49]) == 9, "5th example"
assert min_diff_sets([1, 1, 1, 3]) == 0, "6th example"
The recursive approach is to generate all possible sums from all the values of array and to check
which solution is the most optimal one.
To generate sums we either include the i’th item in set 1 or don’t include, i.e., include in
set 2.
The time complexity is O(n*sum) for both time and space.T
public class MinimumSubsetSum {
static int dp[][];
public static int minDiffSubsets(int arr[], int i, int calculatedSum, int totalSum) {
if(dp[i][calculatedSum] != -1) return dp[i][calculatedSum];
/**
* If i=0, then the sum of one subset has been calculated as we have reached the last
* element. The sum of another subset is totalSum - calculated sum. We need to return the
* difference between them.
*/
if(i == 0) {
return Math.abs((totalSum - calculatedSum) - calculatedSum);
}
//Including the ith element
int iElementIncluded = minDiffSubsets(arr, i-1, arr[i-1] + calculatedSum,
totalSum);
//Excluding the ith element
int iElementExcluded = minDiffSubsets(arr, i-1, calculatedSum, totalSum);
int res = Math.min(iElementIncluded, iElementExcluded);
dp[i][calculatedSum] = res;
return res;
}
public static void util(int arr[]) {
int totalSum = 0;
int n = arr.length;
for(Integer e : arr) totalSum += e;
dp = new int[n+1][totalSum+1];
for(int i=0; i <= n; i++)
for(int j=0; j <= totalSum; j++)
dp[i][j] = -1;
int res = minDiffSubsets(arr, n, 0, totalSum);
System.out.println("The min difference between two subset is " + res);
}
public static void main(String[] args) {
util(new int[]{3, 1, 4, 2, 2, 1});
}
}
We can use Dynamic Programming (similar to the way we find if a set can be partitioned into two equal sum subsets). Then we find the max possible sum, which will be our first partition.
Second partition will be the difference of the total sum and firstSum.
Answer will be the difference of the first and second partitions.
public int minDiffernce(int set[]) {
int sum = 0;
int n = set.length;
for(int i=0; i<n; i++)
sum+=set[i];
//finding half of total sum, because min difference can be at max 0, if one subset reaches half
int target = sum/2;
boolean[][] dp = new boolean[n+1][target+1];//2
for(int i = 0; i<=n; i++)
dp[i][0] = true;
for(int i= 1; i<=n; i++){
for(int j = 1; j<=target;j++){
if(set[i-1]>j) dp[i][j] = dp[i-1][j];
else dp[i][j] = dp[i-1][j] || dp[i-1][j-set[i-1]];
}
}
// we now find the max sum possible starting from target
int firstPart = 0;
for(int j = target; j>=0; j--){
if(dp[n][j] == true) {
firstPart = j; break;
}
}
int secondPart = sum - firstPart;
return Math.abs(firstPart - secondPart);
}
One small change: reverse the order - start with the largest number and work down. This will minimize the error.
Are you sorting your subset into decending order or ascending order?
Think about it like this, the array {1, 3, 5, 8, 9, 25}
if you were to divide, you would have {1,8,9} =18 {3,5,25} =33
If it were sorted into descending order it would work out a lot better
{25,1}=26 {9,8,5,3}=25
So your solution is basically correct, it just needs to make sure to take the largest values first.
EDIT: Read tskuzzy's post. Mine does not work
This is a variation of the knapsack and subset sum problem.
In subset sum problem, given n positive integers and a value k and we have to find the sum of subset whose value is less than or equal to k.
In the above problem we have given an array, here we have to find the subset whose sum is less than or equal to total_sum(sum of array values).
So the
subset sum can be found using a variation in knapsack algorithm,by
taking profits as given array values. And the final answer is
total_sum-dp[n][total_sum/2]. Have a look at the below code for clear
understanding.
#include<iostream>
#include<cstdio>
using namespace std;
int main()
{
int n;
cin>>n;
int arr[n],sum=0;
for(int i=1;i<=n;i++)
cin>>arr[i],sum+=arr[i];
int temp=sum/2;
int dp[n+1][temp+2];
for(int i=0;i<=n;i++)
{
for(int j=0;j<=temp;j++)
{
if(i==0 || j==0)
dp[i][j]=0;
else if(arr[i]<=j)
dp[i][j]=max(dp[i-1][j],dp[i-1][j-arr[i]]+arr[i]);
else
{
dp[i][j]=dp[i-1][j];
}
}
}
cout<<sum-2*dp[n][temp]<<endl;
}
This can be solve using BST.
First sort the array say arr1
To start create another arr2 with the last element of arr1 (remove this ele from arr1)
Now:Repeat the steps till no swap happens.
Check arr1 for an element which can be moved to arr2 using BST such that the diff is less MIN diff found till now.
if we find an element move this element to arr2 and go to step1 again.
if we don't find any element in above steps do steps 1 & 2 for arr2 & arr1.
i.e. now check if we have any element in arr2 which can be moved to arr1
continue steps 1-4 till we don't need any swap..
we get the solution.
Sample Java Code:
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* Divide an array so that the difference between these 2 is min
*
* #author shaikhjamir
*
*/
public class DivideArrayForMinDiff {
/**
* Create 2 arrays and try to find the element from 2nd one so that diff is
* min than the current one
*/
private static int sum(List<Integer> arr) {
int total = 0;
for (int i = 0; i < arr.size(); i++) {
total += arr.get(i);
}
return total;
}
private static int diff(ArrayList<Integer> arr, ArrayList<Integer> arr2) {
int diff = sum(arr) - sum(arr2);
if (diff < 0)
diff = diff * -1;
return diff;
}
private static int MIN = Integer.MAX_VALUE;
private static int binarySearch(int low, int high, ArrayList<Integer> arr1, int arr2sum) {
if (low > high || low < 0)
return -1;
int mid = (low + high) / 2;
int midVal = arr1.get(mid);
int sum1 = sum(arr1);
int resultOfMoveOrg = (sum1 - midVal) - (arr2sum + midVal);
int resultOfMove = (sum1 - midVal) - (arr2sum + midVal);
if (resultOfMove < 0)
resultOfMove = resultOfMove * -1;
if (resultOfMove < MIN) {
// lets do the swap
return mid;
}
// this is positive number greater than min
// which mean we should move left
if (resultOfMoveOrg < 0) {
// 1,10, 19 ==> 30
// 100
// 20, 110 = -90
// 29, 111 = -83
return binarySearch(low, mid - 1, arr1, arr2sum);
} else {
// resultOfMoveOrg > 0
// 1,5,10, 15, 19, 20 => 70
// 21
// For 10
// 60, 31 it will be 29
// now if we move 1
// 71, 22 ==> 49
// but now if we move 20
// 50, 41 ==> 9
return binarySearch(mid + 1, high, arr1, arr2sum);
}
}
private static int findMin(ArrayList<Integer> arr1) {
ArrayList<Integer> list2 = new ArrayList<>(arr1.subList(arr1.size() - 1, arr1.size()));
arr1.remove(arr1.size() - 1);
while (true) {
int index = binarySearch(0, arr1.size(), arr1, sum(list2));
if (index != -1) {
int val = arr1.get(index);
arr1.remove(index);
list2.add(val);
Collections.sort(list2);
MIN = diff(arr1, list2);
} else {
// now try for arr2
int index2 = binarySearch(0, list2.size(), list2, sum(arr1));
if (index2 != -1) {
int val = list2.get(index2);
list2.remove(index2);
arr1.add(val);
Collections.sort(arr1);
MIN = diff(arr1, list2);
} else {
// no switch in both the cases
break;
}
}
}
System.out.println("MIN==>" + MIN);
System.out.println("arr1==>" + arr1 + ":" + sum(arr1));
System.out.println("list2==>" + list2 + ":" + sum(list2));
return 0;
}
public static void main(String args[]) {
ArrayList<Integer> org = new ArrayList<>();
org = new ArrayList<>();
org.add(1);
org.add(2);
org.add(3);
org.add(7);
org.add(8);
org.add(10);
findMin(org);
}
}
you can use bits to solve this problem by looping over all the possible combinations using bits:
main algorithm:
for(int i = 0; i < 1<<n; i++) {
int s = 0;
for(int j = 0; j < n; j++) {
if(i & 1<<j) s += arr[j];
}
int curr = abs((total-s)-s);
ans = min(ans, curr);
}
use long long for greater inputs.
but here I found a recursive and dynamic programming solution and I used both the approaches to solve the question and both worked for greater inputs perfectly fine. Hope this helps :) link to solution
Please check this logic which I have written for this problem. It worked for few scenarios I checked. Please comment on the solution,
Approach :
Sort the main array and divide it into 2 teams.
Then start making the team equal by shift and swapping elements from one array to other, based on the conditions mentioned in the code.
If the difference is difference of sum is less than the minimum number of the larger array(array with bigger sum), then shift the elements from the bigger array to smaller array.Shifting happens with the condition, that element from the bigger array with value less than or equal to the difference.When all the elements from the bigger array is greater than the difference, the shifting stops and swapping happens. I m just swapping the last elements of the array (It can be made more efficient by finding which two elements to swap), but still this worked. Let me know if this logic failed in any scenario.
public class SmallestDifference {
static int sum1 = 0, sum2 = 0, diff, minDiff;
private static List<Integer> minArr1;
private static List<Integer> minArr2;
private static List<Integer> biggerArr;
/**
* #param args
*/
public static void main(String[] args) {
SmallestDifference sm = new SmallestDifference();
Integer[] array1 = { 2, 7, 1, 4, 5, 9, 10, 11 };
List<Integer> array = new ArrayList<Integer>();
for (Integer val : array1) {
array.add(val);
}
Collections.sort(array);
CopyOnWriteArrayList<Integer> arr1 = new CopyOnWriteArrayList<>(array.subList(0, array.size() / 2));
CopyOnWriteArrayList<Integer> arr2 = new CopyOnWriteArrayList<>(array.subList(array.size() / 2, array.size()));
diff = Math.abs(sm.getSum(arr1) - sm.getSum(arr2));
minDiff = array.get(0);
sm.updateSum(arr1, arr2);
System.out.println(arr1 + " : " + arr2);
System.out.println(sum1 + " - " + sum2 + " = " + diff + " : minDiff = " + minDiff);
int k = arr2.size();
biggerArr = arr2;
while (diff != 0 && k >= 0) {
while (diff != 0 && sm.findMin(biggerArr) < diff) {
sm.swich(arr1, arr2);
int sum1 = sm.getSum(arr1), sum2 = sm.getSum(arr2);
diff = Math.abs(sum1 - sum2);
if (sum1 > sum2) {
biggerArr = arr1;
} else {
biggerArr = arr2;
}
if (minDiff > diff || sm.findMin(biggerArr) > diff) {
minDiff = diff;
minArr1 = new CopyOnWriteArrayList<>(arr1);
minArr2 = new CopyOnWriteArrayList<>(arr2);
}
sm.updateSum(arr1, arr2);
System.out.println("Shifting : " + sum1 + " - " + sum2 + " = " + diff + " : minDiff = " + minDiff);
}
while (k >= 0 && minDiff > array.get(0) && minDiff != 0) {
sm.swap(arr1, arr2);
diff = Math.abs(sm.getSum(arr1) - sm.getSum(arr2));
if (minDiff > diff) {
minDiff = diff;
minArr1 = new CopyOnWriteArrayList<>(arr1);
minArr2 = new CopyOnWriteArrayList<>(arr2);
}
sm.updateSum(arr1, arr2);
System.out.println("Swapping : " + sum1 + " - " + sum2 + " = " + diff + " : minDiff = " + minDiff);
k--;
}
k--;
}
System.out.println(minArr1 + " : " + minArr2 + " = " + minDiff);
}
private void updateSum(CopyOnWriteArrayList<Integer> arr1, CopyOnWriteArrayList<Integer> arr2) {
SmallestDifference sm1 = new SmallestDifference();
sum1 = sm1.getSum(arr1);
sum2 = sm1.getSum(arr2);
}
private int findMin(List<Integer> biggerArr2) {
Integer min = biggerArr2.get(0);
for (Integer integer : biggerArr2) {
if(min > integer) {
min = integer;
}
}
return min;
}
private int getSum(CopyOnWriteArrayList<Integer> arr) {
int sum = 0;
for (Integer val : arr) {
sum += val;
}
return sum;
}
private void swap(CopyOnWriteArrayList<Integer> arr1, CopyOnWriteArrayList<Integer> arr2) {
int l1 = arr1.size(), l2 = arr2.size(), temp2 = arr2.get(l2 - 1), temp1 = arr1.get(l1 - 1);
arr1.remove(l1 - 1);
arr1.add(temp2);
arr2.remove(l2 - 1);
arr2.add(temp1);
System.out.println(arr1 + " : " + arr2);
}
private void swich(CopyOnWriteArrayList<Integer> arr1, CopyOnWriteArrayList<Integer> arr2) {
Integer e;
if (sum1 > sum2) {
e = this.findElementJustLessThanMinDiff(arr1);
arr1.remove(e);
arr2.add(e);
} else {
e = this.findElementJustLessThanMinDiff(arr2);
arr2.remove(e);
arr1.add(e);
}
System.out.println(arr1 + " : " + arr2);
}
private Integer findElementJustLessThanMinDiff(CopyOnWriteArrayList<Integer> arr1) {
Integer e = arr1.get(0);
int tempDiff = diff - e;
for (Integer integer : arr1) {
if (diff > integer && (diff - integer) < tempDiff) {
e = integer;
tempDiff = diff - e;
}
}
return e;
}
}
A possible solution here- https://stackoverflow.com/a/31228461/4955513
This Java program seems to solve this problem, provided one condition is fulfilled- that there is one and only one solution to the problem.
I'll convert this problem to subset sum problem
let's take array int[] A = { 10,20,15,5,25,33 };
it should be divided into {25 20 10} and { 33 20 } and answer is 55-53=2
Notations : SUM == sum of whole array
sum1 == sum of subset1
sum2 == sum of subset1
step 1: get sum of whole array SUM=108
step 2: whichever way we divide our array into two part one thing will remain true
sum1+ sum2= SUM
step 3: if our intention is to get minimum sum difference then sum1 and sum2 should be near SUM/2 (example sum1=54 and sum2=54 then diff=0 )
steon 4: let's try combinations
sum1 = 54 AND sum2 = 54 (not possible to divide like this)
sum1 = 55 AND sum2 = 53 (possible and our solution, should break here)
sum1 = 56 AND sum2 = 52
sum1 = 57 AND sum2 = 51 .......so on
pseudo code
SUM=Array.sum();
sum1 = SUM/2;
sum2 = SUM-sum1;
while(true){
if(subSetSuMProblem(A,sum1) && subSetSuMProblem(A,sum2){
print "possible"
break;
}
else{
sum1++;
sum2--;
}
}
Java code for the same
import java.util.ArrayList;
import java.util.List;
public class MinimumSumSubsetPrint {
public static void main(String[] args) {
int[] A = {10, 20, 15, 5, 25, 32};
int sum = 0;
for (int i = 0; i < A.length; i++) {
sum += A[i];
}
subsetSumDynamic(A, sum);
}
private static boolean subsetSumDynamic(int[] A, int sum) {
int n = A.length;
boolean[][] T = new boolean[n + 1][sum + 1];
// sum2[0][0]=true;
for (int i = 0; i <= n; i++) {
T[i][0] = true;
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= sum; j++) {
if (A[i - 1] > j) {
T[i][j] = T[i - 1][j];
} else {
T[i][j] = T[i - 1][j] || T[i - 1][j - A[i - 1]];
}
}
}
int sum1 = sum / 2;
int sum2 = sum - sum1;
while (true) {
if (T[n][sum1] && T[n][sum2]) {
printSubsets(T, sum1, n, A);
printSubsets(T, sum2, n, A);
break;
} else {
sum1 = sum1 - 1;
sum2 = sum - sum1;
System.out.println(sum1 + ":" + sum2);
}
}
return T[n][sum];
}
private static void printSubsets(boolean[][] T, int sum, int n, int[] A) {
List<Integer> sumvals = new ArrayList<Integer>();
int i = n;
int j = sum;
while (i > 0 && j > 0) {
if (T[i][j] == T[i - 1][j]) {
i--;
} else {
sumvals.add(A[i - 1]);
j = j - A[i - 1];
i--;
}
}
System.out.println();
for (int p : sumvals) {
System.out.print(p + " ");
}
System.out.println();
}
}
Here is recursive approach
def helper(arr,sumCal,sumTot,n):
if n==0:
return abs(abs(sumCal-sumTot)-sumCal)
return min(helper(arr,sumCal+arr[n-1],sumTot,n-1),helper(arr,sumCal,sumTot,n-1))
def minimum_subset_diff(arr,n):
sum=0
for i in range(n):
sum+=arr[i]
return helper(arr,0,sum,n)
Here is a Top down Dynamic approach to reduce the time complexity
dp=[[-1]*100 for i in range(100)]
def helper_dp(arr,sumCal,sumTot,n):
if n==0:
return abs(abs(sumCal-sumTot)-sumCal)
if dp[n][sumTot]!=-1:
return dp[n][sumTot]
return min(helper_dp(arr,sumCal+arr[n-1],sumTot,n-1),helper_dp(arr,sumCal,sumTot,n-1))
def minimum_subset_diff_dp(arr,n):
sum=0
for i in range(n):
sum+=arr[i]
return helper_dp(arr,0,sum,n)
int ModDiff(int a, int b)
{
if(a < b)return b - a;
return a-b;
}
int EqDiv(int *a, int l, int *SumI, int *SumE)
{
static int tc = 0;
int min = ModDiff(*SumI,*SumE);
for(int i = 0; i < l; i++)
{
swap(a,0,i);
a++;
int m1 = EqDiv(a, l-1, SumI,SumE);
a--;
swap(a,0,i);
*SumI = *SumI + a[i];
*SumE = *SumE - a[i];
swap(a,0,i);
a++;
int m2 = EqDiv(a,l-1, SumI,SumE);
a--;
swap(a,0,i);
*SumI = *SumI - a[i];
*SumE = *SumE + a[i];
min = min3(min,m1,m2);
}
return min;
}
call the function with SumI =0 and SumE= sumof all the elements in a.
This O(n!) solution does compute the way we can divide the given array into 2 parts such the difference is minimum.
But definitely not practical due to the n! time complexity looking to improve this using DP.
#include<bits/stdc++.h>
using namespace std;
bool ison(int i,int x)
{
if((i>>x) & 1)return true;
return false;
}
int main()
{
// cout<<"enter the number of elements : ";
int n;
cin>>n;
int a[n];
for(int i=0;i<n;i++)
cin>>a[i];
int sumarr1[(1<<n)-1];
int sumarr2[(1<<n)-1];
memset(sumarr1,0,sizeof(sumarr1));
memset(sumarr2,0,sizeof(sumarr2));
int index=0;
vector<int>v1[(1<<n)-1];
vector<int>v2[(1<<n)-1];
for(int i=1;i<(1<<n);i++)
{
for(int j=0;j<n;j++)
{
if(ison(i,j))
{
sumarr1[index]+=a[j];
v1[index].push_back(a[j]);
}
else
{
sumarr2[index]+=a[j];
v2[index].push_back(a[j]);
}
}index++;
}
int ans=INT_MAX;
int ii;
for(int i=0;i<index;i++)
{
if(abs(sumarr1[i]-sumarr2[i])<ans)
{
ii=i;
ans=abs(sumarr1[i]-sumarr2[i]);
}
}
cout<<"first partitioned array : ";
for(int i=0;i<v1[ii].size();i++)
{
cout<<v1[ii][i]<<" ";
}
cout<<endl;
cout<<"2nd partitioned array : ";
for(int i=0;i<v2[ii].size();i++)
{
cout<<v2[ii][i]<<" ";
}
cout<<endl;
cout<<"minimum difference is : "<<ans<<endl;
}
Many answers mentioned about getting an 'approximate' solution in a very acceptable time bound . But since it is asked in an interview , I dont expect they need an approximation algorithm. Also I dont expect they need a naive exponential algorithm either.
Coming to the problem , assuming the maximum value of sum of numbers is known , it can infact be solved in polynomial time using dynamic programming. Refer this link
https://people.cs.clemson.edu/~bcdean/dp_practice/dp_4.swf
HI I think This Problem can be solved in Linear Time on a sorted array , no Polynomial Time is required , rather than Choosing Next Element u can choose nest two Element and decide which side which element to go. in This Way
in this way minimize the difference, let suppose
{0,1,5,6} ,
choose {0,1}
{0} , {1}
choose 5,6
{0,6}, {1,5}
but still that is not exact solution , now at the end there will be difference of sum in 2 array let suppose x
but there can be better solution of difference of (less than x)
for that Find again 1 greedy approach over sorted half sized array
and move x/2(or nearby) element from 1 set to another or exchange element of(difference x/2) so that difference can be minimized***
Given an array A of N integers we draw N discs in a 2D plane, such that i-th disc has center in (0,i) and a radius A[i]. We say that k-th disc and j-th disc intersect, if k-th and j-th discs have at least one common point.
Write a function
int number_of_disc_intersections(int[] A);
which given an array A describing N discs as explained above, returns the number of pairs of intersecting discs. For example, given N=6 and
A[0] = 1
A[1] = 5
A[2] = 2
A[3] = 1
A[4] = 4
A[5] = 0
there are 11 pairs of intersecting discs:
0th and 1st
0th and 2nd
0th and 4th
1st and 2nd
1st and 3rd
1st and 4th
1st and 5th
2nd and 3rd
2nd and 4th
3rd and 4th
4th and 5th
so the function should return 11.
The function should return -1 if the number of intersecting pairs exceeds 10,000,000. The function may assume that N does not exceed 10,000,000.
O(N) complexity and O(N) memory solution.
private static int Intersections(int[] a)
{
int result = 0;
int[] dps = new int[a.length];
int[] dpe = new int[a.length];
for (int i = 0, t = a.length - 1; i < a.length; i++)
{
int s = i > a[i]? i - a[i]: 0;
int e = t - i > a[i]? i + a[i]: t;
dps[s]++;
dpe[e]++;
}
int t = 0;
for (int i = 0; i < a.length; i++)
{
if (dps[i] > 0)
{
result += t * dps[i];
result += dps[i] * (dps[i] - 1) / 2;
if (10000000 < result) return -1;
t += dps[i];
}
t -= dpe[i];
}
return result;
}
So you want to find the number of intersections of the intervals [i-A[i], i+A[i]].
Maintain a sorted array (call it X) containing the i-A[i] (also have some extra space which has the value i+A[i] in there).
Now walk the array X, starting at the leftmost interval (i.e smallest i-A[i]).
For the current interval, do a binary search to see where the right end point of the interval (i.e. i+A[i]) will go (called the rank). Now you know that it intersects all the elements to the left.
Increment a counter with the rank and subtract current position (assuming one indexed) as we don't want to double count intervals and self intersections.
O(nlogn) time, O(n) space.
Python 100 / 100 (tested) on codility, with O(nlogn) time and O(n) space.
Here is #noisyboiler's python implementation of #Aryabhatta's method with comments and an example.
Full credit to original authors, any errors / poor wording are entirely my fault.
from bisect import bisect_right
def number_of_disc_intersections(A):
pairs = 0
# create an array of tuples, each containing the start and end indices of a disk
# some indices may be less than 0 or greater than len(A), this is fine!
# sort the array by the first entry of each tuple: the disk start indices
intervals = sorted( [(i-A[i], i+A[i]) for i in range(len(A))] )
# create an array of starting indices using tuples in intervals
starts = [i[0] for i in intervals]
# for each disk in order of the *starting* position of the disk, not the centre
for i in range(len(starts)):
# find the end position of that disk from the array of tuples
disk_end = intervals[i][1]
# find the index of the rightmost value less than or equal to the interval-end
# this finds the number of disks that have started before disk i ends
count = bisect_right(starts, disk_end )
# subtract current position to exclude previous matches
# this bit seemed 'magic' to me, so I think of it like this...
# for disk i, i disks that start to the left have already been dealt with
# subtract i from count to prevent double counting
# subtract one more to prevent counting the disk itsself
count -= (i+1)
pairs += count
if pairs > 10000000:
return -1
return pairs
Worked example: given [3, 0, 1, 6] the disk radii would look like this:
disk0 ------- start= -3, end= 3
disk1 . start= 1, end= 1
disk2 --- start= 1, end= 3
disk3 ------------- start= -3, end= 9
index 3210123456789 (digits left of zero are -ve)
intervals = [(-3, 3), (-3, 9), (1, 1), (1,3)]
starts = [-3, -3, 1, 1]
the loop order will be: disk0, disk3, disk1, disk2
0th loop:
by the end of disk0, 4 disks have started
one of which is disk0 itself
none of which could have already been counted
so add 3
1st loop:
by the end of disk3, 4 disks have started
one of which is disk3 itself
one of which has already started to the left so is either counted OR would not overlap
so add 2
2nd loop:
by the end of disk1, 4 disks have started
one of which is disk1 itself
two of which have already started to the left so are either counted OR would not overlap
so add 1
3rd loop:
by the end of disk2, 4 disks have started
one of which is disk2 itself
two of which have already started to the left so are either counted OR would not overlap
so add 0
pairs = 6
to check: these are (0,1), (0,2), (0,2), (1,2), (1,3), (2,3),
Well, I adapted Falk Hüffner's idea to c++, and made a change in the range.
Opposite to what is written above, there is no need to go beyond the scope of the array (no matter how large are the values in it).
On Codility this code received 100%.
Thank you Falk for your great idea!
int number_of_disc_intersections ( const vector<int> &A ) {
int sum=0;
vector<int> start(A.size(),0);
vector<int> end(A.size(),0);
for (unsigned int i=0;i<A.size();i++){
if ((int)i<A[i]) start[0]++;
else start[i-A[i]]++;
if (i+A[i]>=A.size()) end[A.size()-1]++;
else end[i+A[i]]++;
}
int active=0;
for (unsigned int i=0;i<A.size();i++){
sum+=active*start[i]+(start[i]*(start[i]-1))/2;
if (sum>10000000) return -1;
active+=start[i]-end[i];
}
return sum;
}
This can even be done in linear time [EDIT: this is not linear time, see comments]. In fact, it becomes easier if you ignore the fact that there is exactly one interval centered at each point, and just treat it as a set of start- and endpoints of intervals. You can then just scan it from the left (Python code for simplicity):
from collections import defaultdict
a = [1, 5, 2, 1, 4, 0]
start = defaultdict(int)
stop = defaultdict(int)
for i in range(len(a)):
start[i - a[i]] += 1
stop[i + a[i]] += 1
active = 0
intersections = 0
for i in range(-len(a), len(a)):
intersections += active * start[i] + (start[i] * (start[i] - 1)) / 2
active += start[i]
active -= stop[i]
print intersections
Here's a O(N) time, O(N) space algorithm requiring 3 runs across the array and no sorting, verified scoring 100%:
You're interested in pairs of discs. Each pair involves one side of one disc and the other side of the other disc. Therefore we won't have duplicate pairs if we handle one side of each disc. Let's call the sides right and left (I rotated the space while thinking about it).
An overlap is either due to a right side overlapping another disc directly at the center (so pairs equal to the radius with some care about the array length) or due to the number of left sides existing at the rightmost edge.
So we create an array that contains the number of left sides at each point and then it's a simple sum.
C code:
int solution(int A[], int N) {
int C[N];
int a, S=0, t=0;
// Mark left and middle of disks
for (int i=0; i<N; i++) {
C[i] = -1;
a = A[i];
if (a>=i) {
C[0]++;
} else {
C[i-a]++;
}
}
// Sum of left side of disks at location
for (int i=0; i<N; i++) {
t += C[i];
C[i] = t;
}
// Count pairs, right side only:
// 1. overlaps based on disk size
// 2. overlaps based on disks but not centers
for (int i=0; i<N; i++) {
a = A[i];
S += ((a<N-i) ? a: N-i-1);
if (i != N-1) {
S += C[((a<N-i) ? i+a: N-1)];
}
if (S>10000000) return -1;
}
return S;
}
I got 100 out of 100 with this C++ implementation:
#include <map>
#include <algorithm>
inline bool mySortFunction(pair<int,int> p1, pair<int,int> p2)
{
return ( p1.first < p2.first );
}
int number_of_disc_intersections ( const vector<int> &A ) {
int i, size = A.size();
if ( size <= 1 ) return 0;
// Compute lower boundary of all discs and sort them in ascending order
vector< pair<int,int> > lowBounds(size);
for(i=0; i<size; i++) lowBounds[i] = pair<int,int>(i-A[i],i+A[i]);
sort(lowBounds.begin(), lowBounds.end(), mySortFunction);
// Browse discs
int nbIntersect = 0;
for(i=0; i<size; i++)
{
int curBound = lowBounds[i].second;
for(int j=i+1; j<size && lowBounds[j].first<=curBound; j++)
{
nbIntersect++;
// Maximal number of intersections
if ( nbIntersect > 10000000 ) return -1;
}
}
return nbIntersect;
}
A Python answer
from bisect import bisect_right
def number_of_disc_intersections(li):
pairs = 0
# treat as a series of intervals on the y axis at x=0
intervals = sorted( [(i-li[i], i+li[i]) for i in range(len(li))] )
# do this by creating a list of start points of each interval
starts = [i[0] for i in intervals]
for i in range(len(starts)):
# find the index of the rightmost value less than or equal to the interval-end
count = bisect_right(starts, intervals[i][1])
# subtract current position to exclude previous matches, and subtract self
count -= (i+1)
pairs += count
if pairs > 10000000:
return -1
return pairs
100/100 c#
class Solution
{
class Interval
{
public long Left;
public long Right;
}
public int solution(int[] A)
{
if (A == null || A.Length < 1)
{
return 0;
}
var itervals = new Interval[A.Length];
for (int i = 0; i < A.Length; i++)
{
// use long to avoid data overflow (eg. int.MaxValue + 1)
long radius = A[i];
itervals[i] = new Interval()
{
Left = i - radius,
Right = i + radius
};
}
itervals = itervals.OrderBy(i => i.Left).ToArray();
int result = 0;
for (int i = 0; i < itervals.Length; i++)
{
var right = itervals[i].Right;
for (int j = i + 1; j < itervals.Length && itervals[j].Left <= right; j++)
{
result++;
if (result > 10000000)
{
return -1;
}
}
}
return result;
}
}
I'm offering one more solution because I did not find the counting principle of the previous solutions easy to follow. Though the results are the same, an explanation and more intuitive counting procedure seems worth presenting.
To begin, start by considering the O(N^2) solution that iterates over the discs in order of their center points, and counts the number of discs centered to the right of the current disc's that intersect the current disc, using the condition current_center + radius >= other_center - radius. Notice that we could get the same result counting discs centered to the left of the current disc using the condition current_center - radius <= other_center + radius.
def simple(A):
"""O(N^2) solution for validating more efficient solution."""
N = len(A)
unique_intersections = 0
# Iterate over discs in order of their center positions
for j in range(N):
# Iterate over discs whose center is to the right, to avoid double-counting.
for k in range(j+1, N):
# Increment cases where edge of current disk is at or right of the left edge of another disk.
if j + A[j] >= k - A[k]:
unique_intersections += 1
# Stop early if we have enough intersections.
# BUT: if the discs are small we still N^2 compare them all and time out.
if unique_intersections > 10000000:
return -1
return unique_intersections
We can go from O(N^2) to O(N) if we could only "look up" the number of discs to the right (or to the left!) that intersect the current disc. The key insight is to reinterpret the intersection condition as "the right edge of one disc overlaps the left edge of another disc", meaning (a ha!) the centers don't matter, only the edges.
The next insight is to try sorting the edges, taking O(N log N) time. Given a sorted array of the left edges and a sorted array of the right edges, as we scan our way from left to right along the number line, the number of left or right edges to the left of the current location point is simply the current index into left_edges and right_edges respectively: a constant-time deduction.
Finally, we use the "right edge > left edge" condition to deduce that the number of intersections between the current disc and discs that start only to the left of the current disc (to avoid duplicates) is the number of left edges to the left of the current edge, minus the number of right edges to the left of the current edge. That is, the number of discs starting to left of this one, minus the ones that closed already.
Now for this code, tested 100% on Codility:
def solution(A):
"""O(N log N) due to sorting, with O(N) pass over sorted arrays"""
N = len(A)
# Left edges of the discs, in increasing order of position.
left_edges = sorted([(p-r) for (p,r) in enumerate(A)])
# Right edges of the discs, in increasing order of position.
right_edges = sorted([(p+r) for (p,r) in enumerate(A)])
#print("left edges:", left_edges[:10])
#print("right edges:", right_edges[:10])
intersections = 0
right_i = 0
# Iterate over the discs in order of their leftmost edge position.
for left_i in range(N):
# Find the first right_edge that's right of or equal to the current left_edge, naively:
# right_i = bisect.bisect_left(right_edges, left_edges[left_i])
# Just scan from previous index until right edge is at or beyond current left:
while right_edges[right_i] < left_edges[left_i]:
right_i += 1
# Count number of discs starting left of current, minus the ones that already closed.
intersections += left_i - right_i
# Return early if we find more than 10 million intersections.
if intersections > 10000000:
return -1
#print("correct:", simple(A))
return intersections
Java 2*100%.
result is declared as long for a case codility doesn't test, namely 50k*50k intersections at one point.
class Solution {
public int solution(int[] A) {
int[] westEnding = new int[A.length];
int[] eastEnding = new int[A.length];
for (int i=0; i<A.length; i++) {
if (i-A[i]>=0) eastEnding[i-A[i]]++; else eastEnding[0]++;
if ((long)i+A[i]<A.length) westEnding[i+A[i]]++; else westEnding[A.length-1]++;
}
long result = 0; //long to contain the case of 50k*50k. codility doesn't test for this.
int wests = 0;
int easts = 0;
for (int i=0; i<A.length; i++) {
int balance = easts*wests; //these are calculated elsewhere
wests++;
easts+=eastEnding[i];
result += (long) easts*wests - balance - 1; // 1 stands for the self-intersection
if (result>10000000) return -1;
easts--;
wests-= westEnding[i];
}
return (int) result;
}
}
Swift 4 Solution 100% (Codility do not check the worst case for this solution)
public func solution(_ A : inout [Int]) -> Int {
// write your code in Swift 4.2.1 (Linux)
var count = 0
let sortedA = A.sorted(by: >)
if sortedA.isEmpty{ return 0 }
let maxVal = sortedA[0]
for i in 0..<A.count{
let maxIndex = min(i + A[i] + maxVal + 1,A.count)
for j in i + 1..<maxIndex{
if j - A[j] <= i + A[i]{
count += 1
}
}
if count > 10_000_000{
return -1
}
}
return count
}
Here my JavaScript solution, based in other solutions in this thread but implemented in other languages.
function solution(A) {
let circleEndpoints = [];
for(const [index, num] of Object.entries(A)) {
circleEndpoints.push([parseInt(index)-num, true]);
circleEndpoints.push([parseInt(index)+num, false]);
}
circleEndpoints = circleEndpoints.sort(([a, openA], [b, openB]) => {
if(a == b) return openA ? -1 : 1;
return a - b;
});
let openCircles = 0;
let intersections = 0;
for(const [endpoint, opening] of circleEndpoints) {
if(opening) {
intersections += openCircles;
openCircles ++;
} else {
openCircles --;
}
if(intersections > 10000000) return -1;
}
return intersections;
}
count = 0
for (int i = 0; i < N; i++) {
for (int j = i+1; j < N; j++) {
if (i + A[i] >= j - A[j]) count++;
}
}
It is O(N^2) so pretty slow, but it works.
This is a ruby solution that scored 100/100 on codility. I'm posting it now because I'm finding it difficult to follow the already posted ruby answer.
def solution(a)
end_points = []
a.each_with_index do |ai, i|
end_points << [i - ai, i + ai]
end
end_points = end_points.sort_by { |points| points[0]}
intersecting_pairs = 0
end_points.each_with_index do |point, index|
lep, hep = point
pairs = bsearch(end_points, index, end_points.size - 1, hep)
return -1 if 10000000 - pairs + index < intersecting_pairs
intersecting_pairs += (pairs - index)
end
return intersecting_pairs
end
# This method returns the maximally appropriate position
# where the higher end-point may have been inserted.
def bsearch(a, l, u, x)
if l == u
if x >= a[u][0]
return u
else
return l - 1
end
end
mid = (l + u)/2
# Notice that we are searching in higher range
# even if we have found equality.
if a[mid][0] <= x
return bsearch(a, mid+1, u, x)
else
return bsearch(a, l, mid, x)
end
end
Probably extremely fast. O(N). But you need to check it out. 100% on Codility.
Main idea:
1. At any point of the table, there are number of circles "opened" till the right edge of the circle, lets say "o".
2. So there are (o-1-used) possible pairs for the circle in that point. "used" means circle that have been processed and pairs for them counted.
public int solution(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;
}
private 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;
}
There are a lot of great answers here already, including the great explanation from the accepted answer. However, I wanted to point out a small observation about implementation details in the Python language.
Originally, I've came up with the solution shown below. I was expecting to get O(N*log(N)) time complexity as soon as we have a single for-loop with N iterations, and each iteration performs a binary search that takes at most log(N).
def solution(a):
import bisect
if len(a) <= 1:
return 0
cuts = [(c - r, c + r) for c, r in enumerate(a)]
cuts.sort(key=lambda pair: pair[0])
lefts, rights = zip(*cuts)
n = len(cuts)
total = 0
for i in range(n):
r = rights[i]
pos = bisect.bisect_right(lefts[i+1:], r)
total += pos
if total > 10e6:
return -1
return total
However, I've get O(N**2) and a timeout failure. Do you see what is wrong here? Right, this line:
pos = bisect.bisect_right(lefts[i+1:], r)
In this line, you are actually taking a copy of the original list to pass it into binary search function, and it totally ruins the efficiency of the proposed solution! It makes your code just a bit more consice (i.e., you don't need to write pos - i - 1) but heavily undermies the performance. So, as it was shown above, the solution should be:
def solution(a):
import bisect
if len(a) <= 1:
return 0
cuts = [(c - r, c + r) for c, r in enumerate(a)]
cuts.sort(key=lambda pair: pair[0])
lefts, rights = zip(*cuts)
n = len(cuts)
total = 0
for i in range(n):
r = rights[i]
pos = bisect.bisect_right(lefts, r)
total += (pos - i - 1)
if total > 10e6:
return -1
return total
It seems that sometimes one could be too eager about making slices and copies because Python allows you to do it so easily :) Probably not a great insight, but for me it was a good lesson to pay more attention to these "technical" moments when converting ideas and algorithms into real-word solutions.
I know that this is an old questions but it is still active on codility.
private int solution(int[] A)
{
int openedCircles = 0;
int intersectCount = 0;
We need circles with their start and end values. For that purpose I have used Tuple.
True/False indicates if we are adding Circle Starting or Circle Ending value.
List<Tuple<decimal, bool>> circles = new List<Tuple<decimal, bool>>();
for(int i = 0; i < A.Length; i ++)
{
// Circle start value
circles.Add(new Tuple<decimal, bool>((decimal)i - (decimal)A[i], true));
// Circle end value
circles.Add(new Tuple<decimal, bool>((decimal)i + (decimal)A[i], false));
}
Order "circles" by their values.
If one circle is ending at same value where other circle is starting, it should be counted as intersect (because of that "opening" should be in front of "closing" if in same point)
circles = circles.OrderBy(x => x.Item1).ThenByDescending(x => x.Item2).ToList();
Counting and returning counter
foreach (var circle in circles)
{
// We are opening new circle (within existing circles)
if(circle.Item2 == true)
{
intersectCount += openedCircles;
if (intersectCount > 10000000)
{
return -1;
}
openedCircles++;
}
else
{
// We are closing circle
openedCircles--;
}
}
return intersectCount;
}
Javascript solution 100/100 based on this video https://www.youtube.com/watch?v=HV8tzIiidSw
function sortArray(A) {
return A.sort((a, b) => a - b)
}
function getDiskPoints(A) {
const diskStarPoint = []
const diskEndPoint = []
for(i = 0; i < A.length; i++) {
diskStarPoint.push(i - A[i])
diskEndPoint.push(i + A[i])
}
return {
diskStarPoint: sortArray(diskStarPoint),
diskEndPoint: sortArray(diskEndPoint)
};
}
function solution(A) {
const { diskStarPoint, diskEndPoint } = getDiskPoints(A)
let index = 0;
let openDisks = 0;
let intersections = 0;
for(i = 0; i < diskStarPoint.length; i++) {
while(diskStarPoint[i] > diskEndPoint[index]) {
openDisks--
index++
}
intersections += openDisks
openDisks++
}
return intersections > 10000000 ? -1 : intersections
}
so, I was doing this test in Scala and I would like to share here my example. My idea to solve is:
Extract the limits to the left and right of each position on the array.
A[0] = 1 --> (0-1, 0+1) = A0(-1, 1)
A[1] = 5 --> (1-5, 1+5) = A1(-4, 6)
A[2] = 2 --> (2-2, 2+2) = A2(0, 4)
A[3] = 1 --> (3-1, 3+1) = A3(2, 4)
A[4] = 4 --> (4-4, 4+4) = A4(0, 8)
A[5] = 0 --> (5-0, 5+0) = A5(5, 5)
Check if there is intersections between any two positions
(A0_0 >= A1_0 AND A0_0 <= A1_1) OR // intersection
(A0_1 >= A1_0 AND A0_1 <= A1_1) OR // intersection
(A0_0 <= A1_0 AND A0_1 >= A1_1) // one circle contain inside the other
if any of these two checks is true count one intersection.
object NumberOfDiscIntersections {
def solution(a: Array[Int]): Int = {
var count: Long = 0
for (posI: Long <- 0L until a.size) {
for (posJ <- (posI + 1) until a.size) {
val tupleI = (posI - a(posI.toInt), posI + a(posI.toInt))
val tupleJ = (posJ - a(posJ.toInt), posJ + a(posJ.toInt))
if ((tupleI._1 >= tupleJ._1 && tupleI._1 <= tupleJ._2) ||
(tupleI._2 >= tupleJ._1 && tupleI._2 <= tupleJ._2) ||
(tupleI._1 <= tupleJ._1 && tupleI._2 >= tupleJ._2)) {
count += 1
}
}
}
count.toInt
}
}
This got 100/100 in c#
class CodilityDemo3
{
public static int GetIntersections(int[] A)
{
if (A == null)
{
return 0;
}
int size = A.Length;
if (size <= 1)
{
return 0;
}
List<Line> lines = new List<Line>();
for (int i = 0; i < size; i++)
{
if (A[i] >= 0)
{
lines.Add(new Line(i - A[i], i + A[i]));
}
}
lines.Sort(Line.CompareLines);
size = lines.Count;
int intersects = 0;
for (int i = 0; i < size; i++)
{
Line ln1 = lines[i];
for (int j = i + 1; j < size; j++)
{
Line ln2 = lines[j];
if (ln2.YStart <= ln1.YEnd)
{
intersects += 1;
if (intersects > 10000000)
{
return -1;
}
}
else
{
break;
}
}
}
return intersects;
}
}
public class Line
{
public Line(double ystart, double yend)
{
YStart = ystart;
YEnd = yend;
}
public double YStart { get; set; }
public double YEnd { get; set; }
public static int CompareLines(Line line1, Line line2)
{
return (line1.YStart.CompareTo(line2.YStart));
}
}
}
Thanks to Falk for the great idea! Here is a ruby implementation that takes advantage of sparseness.
def int(a)
event = Hash.new{|h,k| h[k] = {:start => 0, :stop => 0}}
a.each_index {|i|
event[i - a[i]][:start] += 1
event[i + a[i]][:stop ] += 1
}
sorted_events = (event.sort_by {|index, value| index}).map! {|n| n[1]}
past_start = 0
intersect = 0
sorted_events.each {|e|
intersect += e[:start] * (e[:start]-1) / 2 +
e[:start] * past_start
past_start += e[:start]
past_start -= e[:stop]
}
return intersect
end
puts int [1,1]
puts int [1,5,2,1,4,0]
#include <stdio.h>
#include <stdlib.h>
void sortPairs(int bounds[], int len){
int i,j, temp;
for(i=0;i<(len-1);i++){
for(j=i+1;j<len;j++){
if(bounds[i] > bounds[j]){
temp = bounds[i];
bounds[i] = bounds[j];
bounds[j] = temp;
temp = bounds[i+len];
bounds[i+len] = bounds[j+len];
bounds[j+len] = temp;
}
}
}
}
int adjacentPointPairsCount(int a[], int len){
int count=0,i,j;
int *bounds;
if(len<2) {
goto toend;
}
bounds = malloc(sizeof(int)*len *2);
for(i=0; i< len; i++){
bounds[i] = i-a[i];
bounds[i+len] = i+a[i];
}
sortPairs(bounds, len);
for(i=0;i<len;i++){
int currentBound = bounds[i+len];
for(j=i+1;a[j]<=currentBound;j++){
if(count>100000){
count=-1;
goto toend;
}
count++;
}
}
toend:
free(bounds);
return count;
}
An Implementation of Idea stated above in Java:
public class DiscIntersectionCount {
public int number_of_disc_intersections(int[] A) {
int[] leftPoints = new int[A.length];
for (int i = 0; i < A.length; i++) {
leftPoints[i] = i - A[i];
}
Arrays.sort(leftPoints);
// System.out.println(Arrays.toString(leftPoints));
int count = 0;
for (int i = 0; i < A.length - 1; i++) {
int rpoint = A[i] + i;
int rrank = getRank(leftPoints, rpoint);
//if disk has sifnificant radius, exclude own self
if (rpoint > i) rrank -= 1;
int rank = rrank;
// System.out.println(rpoint+" : "+rank);
rank -= i;
count += rank;
}
return count;
}
public int getRank(int A[], int num) {
if (A==null || A.length == 0) return -1;
int mid = A.length/2;
while ((mid >= 0) && (mid < A.length)) {
if (A[mid] == num) return mid;
if ((mid == 0) && (A[mid] > num)) return -1;
if ((mid == (A.length - 1)) && (A[mid] < num)) return A.length;
if (A[mid] < num && A[mid + 1] >= num) return mid + 1;
if (A[mid] > num && A[mid - 1] <= num) return mid - 1;
if (A[mid] < num) mid = (mid + A.length)/2;
else mid = (mid)/2;
}
return -1;
}
public static void main(String[] args) {
DiscIntersectionCount d = new DiscIntersectionCount();
int[] A =
//{1,5,2,1,4,0}
//{0,0,0,0,0,0}
// {1,1,2}
{3}
;
int count = d.number_of_disc_intersections(A);
System.out.println(count);
}
}
Here is the PHP code that scored 100 on codility:
$sum=0;
//One way of cloning the A:
$start = array();
$end = array();
foreach ($A as $key=>$value)
{
$start[]=0;
$end[]=0;
}
for ($i=0; $i<count($A); $i++)
{
if ($i<$A[$i])
$start[0]++;
else
$start[$i-$A[$i]]++;
if ($i+$A[$i] >= count($A))
$end[count($A)-1]++;
else
$end[$i+$A[$i]]++;
}
$active=0;
for ($i=0; $i<count($A);$i++)
{
$sum += $active*$start[$i]+($start[$i]*($start[$i]-1))/2;
if ($sum>10000000) return -1;
$active += $start[$i]-$end[$i];
}
return $sum;
However I dont understand the logic. This is just transformed C++ code from above. Folks, can you elaborate on what you were doing here, please?
A 100/100 C# implementation as described by Aryabhatta (the binary search solution).
using System;
class Solution {
public int solution(int[] A)
{
return IntersectingDiscs.Execute(A);
}
}
class IntersectingDiscs
{
public static int Execute(int[] data)
{
int counter = 0;
var intervals = Interval.GetIntervals(data);
Array.Sort(intervals); // sort by Left value
for (int i = 0; i < intervals.Length; i++)
{
counter += GetCoverage(intervals, i);
if(counter > 10000000)
{
return -1;
}
}
return counter;
}
private static int GetCoverage(Interval[] intervals, int i)
{
var currentInterval = intervals[i];
// search for an interval starting at currentInterval.Right
int j = Array.BinarySearch(intervals, new Interval { Left = currentInterval.Right });
if(j < 0)
{
// item not found
j = ~j; // bitwise complement (see Array.BinarySearch documentation)
// now j == index of the next item larger than the searched one
j = j - 1; // set index to the previous element
}
while(j + 1 < intervals.Length && intervals[j].Left == intervals[j + 1].Left)
{
j++; // get the rightmost interval starting from currentInterval.Righ
}
return j - i; // reduce already processed intervals (the left side from currentInterval)
}
}
class Interval : IComparable
{
public long Left { get; set; }
public long Right { get; set; }
// Implementation of IComparable interface
// which is used by Array.Sort().
public int CompareTo(object obj)
{
// elements will be sorted by Left value
var another = obj as Interval;
if (this.Left < another.Left)
{
return -1;
}
if (this.Left > another.Left)
{
return 1;
}
return 0;
}
/// <summary>
/// Transform array items into Intervals (eg. {1, 2, 4} -> {[-1,1], [-1,3], [-2,6]}).
/// </summary>
public static Interval[] GetIntervals(int[] data)
{
var intervals = new Interval[data.Length];
for (int i = 0; i < data.Length; i++)
{
// use long to avoid data overflow (eg. int.MaxValue + 1)
long radius = data[i];
intervals[i] = new Interval
{
Left = i - radius,
Right = i + radius
};
}
return intervals;
}
}
100% score in Codility.
Here is an adaptation to C# of Толя solution:
public int solution(int[] A)
{
long result = 0;
Dictionary<long, int> dps = new Dictionary<long, int>();
Dictionary<long, int> dpe = new Dictionary<long, int>();
for (int i = 0; i < A.Length; i++)
{
Inc(dps, Math.Max(0, i - A[i]));
Inc(dpe, Math.Min(A.Length - 1, i + A[i]));
}
long t = 0;
for (int i = 0; i < A.Length; i++)
{
int value;
if (dps.TryGetValue(i, out value))
{
result += t * value;
result += value * (value - 1) / 2;
t += value;
if (result > 10000000)
return -1;
}
dpe.TryGetValue(i, out value);
t -= value;
}
return (int)result;
}
private static void Inc(Dictionary<long, int> values, long index)
{
int value;
values.TryGetValue(index, out value);
values[index] = ++value;
}
Here's a two-pass C++ solution that doesn't require any libraries, binary searching, sorting, etc.
int solution(vector<int> &A) {
#define countmax 10000000
int count = 0;
// init lower edge array
vector<int> E(A.size());
for (int i = 0; i < (int) E.size(); i++)
E[i] = 0;
// first pass
// count all lower numbered discs inside this one
// mark lower edge of each disc
for (int i = 0; i < (int) A.size(); i++)
{
// if disc overlaps zero
if (i - A[i] <= 0)
count += i;
// doesn't overlap zero
else {
count += A[i];
E[i - A[i]]++;
}
if (count > countmax)
return -1;
}
// second pass
// count higher numbered discs with edge inside this one
for (int i = 0; i < (int) A.size(); i++)
{
// loop up inside this disc until top of vector
int jend = ((int) E.size() < (long long) i + A[i] + 1 ?
(int) E.size() : i + A[i] + 1);
// count all discs with edge inside this disc
// note: if higher disc is so big that edge is at or below
// this disc center, would count intersection in first pass
for (int j = i + 1; j < jend; j++)
count += E[j];
if (count > countmax)
return -1;
}
return count;
}
My answer in Swift; gets a 100% score.
import Glibc
struct Interval {
let start: Int
let end: Int
}
func bisectRight(intervals: [Interval], end: Int) -> Int {
var pos = -1
var startpos = 0
var endpos = intervals.count - 1
if intervals.count == 1 {
if intervals[0].start < end {
return 1
} else {
return 0
}
}
while true {
let currentLength = endpos - startpos
if currentLength == 1 {
pos = startpos
pos += 1
if intervals[pos].start <= end {
pos += 1
}
break
} else {
let middle = Int(ceil( Double((endpos - startpos)) / 2.0 ))
let middlepos = startpos + middle
if intervals[middlepos].start <= end {
startpos = middlepos
} else {
endpos = middlepos
}
}
}
return pos
}
public func solution(inout A: [Int]) -> Int {
let N = A.count
var nIntersections = 0
// Create array of intervals
var unsortedIntervals: [Interval] = []
for i in 0 ..< N {
let interval = Interval(start: i-A[i], end: i+A[i])
unsortedIntervals.append(interval)
}
// Sort array
let intervals = unsortedIntervals.sort {
$0.start < $1.start
}
for i in 0 ..< intervals.count {
let end = intervals[i].end
var count = bisectRight(intervals, end: end)
count -= (i + 1)
nIntersections += count
if nIntersections > Int(10E6) {
return -1
}
}
return nIntersections
}
C# solution 100/100
using System.Linq;
class Solution
{
private struct Interval
{
public Interval(long #from, long to)
{
From = #from;
To = to;
}
public long From { get; }
public long To { get; }
}
public int solution(int[] A)
{
int result = 0;
Interval[] intervals = A.Select((value, i) =>
{
long iL = i;
return new Interval(iL - value, iL + value);
})
.OrderBy(x => x.From)
.ToArray();
for (int i = 0; i < intervals.Length; i++)
{
for (int j = i + 1; j < intervals.Length && intervals[j].From <= intervals[i].To; j++)
result++;
if (result > 10000000)
return -1;
}
return result;
}
}
Given array of n integers and given a number X, find all the unique pairs of elements (a,b), whose summation is equal to X.
The following is my solution, it is O(nLog(n)+n), but I am not sure whether or not it is optimal.
int main(void)
{
int arr [10] = {1,2,3,4,5,6,7,8,9,0};
findpair(arr, 10, 7);
}
void findpair(int arr[], int len, int sum)
{
std::sort(arr, arr+len);
int i = 0;
int j = len -1;
while( i < j){
while((arr[i] + arr[j]) <= sum && i < j)
{
if((arr[i] + arr[j]) == sum)
cout << "(" << arr[i] << "," << arr[j] << ")" << endl;
i++;
}
j--;
while((arr[i] + arr[j]) >= sum && i < j)
{
if((arr[i] + arr[j]) == sum)
cout << "(" << arr[i] << "," << arr[j] << ")" << endl;
j--;
}
}
}
There are 3 approaches to this solution:
Let the sum be T and n be the size of array
Approach 1:
The naive way to do this would be to check all combinations (n choose 2). This exhaustive search is O(n2).
Approach 2:
A better way would be to sort the array. This takes O(n log n)
Then for each x in array A,
use binary search to look for T-x. This will take O(nlogn).
So, overall search is O(n log n)
Approach 3 :
The best way
would be to insert every element into a hash table (without sorting). This takes O(n) as constant time insertion.
Then for every x,
we can just look up its complement, T-x, which is O(1).
Overall the run time of this approach is O(n).
You can refer more here.Thanks.
# Let arr be the given array.
# And K be the give sum
for i=0 to arr.length - 1 do
# key is the element and value is its index.
hash(arr[i]) = i
end-for
for i=0 to arr.length - 1 do
# if K-th element exists and it's different then we found a pair
if hash(K - arr[i]) != i
print "pair i , hash(K - arr[i]) has sum K"
end-if
end-for
Implementation in Java : Using codaddict's algorithm (Maybe slightly different)
import java.util.HashMap;
public class ArrayPairSum {
public static void main(String[] args) {
int []a = {2,45,7,3,5,1,8,9};
printSumPairs(a,10);
}
public static void printSumPairs(int []input, int k){
Map<Integer, Integer> pairs = new HashMap<Integer, Integer>();
for(int i=0;i<input.length;i++){
if(pairs.containsKey(input[i]))
System.out.println(input[i] +", "+ pairs.get(input[i]));
else
pairs.put(k-input[i], input[i]);
}
}
}
For input = {2,45,7,3,5,1,8,9} and if Sum is 10
Output pairs:
3,7
8,2
9,1
Some notes about the solution :
We iterate only once through the array --> O(n) time
Insertion and lookup time in Hash is O(1).
Overall time is O(n), although it uses extra space in terms of hash.
Solution in java. You can add all the String elements to an ArrayList of strings and return the list. Here I am just printing it out.
void numberPairsForSum(int[] array, int sum) {
HashSet<Integer> set = new HashSet<Integer>();
for (int num : array) {
if (set.contains(sum - num)) {
String s = num + ", " + (sum - num) + " add up to " + sum;
System.out.println(s);
}
set.add(num);
}
}
Python Implementation:
import itertools
list = [1, 1, 2, 3, 4, 5,]
uniquelist = set(list)
targetsum = 5
for n in itertools.combinations(uniquelist, 2):
if n[0] + n[1] == targetsum:
print str(n[0]) + " + " + str(n[1])
Output:
1 + 4
2 + 3
C++11, run time complexity O(n):
#include <vector>
#include <unordered_map>
#include <utility>
std::vector<std::pair<int, int>> FindPairsForSum(
const std::vector<int>& data, const int& sum)
{
std::unordered_map<int, size_t> umap;
std::vector<std::pair<int, int>> result;
for (size_t i = 0; i < data.size(); ++i)
{
if (0 < umap.count(sum - data[i]))
{
size_t j = umap[sum - data[i]];
result.push_back({data[i], data[j]});
}
else
{
umap[data[i]] = i;
}
}
return result;
}
Here is a solution witch takes into account duplicate entries. It is written in javascript and assumes array is sorted. The solution runs in O(n) time and does not use any extra memory aside from variable.
var count_pairs = function(_arr,x) {
if(!x) x = 0;
var pairs = 0;
var i = 0;
var k = _arr.length-1;
if((k+1)<2) return pairs;
var halfX = x/2;
while(i<k) {
var curK = _arr[k];
var curI = _arr[i];
var pairsThisLoop = 0;
if(curK+curI==x) {
// if midpoint and equal find combinations
if(curK==curI) {
var comb = 1;
while(--k>=i) pairs+=(comb++);
break;
}
// count pair and k duplicates
pairsThisLoop++;
while(_arr[--k]==curK) pairsThisLoop++;
// add k side pairs to running total for every i side pair found
pairs+=pairsThisLoop;
while(_arr[++i]==curI) pairs+=pairsThisLoop;
} else {
// if we are at a mid point
if(curK==curI) break;
var distK = Math.abs(halfX-curK);
var distI = Math.abs(halfX-curI);
if(distI > distK) while(_arr[++i]==curI);
else while(_arr[--k]==curK);
}
}
return pairs;
}
I solved this during an interview for a large corporation. They took it but not me.
So here it is for everyone.
Start at both side of the array and slowly work your way inwards making sure to count duplicates if they exist.
It only counts pairs but can be reworked to
find the pairs
find pairs < x
find pairs > x
Enjoy!
O(n)
def find_pairs(L,sum):
s = set(L)
edgeCase = sum/2
if L.count(edgeCase) ==2:
print edgeCase, edgeCase
s.remove(edgeCase)
for i in s:
diff = sum-i
if diff in s:
print i, diff
L = [2,45,7,3,5,1,8,9]
sum = 10
find_pairs(L,sum)
Methodology: a + b = c, so instead of looking for (a,b) we look for a = c -
b
Implementation in Java : Using codaddict's algorithm:
import java.util.Hashtable;
public class Range {
public static void main(String[] args) {
// TODO Auto-generated method stub
Hashtable mapping = new Hashtable();
int a[]= {80,79,82,81,84,83,85};
int k = 160;
for (int i=0; i < a.length; i++){
mapping.put(a[i], i);
}
for (int i=0; i < a.length; i++){
if (mapping.containsKey(k - a[i]) && (Integer)mapping.get(k-a[i]) != i){
System.out.println(k-a[i]+", "+ a[i]);
}
}
}
}
Output:
81, 79
79, 81
If you want duplicate pairs (eg: 80,80) also then just remove && (Integer)mapping.get(k-a[i]) != i from the if condition and you are good to go.
Just attended this question on HackerRank and here's my 'Objective C' Solution:
-(NSNumber*)sum:(NSArray*) a andK:(NSNumber*)k {
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
long long count = 0;
for(long i=0;i<a.count;i++){
if(dict[a[i]]) {
count++;
NSLog(#"a[i]: %#, dict[array[i]]: %#", a[i], dict[a[i]]);
}
else{
NSNumber *calcNum = #(k.longLongValue-((NSNumber*)a[i]).longLongValue);
dict[calcNum] = a[i];
}
}
return #(count);
}
Hope it helps someone.
this is the implementation of O(n*lg n) using binary search implementation inside a loop.
#include <iostream>
using namespace std;
bool *inMemory;
int pairSum(int arr[], int n, int k)
{
int count = 0;
if(n==0)
return count;
for (int i = 0; i < n; ++i)
{
int start = 0;
int end = n-1;
while(start <= end)
{
int mid = start + (end-start)/2;
if(i == mid)
break;
else if((arr[i] + arr[mid]) == k && !inMemory[i] && !inMemory[mid])
{
count++;
inMemory[i] = true;
inMemory[mid] = true;
}
else if(arr[i] + arr[mid] >= k)
{
end = mid-1;
}
else
start = mid+1;
}
}
return count;
}
int main()
{
int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
inMemory = new bool[10];
for (int i = 0; i < 10; ++i)
{
inMemory[i] = false;
}
cout << pairSum(arr, 10, 11) << endl;
return 0;
}
In python
arr = [1, 2, 4, 6, 10]
diff_hash = {}
expected_sum = 3
for i in arr:
if diff_hash.has_key(i):
print i, diff_hash[i]
key = expected_sum - i
diff_hash[key] = i
Nice solution from Codeaddict. I took the liberty of implementing a version of it in Ruby:
def find_sum(arr,sum)
result ={}
h = Hash[arr.map {|i| [i,i]}]
arr.each { |l| result[l] = sum-l if h[sum-l] && !result[sum-l] }
result
end
To allow duplicate pairs (1,5), (5,1) we just have to remove the && !result[sum-l] instruction
Here is Java code for three approaches:
1. Using Map O(n), HashSet can also be used here.
2. Sort array and then use BinarySearch to look for complement O(nLog(n))
3. Traditional BruteForce two loops O(n^2)
public class PairsEqualToSum {
public static void main(String[] args) {
int a[] = {1,10,5,8,2,12,6,4};
findPairs1(a,10);
findPairs2(a,10);
findPairs3(a,10);
}
//Method1 - O(N) use a Map to insert values as keys & check for number's complement in map
static void findPairs1(int[]a, int sum){
Map<Integer, Integer> pairs = new HashMap<Integer, Integer>();
for(int i=0; i<a.length; i++){
if(pairs.containsKey(sum-a[i]))
System.out.println("("+a[i]+","+(sum-a[i])+")");
else
pairs.put(a[i], 0);
}
}
//Method2 - O(nlog(n)) using Sort
static void findPairs2(int[]a, int sum){
Arrays.sort(a);
for(int i=0; i<a.length/2; i++){
int complement = sum - a[i];
int foundAtIndex = Arrays.binarySearch(a,complement);
if(foundAtIndex >0 && foundAtIndex != i) //to avoid situation where binarySearch would find the original and not the complement like "5"
System.out.println("("+a[i]+","+(sum-a[i])+")");
}
}
//Method 3 - Brute Force O(n^2)
static void findPairs3(int[]a, int sum){
for(int i=0; i<a.length; i++){
for(int j=i; j<a.length;j++){
if(a[i]+a[j] == sum)
System.out.println("("+a[i]+","+a[j]+")");
}
}
}
}
A Simple program in java for arrays having unique elements:
import java.util.*;
public class ArrayPairSum {
public static void main(String[] args) {
int []a = {2,4,7,3,5,1,8,9,5};
sumPairs(a,10);
}
public static void sumPairs(int []input, int k){
Set<Integer> set = new HashSet<Integer>();
for(int i=0;i<input.length;i++){
if(set.contains(input[i]))
System.out.println(input[i] +", "+(k-input[i]));
else
set.add(k-input[i]);
}
}
}
A simple Java code snippet for printing the pairs below:
public static void count_all_pairs_with_given_sum(int arr[], int S){
if(arr.length < 2){
return;
}
HashSet values = new HashSet(arr.length);
for(int value : arr)values.add(value);
for(int value : arr){
int difference = S - value;
if(values.contains(difference) && value<difference){
System.out.printf("(%d, %d) %n", value, difference);
}
}
}
Another solution in Swift: the idea is to create an hash that store values of (sum - currentValue) and compare this to the current value of the loop. The complexity is O(n).
func findPair(list: [Int], _ sum: Int) -> [(Int, Int)]? {
var hash = Set<Int>() //save list of value of sum - item.
var dictCount = [Int: Int]() //to avoid the case A*2 = sum where we have only one A in the array
var foundKeys = Set<Int>() //to avoid duplicated pair in the result.
var result = [(Int, Int)]() //this is for the result.
for item in list {
//keep track of count of each element to avoid problem: [2, 3, 5], 10 -> result = (5,5)
if (!dictCount.keys.contains(item)) {
dictCount[item] = 1
} else {
dictCount[item] = dictCount[item]! + 1
}
//if my hash does not contain the (sum - item) value -> insert to hash.
if !hash.contains(sum-item) {
hash.insert(sum-item)
}
//check if current item is the same as another hash value or not, if yes, return the tuple.
if hash.contains(item) &&
(dictCount[item] > 1 || sum != item*2) // check if we have item*2 = sum or not.
{
if !foundKeys.contains(item) && !foundKeys.contains(sum-item) {
foundKeys.insert(item) //add to found items in order to not to add duplicated pair.
result.append((item, sum-item))
}
}
}
return result
}
//test:
let a = findPair([2,3,5,4,1,7,6,8,9,5,3,3,3,3,3,3,3,3,3], 14) //will return (8,6) and (9,5)
My Solution - Java - Without duplicates
public static void printAllPairSum(int[] a, int x){
System.out.printf("printAllPairSum(%s,%d)\n", Arrays.toString(a),x);
if(a==null||a.length==0){
return;
}
int length = a.length;
Map<Integer,Integer> reverseMapOfArray = new HashMap<>(length,1.0f);
for (int i = 0; i < length; i++) {
reverseMapOfArray.put(a[i], i);
}
for (int i = 0; i < length; i++) {
Integer j = reverseMapOfArray.get(x - a[i]);
if(j!=null && i<j){
System.out.printf("a[%d] + a[%d] = %d + %d = %d\n",i,j,a[i],a[j],x);
}
}
System.out.println("------------------------------");
}
This prints the pairs and avoids duplicates using bitwise manipulation.
public static void findSumHashMap(int[] arr, int key) {
Map<Integer, Integer> valMap = new HashMap<Integer, Integer>();
for(int i=0;i<arr.length;i++)
valMap.put(arr[i], i);
int indicesVisited = 0;
for(int i=0;i<arr.length;i++) {
if(valMap.containsKey(key - arr[i]) && valMap.get(key - arr[i]) != i) {
if(!((indicesVisited & ((1<<i) | (1<<valMap.get(key - arr[i])))) > 0)) {
int diff = key-arr[i];
System.out.println(arr[i] + " " +diff);
indicesVisited = indicesVisited | (1<<i) | (1<<valMap.get(key - arr[i]));
}
}
}
}
I bypassed the bit manuplation and just compared the index values. This is less than the loop iteration value (i in this case). This will not print the duplicate pairs and duplicate array elements also.
public static void findSumHashMap(int[] arr, int key) {
Map<Integer, Integer> valMap = new HashMap<Integer, Integer>();
for (int i = 0; i < arr.length; i++) {
valMap.put(arr[i], i);
}
for (int i = 0; i < arr.length; i++) {
if (valMap.containsKey(key - arr[i])
&& valMap.get(key - arr[i]) != i) {
if (valMap.get(key - arr[i]) < i) {
int diff = key - arr[i];
System.out.println(arr[i] + " " + diff);
}
}
}
}
in C#:
int[] array = new int[] { 1, 5, 7, 2, 9, 8, 4, 3, 6 }; // given array
int sum = 10; // given sum
for (int i = 0; i <= array.Count() - 1; i++)
if (array.Contains(sum - array[i]))
Console.WriteLine("{0}, {1}", array[i], sum - array[i]);
One Solution can be this, but not optimul (The complexity of this code is O(n^2)):
public class FindPairsEqualToSum {
private static int inputSum = 0;
public static List<String> findPairsForSum(int[] inputArray, int sum) {
List<String> list = new ArrayList<String>();
List<Integer> inputList = new ArrayList<Integer>();
for (int i : inputArray) {
inputList.add(i);
}
for (int i : inputArray) {
int tempInt = sum - i;
if (inputList.contains(tempInt)) {
String pair = String.valueOf(i + ", " + tempInt);
list.add(pair);
}
}
return list;
}
}
A simple python version of the code that find a pair sum of zero and can be modify to find k:
def sumToK(lst):
k = 0 # <- define the k here
d = {} # build a dictionary
# build the hashmap key = val of lst, value = i
for index, val in enumerate(lst):
d[val] = index
# find the key; if a key is in the dict, and not the same index as the current key
for i, val in enumerate(lst):
if (k-val) in d and d[k-val] != i:
return True
return False
The run time complexity of the function is O(n) and Space: O(n) as well.
public static int[] f (final int[] nums, int target) {
int[] r = new int[2];
r[0] = -1;
r[1] = -1;
int[] vIndex = new int[0Xfff];
for (int i = 0; i < nums.length; i++) {
int delta = 0Xff;
int gapIndex = target - nums[i] + delta;
if (vIndex[gapIndex] != 0) {
r[0] = vIndex[gapIndex];
r[1] = i + 1;
return r;
} else {
vIndex[nums[i] + delta] = i + 1;
}
}
return r;
}
less than o(n) solution will be=>
function(array,k)
var map = {};
for element in array
map(element) = true;
if(map(k-element))
return {k,element}
Solution in Python using list comprehension
f= [[i,j] for i in list for j in list if j+i==X];
O(N2)
also gives two ordered pairs- (a,b) and (b,a) as well
I can do it in O(n). Let me know when you want the answer. Note it involves simply traversing the array once with no sorting, etc... I should mention too that it exploits commutativity of addition and doesn't use hashes but wastes memory.
using System;
using System.Collections.Generic;
/*
An O(n) approach exists by using a lookup table. The approach is to store the value in a "bin" that can easily be looked up(e.g., O(1)) if it is a candidate for an appropriate sum.
e.g.,
for each a[k] in the array we simply put the it in another array at the location x - a[k].
Suppose we have [0, 1, 5, 3, 6, 9, 8, 7] and x = 9
We create a new array,
indexes value
9 - 0 = 9 0
9 - 1 = 8 1
9 - 5 = 4 5
9 - 3 = 6 3
9 - 6 = 3 6
9 - 9 = 0 9
9 - 8 = 1 8
9 - 7 = 2 7
THEN the only values that matter are the ones who have an index into the new table.
So, say when we reach 9 or equal we see if our new array has the index 9 - 9 = 0. Since it does we know that all the values it contains will add to 9. (note in this cause it's obvious there is only 1 possible one but it might have multiple index values in it which we need to store).
So effectively what we end up doing is only having to move through the array once. Because addition is commutative we will end up with all the possible results.
For example, when we get to 6 we get the index into our new table as 9 - 6 = 3. Since the table contains that index value we know the values.
This is essentially trading off speed for memory.
*/
namespace sum
{
class Program
{
static void Main(string[] args)
{
int num = 25;
int X = 10;
var arr = new List<int>();
for(int i = 0; i <= num; i++) arr.Add((new Random((int)(DateTime.Now.Ticks + i*num))).Next(0, num*2));
Console.Write("["); for (int i = 0; i < num - 1; i++) Console.Write(arr[i] + ", "); Console.WriteLine(arr[arr.Count-1] + "] - " + X);
var arrbrute = new List<Tuple<int,int>>();
var arrfast = new List<Tuple<int,int>>();
for(int i = 0; i < num; i++)
for(int j = i+1; j < num; j++)
if (arr[i] + arr[j] == X)
arrbrute.Add(new Tuple<int, int>(arr[i], arr[j]));
int M = 500;
var lookup = new List<List<int>>();
for(int i = 0; i < 1000; i++) lookup.Add(new List<int>());
for(int i = 0; i < num; i++)
{
// Check and see if we have any "matches"
if (lookup[M + X - arr[i]].Count != 0)
{
foreach(var j in lookup[M + X - arr[i]])
arrfast.Add(new Tuple<int, int>(arr[i], arr[j]));
}
lookup[M + arr[i]].Add(i);
}
for(int i = 0; i < arrbrute.Count; i++)
Console.WriteLine(arrbrute[i].Item1 + " + " + arrbrute[i].Item2 + " = " + X);
Console.WriteLine("---------");
for(int i = 0; i < arrfast.Count; i++)
Console.WriteLine(arrfast[i].Item1 + " + " + arrfast[i].Item2 + " = " + X);
Console.ReadKey();
}
}
}
I implemented logic in Scala with out a Map. It gives duplicate pairs since the counter loops thru entire elements of the array. If duplicate pairs are needed, you can simply return the value pc
val arr = Array[Int](8, 7, 2, 5, 3, 1, 5)
val num = 10
var pc = 0
for(i <- arr.indices) {
if(arr.contains(Math.abs(arr(i) - num))) pc += 1
}
println(s"Pairs: ${pc/2}")
It is working with duplicates values in the array as well.
GOLANG Implementation
func findPairs(slice1 []int, sum int) [][]int {
pairMap := make(map[int]int)
var SliceOfPairs [][]int
for i, v := range slice1 {
if valuei, ok := pairMap[v]; ok {
//fmt.Println("Pair Found", i, valuei)
SliceOfPairs = append(SliceOfPairs, []int{i, valuei})
} else {
pairMap[sum-v] = i
}
}
return SliceOfPairs
}
function findPairOfNumbers(arr, targetSum) {
arr = arr.sort();
var low = 0, high = arr.length - 1, sum, result = [];
while(low < high) {
sum = arr[low] + arr[high];
if(sum < targetSum)
low++;
else if(sum > targetSum)
high--;
else if(sum === targetSum) {
result.push({val1: arr[low], val2: arr[high]});
high--;
}
}
return (result || false);
}
var pairs = findPairOfNumbers([1,2,3,4,5,6,7,8,9,0], 7);
if(pairs.length) {
console.log(pairs);
} else {
console.log("No pair of numbers found that sums to " + 7);
}
Can someone give an example for finding greatest common divisor algorithm for more than two numbers?
I believe programming language doesn't matter.
Start with the first pair and get their GCD, then take the GCD of that result and the next number. The obvious optimization is you can stop if the running GCD ever reaches 1. I'm watching this one to see if there are any other optimizations. :)
Oh, and this can be easily parallelized since the operations are commutative/associative.
The GCD of 3 numbers can be computed as gcd(a, b, c) = gcd(gcd(a, b), c). You can apply the Euclidean algorithm, the extended Euclidian or the binary GCD algorithm iteratively and get your answer. I'm not aware of any other (smarter?) ways to find a GCD, unfortunately.
A little late to the party I know, but a simple JavaScript implementation, utilising Sam Harwell's description of the algorithm:
function euclideanAlgorithm(a, b) {
if(b === 0) {
return a;
}
const remainder = a % b;
return euclideanAlgorithm(b, remainder)
}
function gcdMultipleNumbers(...args) { //ES6 used here, change as appropriate
const gcd = args.reduce((memo, next) => {
return euclideanAlgorithm(memo, next)}
);
return gcd;
}
gcdMultipleNumbers(48,16,24,96) //8
I just updated a Wiki page on this.
[https://en.wikipedia.org/wiki/Binary_GCD_algorithm#C.2B.2B_template_class]
This takes an arbitrary number of terms.
use GCD(5, 2, 30, 25, 90, 12);
template<typename AType> AType GCD(int nargs, ...)
{
va_list arglist;
va_start(arglist, nargs);
AType *terms = new AType[nargs];
// put values into an array
for (int i = 0; i < nargs; i++)
{
terms[i] = va_arg(arglist, AType);
if (terms[i] < 0)
{
va_end(arglist);
return (AType)0;
}
}
va_end(arglist);
int shift = 0;
int numEven = 0;
int numOdd = 0;
int smallindex = -1;
do
{
numEven = 0;
numOdd = 0;
smallindex = -1;
// count number of even and odd
for (int i = 0; i < nargs; i++)
{
if (terms[i] == 0)
continue;
if (terms[i] & 1)
numOdd++;
else
numEven++;
if ((smallindex < 0) || terms[i] < terms[smallindex])
{
smallindex = i;
}
}
// check for exit
if (numEven + numOdd == 1)
continue;
// If everything in S is even, divide everything in S by 2, and then multiply the final answer by 2 at the end.
if (numOdd == 0)
{
shift++;
for (int i = 0; i < nargs; i++)
{
if (terms[i] == 0)
continue;
terms[i] >>= 1;
}
}
// If some numbers in S are even and some are odd, divide all the even numbers by 2.
if (numEven > 0 && numOdd > 0)
{
for (int i = 0; i < nargs; i++)
{
if (terms[i] == 0)
continue;
if ((terms[i] & 1) == 0)
terms[i] >>= 1;
}
}
//If every number in S is odd, then choose an arbitrary element of S and call it k.
//Replace every other element, say n, with | n−k | / 2.
if (numEven == 0)
{
for (int i = 0; i < nargs; i++)
{
if (i == smallindex || terms[i] == 0)
continue;
terms[i] = abs(terms[i] - terms[smallindex]) >> 1;
}
}
} while (numEven + numOdd > 1);
// only one remaining element multiply the final answer by 2s at the end.
for (int i = 0; i < nargs; i++)
{
if (terms[i] == 0)
continue;
return terms[i] << shift;
}
return 0;
};
For golang, using remainder
func GetGCD(a, b int) int {
for b != 0 {
a, b = b, a%b
}
return a
}
func GetGCDFromList(numbers []int) int {
var gdc = numbers[0]
for i := 1; i < len(numbers); i++ {
number := numbers[i]
gdc = GetGCD(gdc, number)
}
return gdc
}
In Java (not optimal):
public static int GCD(int[] a){
int j = 0;
boolean b=true;
for (int i = 1; i < a.length; i++) {
if(a[i]!=a[i-1]){
b=false;
break;
}
}
if(b)return a[0];
j=LeastNonZero(a);
System.out.println(j);
for (int i = 0; i < a.length; i++) {
if(a[i]!=j)a[i]=a[i]-j;
}
System.out.println(Arrays.toString(a));
return GCD(a);
}
public static int LeastNonZero(int[] a){
int b = 0;
for (int i : a) {
if(i!=0){
if(b==0||i<b)b=i;
}
}
return b;
}