Computing next prefix index in KMP implementations - algorithm

I've read through a number of different implementations of KMP and can't quite figure out one aspect they all share.
When they compute the longest prefix which is also suffix-array (lps).
If the characters do not match at the indexes tested at a specific iteration, and the index of the prefix is not 0. The index of the prefix is set to
index = lps[index - 1];
Here is an example
void computeLPSArray(String pat, int M, int lps[])
{
// length of the previous longest prefix suffix
int len = 0;
int i = 1;
lps[0] = 0; // lps[0] is always 0
// the loop calculates lps[i] for i = 1 to M-1
while (i < M)
{
if (pat.charAt(i) == pat.charAt(len))
{
len++;
lps[i] = len;
i++;
}
else // (pat[i] != pat[len])
{
// This is tricky. Consider the example.
// AAACAAAA and i = 7. The idea is similar
// to search step.
if (len != 0)
{
len = lps[len-1];
// Also, note that we do not increment
// i here
}
else // if (len == 0)
{
lps[i] = len;
i++;
}
}
}
}
Is there any situation where index = lps[index-1] is not equivalent to
index--;

Related

Missing integer variation - O(n) solution needed [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
The problem comes from Codility programming training and it sounds as follows:
we have an array (A[]) with n (ranging from 1 to 100,000) elements and these are our parameters. The elements of the array are integers from −2,147,483,648 to 2,147,483,647, and we need to find smallest positive integer that is NOT in the array. Of course this could be done easily in O(n*log n) by sorting them all and going through the sorted array, looking for the missing posiitve number (this last operation has O(n) worst time complexity in my solution). But according to Codility, this ENTIRE problem can be done in O(n), and I cannot see any way to do that. Could someone give some tips to let me get un-stuck?
PS Here is a link to detailed description of the problem which I'm not allowed to copy - https://codility.com/c/intro/demo35UEXH-EAT
By pigeonhole principle, at least one of the numbers 1, 2, ..., n+1 is not in the array.
Let us create a boolean array b of size n+1 to store whether each of these numbers is present.
Now, we process the input array. If we find a number from 1 to n+1, we mark the corresponding entry in b. If the number we see does not fit into these bounds, just discard it and proceed to the next one. Both cases are O(1) per input entry, total O(n).
After we are done processing the input, we can find the first non-marked entry in our boolean array b trivially in O(n).
Simple solution 100% in Java.
Please note it is O(nlogn) solution but gives 100% result in codility.
public static int solution(final int[] A)
{
Arrays.sort(A);
int min = 1;
// Starting from 1 (min), compare all elements, if it does not match
// that would the missing number.
for (int i : A) {
if (i == min) {
min++;
}
}
return min;
}
wrote this today and got 100/100. not the most elegant solution, but easy to understand -
public int solution(int[] A) {
int max = A.length;
int threshold = 1;
boolean[] bitmap = new boolean[max + 1];
//populate bitmap and also find highest positive int in input list.
for (int i = 0; i < A.length; i++) {
if (A[i] > 0 && A[i] <= max) {
bitmap[A[i]] = true;
}
if (A[i] > threshold) {
threshold = A[i];
}
}
//find the first positive number in bitmap that is false.
for (int i = 1; i < bitmap.length; i++) {
if (!bitmap[i]) {
return i;
}
}
//this is to handle the case when input array is not missing any element.
return (threshold+1);
}
public int solutionMissingInteger(int[] A) {
int solution = 1;
HashSet<Integer> hashSet = new HashSet<>();
for(int i=0; i<A.length; ++i){
if(A[i]<1) continue;
if(hashSet.add(A[i])){
//this int was not handled before
while(hashSet.contains(solution)){
solution++;
}
}
}
return solution;
}
Simple Java soution. Scored 100/100 in correctness and performance.
public int solution(int[] A) {
int smallestMissingInteger = 1;
if (A.length == 0) {
return smallestMissingInteger;
}
Set<Integer> set = new HashSet<Integer>();
for (int i = 0; i < A.length; i++) {
if (A[i] > 0) {
set.add(A[i]);
}
}
while (set.contains(smallestMissingInteger)) {
smallestMissingInteger++;
}
return smallestMissingInteger;
}
Build a hash table of all the values. For the numbers 1 to n + 1, check if they are in the hash table. At least one of them is not. Print out the lowest such number.
This is O(n) expected time (you can get with high probability). See #Gassa's answer for how to avoid the hash table in favor of a lookup table of size O(n).
JavaScript 100%
function solution(A) {
let sortedOb = {};
let biggest = 0;
A.forEach(el => {
if (el > 0) {
sortedOb[el] = 0;
biggest = el > biggest ? el : biggest;
}
});
let arr = Object.keys(sortedOb).map(el => +el);
if (arr.length == 0) return 1;
for(let i = 1; i <= biggest; i++) {
if (sortedOb[i] === undefined) return i;
}
return biggest + 1;
}
100% Javascript
function solution(A) {
// write your code in JavaScript (Node.js 4.0.0)
var max = 0;
var array = [];
for (var i = 0; i < A.length; i++) {
if (A[i] > 0) {
if (A[i] > max) {
max = A[i];
}
array[A[i]] = 0;
}
}
var min = max;
if (max < 1) {
return 1;
}
for (var j = 1; j < max; j++) {
if (typeof array[j] === 'undefined') {
return j
}
}
if (min === max) {
return max + 1;
}
}
C# scored 100%,
Explanation: use of lookup table where we store already seen values from input array, we only care about values that are greater than 0 and lower or equal than length on input array
public static int solution(int[] A)
{
var lookUpArray = new bool[A.Length];
for (int i = 0; i < A.Length; i++)
if (A[i] > 0 && A[i] <= A.Length)
lookUpArray[A[i] - 1] = true;
for (int i = 0; i < lookUpArray.Length; i++)
if (!lookUpArray[i])
return i + 1;
return A.Length + 1;
}
This is my solution is Swift 4
public func solution(_ A: inout [Int]) -> Int {
var minNum = 1
var hashSet = Set<Int>()
for int in A {
if int > 0 {
hashSet.insert(int)
}
}
while hashSet.contains(minNum) {
minNum += 1
}
return minNum
}
var array = [1,3,6]
solution(&array)
// Answer: 2
100%: the Python sort routine is not regarded as cheating...
def solution(A):
"""
Sort the array then loop till the value is higher than expected
"""
missing = 1
for elem in sorted(A):
if elem == missing:
missing += 1
if elem > missing:
break
return missing
It worked for me. It is not O(n), but little simpler:
import java.util.stream.*;
class Solution {
public int solution(int[] A) {
A = IntStream.of(A)
.filter(x->x>0)
.distinct()
.sorted()
.toArray();
int min = 1;
for(int val : A)
{
if(val==min)
min++;
else
return min;
}
return min;
}
}
My solution. 100%. In Java.
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class Solution {
public int solution(int[] A) {
Arrays.sort(A);
ArrayList<Integer> positive = new ArrayList<>();
for (int i = 0; i < A.length; i++) {
if(A[i] > 0)
positive.add(A[i]);
}
if(positive.isEmpty()) return 1;
if(positive.get(0) > 1) return 1;
for(int i = 0; i < positive.size() - 1; i++) {
if(positive.get(i + 1) - positive.get(i) > 1)
return positive.get(i) + 1;
}
return positive.get(positive.size() - 1) + 1;
}
public static void main(String[] args) {
Solution solution = new Solution();
int[] A = {-5,1,2,3,4,6,7,8,9,5};
System.out.println(solution.solution(A));
}
}
javascript 100% 100%
first sort the array, you just need to scan positive elements so find index of 1 (if there is no 1 in array then answer is 1). then search elements after 1 till find missing number.
function solution(A) {
// write your code in JavaScript (Node.js 6.4.0)
var missing = 1;
// sort the array.
A.sort(function(a, b) { return a-b });
// try to find the 1 in sorted array if there is no 1 so answer is 1
if ( A.indexOf(1) == -1) { return 1; }
// just search positive numbers to find missing number
for ( var i = A.indexOf(1); i < A.length; i++) {
if ( A[i] != missing) {
missing++;
if ( A[i] != missing ) { return missing; }
}
}
// if cant find any missing number return next integer number
return missing + 1;
}
I believe the solution is more involved than 'marking' corresponding values using a boolean array of n (100,000) elements. The boolean array of size n will not 'directly' map to the possible range of values (−2,147,483,648 to 2,147,483,647).
This Java example I wrote attempts to map the 100K rows by mapping the value based on their offset from the max value. It also performs a modulus to reduce the resulting array to the same size as the sample element length.
/**
*
* This algorithm calculates the values from the min value and mods this offset with the size of the 100K sample size.
* This routine performs 3 scans.
* 1. Find the min/max
* 2. Record the offsets for the positive integers
* 3. Scan the offsets to find missing value.
*
* #author Paul Goddard
*
*/
public class SmallestPositiveIntMissing {
static int ARRAY_SIZE = 100000;
public static int solve(int[] array) {
int answer = -1;
Maxmin maxmin = getMaxmin(array);
int range = maxmin.max - maxmin.min;
System.out.println("min: " + maxmin.min);
System.out.println("max: " + maxmin.max);
System.out.println("range: " + range);
Integer[] values = new Integer[ARRAY_SIZE];
if (range == ARRAY_SIZE) {
System.out.println("No gaps");
return maxmin.max + 1;
}
for (int val: array) {
if (val > 0) {
int offset = val - maxmin.min;
int index = offset % ARRAY_SIZE;
values[index] = val;
}
}
for (int i = 0; i < ARRAY_SIZE; i++) {
if (values[i] == null) {
int missing = maxmin.min + i;
System.out.println("Missing: " + missing);
answer = missing;
break;
}
}
return answer;
}
public static Maxmin getMaxmin(int[] array) {
int max = Integer.MIN_VALUE;
int min = Integer.MAX_VALUE;
for (int val:array) {
if (val >=0) {
if (val > max) max = val;
if (val < min) min = val;
}
}
return new Maxmin(max,min);
}
public static void main(String[] args) {
int[] A = arrayBuilder();
System.out.println("Min not in array: " + solve(A));
}
public static int[] arrayBuilder() {
int[] array = new int[ARRAY_SIZE];
Random random = new Random();
System.out.println("array: ");
for (int i=0;i < ARRAY_SIZE; i++) {
array[i] = random.nextInt();
System.out.print(array[i] + ", ");
}
System.out.println(" array done.");
return array;
}
}
class Maxmin {
int max;
int min;
Maxmin(int max, int min) {
this.max = max;
this.min = min;
}
}
Sweet Swift version. 100% correct
public func solution(inout A : [Int]) -> Int {
//Create a Hash table
var H = [Int:Bool]()
// Create the minimum possible return value
var high = 1
//Iterate
for i in 0..<A.count {
// Get the highest element
high = A[i] > high ? A[i] : high
// Fill hash table
if (A[i] > 0){
H[A[i]] = true
}
}
// iterate through possible values on the hash table
for j in 1...high {
// If you could not find it on the hash, return it
if H[j] != true {
return j
} else {
// If you went through all values on the hash
// and can't find it, return the next higher value
// e.g.: [1,2,3,4] returns 5
if (j == high) {
return high + 1
}
}
}
return high
}
int[] copy = new int[A.length];
for (int i : A)
{
if (i > 0 && i <= A.length)
{
copy[i - 1] = 1;
}
}
for (int i = 0; i < copy.length; i++)
{
if (copy[i] == 0)
{
return i + 1;
}
}
return A.length + 1;
Swift 3 - 100%
public func solution(_ A : inout [Int]) -> Int {
// write your code in Swift 3.0 (Linux)
var solution = 1
var hashSet = Set<Int>()
for int in A
{
if int > 0
{
hashSet.insert(int)
while hashSet.contains(solution)
{
solution += 1
}
}
}
return solution
}
Thanks to Marian's answer above.
This is my solution using python:
def solution(A):
m = max(A)
if m <= 0:
return 1
if m == 1:
return 2
# Build a sorted list with all elements in A
s = sorted(list(set(A)))
b = 0
# Iterate over the unique list trying to find integers not existing in A
for i in xrange(len(s)):
x = s[i]
# If the current element is lte 0, just skip it
if x <= 0:
continue;
b = b + 1
# If the current element is not equal to the current position,
# it means that the current position is missing from A
if x != b:
return b
return m + 1
Scored 100%/100% https://codility.com/demo/results/demoDCU7CA-SBR/
Create a binary array bin of N+1 length (C uses 0 based indexing)
Traverse the binary array O(n)
If A[i] is within the bounds of bin then mark bin entry at index A[i] as present or true.
Traverse the binary array again
Index of any bin entry that is not present or false is your missing integer
~
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
int solution(int A[], int N) {
// write your code in C99 (gcc 6.2.0)
int i;
bool *bin = (bool *)calloc((N+1),sizeof(bool));
for (i = 0; i < N; i++)
{
if (A[i] > 0 && A[i] < N+1)
{
bin[A[i]] = true;
}
}
for (i = 1; i < N+1; i++)
{
if (bin[i] == false)
{
break;
}
}
return i;
}
May be helpful, I am using arithmetic progression to calculate the sum, and using binary searach the element is fetched. checked with array of couple of hundred values works good. As there is one for loop and itression in step of 2, O(n/2) or less
def Missingelement (A):
B = [x for x in range(1,max(A)+1,1)]
n1 = len(B) - 1
begin = 0
end = (n1)//2
result = 0
print(A)
print(B)
if (len(A) < len(B)):
for i in range(2,n1,2):
if BinSum(A,begin,end) > BinSum(B,begin,end) :
end = (end + begin)//2
if (end - begin) <= 1 :
result=B[begin + 1 ]
elif BinSum(A,begin,end) == BinSum(B,begin,end):
r = end - begin
begin = end
end = (end + r)
if begin == end :
result=B[begin + 1 ]
return result
def BinSum(C,begin,end):
n = (end - begin)
if end >= len(C):
end = len(C) - 1
sum = n*((C[begin]+C[end])/2)
return sum
def main():
A=[1,2,3,5,6,7,9,10,11,12,14,15]
print ("smallest number missing is ",Missingelement(A))
if __name__ == '__main__': main()
Code for C, in fact, this can be used for any programming language without any change in the logic.
Logic is sum of N number is N*(N+1)/2.
int solution(int A[], int N) {
// write your code in C99
long long sum=0;
long long i;
long long Nsum=0;
for(i=0;i<N;i++){
sum=sum + (long long)A[i];
}
if (N%2==0){
Nsum= (N+1)*((N+2)/2);
return (int)(Nsum-sum);
}
else{
Nsum= ((N+1)/2)*(N+2);
return (int)(Nsum-sum);
}
}
This gave the 100/100 score.
This solution gets 100/100 on the test:
class Solution {
public int solution(int[] A) {
int x = 0;
while (x < A.length) {
// Keep swapping the values into the matching array positions.
if (A[x] > 0 && A[x] <= A.length && A[A[x]-1] != A[x]) {
swap(A, x, A[x] - 1);
} else {
x++; // Just need to increment when current element and position match.
}
}
for (int y=0; y < A.length; y++) {
// Find first element that doesn't match position.
// Array is 0 based while numbers are 1 based.
if (A[y] != y + 1) {
return y + 1;
}
}
return A.length + 1;
}
private void swap (int[] a, int i, int j) {
int t = a[i];
a[i] = a[j];
a[j] = t;
}
}
100% in PHP https://codility.com/demo/results/trainingKFXWKW-56V/
function solution($A){
$A = array_unique($A);
sort($A);
if (empty($A)) return 1;
if (max($A) <= 0) return 1;
if (max($A) == 1) return 2;
if (in_array(1, $A)) {
$A = array_slice($A, array_search(1, $A)); // from 0 to the end
array_unshift($A, 0); // Explanation 6a
if ( max($A) == array_search(max($A), $A)) return max($A) + 1; // Explanation 6b
for ($i = 1; $i <= count($A); $i++){
if ($A[$i] != $i) return $i; // Explanation 6c
}
} else {
return 1;
}
}
// Explanation
remove all duplicates
sort from min to max
if the array is empty return 1
if max of array is zero or less, return 1
if max of array is 1, return 2 // next positive integer
all other cases:
6a) split the array from value 1 to the end and add 0 before first number
6b) if the value of last element of array is the max of array, then the array is ascending so we return max + 1 // next positive integer
6c) if the array is not ascending, we find a missing number by a function for: if key of element is not as value the element but it should be (A = [0=>0, 1=>1,2=>3,...]), we return the key, because we expect the key and value to be equal.
Here is my solution, it Yields 88% in evaluation- Time is O(n), Correctness 100%, Performance 75%. REMEMBER - it is possible to have an array of all negative numbers, or numbers that exceed 100,000. Most of the above solutions (with actual code) yield much lower scores, or just do not work. Others seem to be irrelevant to the Missing Integer problem presented on Codility.
int compare( const void * arg1, const void * arg2 )
{
return *((int*)arg1) - *((int*)arg2);
}
solution( int A[], int N )
{
// Make a copy of the original array
// So as not to disrupt it's contents.
int * A2 = (int*)malloc( sizeof(int) * N );
memcpy( A2, A1, sizeof(int) * N );
// Quick sort it.
qsort( &A2[0], N, sizeof(int), compare );
// Start out with a minimum of 1 (lowest positive number)
int min = 1;
int i = 0;
// Skip past any negative or 0 numbers.
while( (A2[i] < 0) && (i < N )
{
i++;
}
// A variable to tell if we found the current minimum
int found;
while( i < N )
{
// We have not yet found the current minimum
found = 0;
while( (A2[i] == min) && (i < N) )
{
// We have found the current minimum
found = 1;
// move past all in the array that are that minimum
i++;
}
// If we are at the end of the array
if( i == N )
{
// Increment min once more and get out.
min++;
break;
}
// If we found the current minimum in the array
if( found == 1 )
{
// progress to the next minimum
min++;
}
else
{
// We did not find the current minimum - it is missing
// Get out - the current minimum is the missing one
break;
}
}
// Always free memory.
free( A2 );
return min;
}
My 100/100 solution
public int solution(int[] A) {
Arrays.sort(A);
for (int i = 1; i < 1_000_000; i++) {
if (Arrays.binarySearch(A, i) < 0){
return i;
}
}
return -1;
}
static int spn(int[] array)
{
int returnValue = 1;
int currentCandidate = 2147483647;
foreach (int item in array)
{
if (item > 0)
{
if (item < currentCandidate)
{
currentCandidate = item;
}
if (item <= returnValue)
{
returnValue++;
}
}
}
return returnValue;
}

Find the number of intersecting circles [duplicate]

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;
}
}

How to find the longest palindromic subsequence (not its length)

I want to find out the longest palindromic subsequence in a string. Everywhere I find the algorithm to find out the length of the subsequence, with the statement that the algo can be extended to return the subsequence as well, but nowhere have I found how. Can anybody explain how can I get the sequence as well?
Since you mentioned the link Longest Palindromic Subsequence in geeksforgeeks, I modified the solution to output the result. I think we need one auxiliary two-dimensions array to stored how the palindromic subsequence comes from, so we can get the result through the auxiliary array at last. You can see the logic in the below code:
#include<iostream>
#include<cstring>
using namespace std;
// A utility function to get max of two integers
int max (int x, int y) { return (x > y)? x : y; }
// Returns the length of the longest palindromic subsequence in seq
int lps(char *str,char *result)
{
int n = strlen(str);
int i, j, cl;
int L[n][n]; // Create a table to store results of subproblems
int Way[n][n];// Store how the palindrome come from.
// Strings of length 1 are palindrome of lentgh 1
for (i = 0; i < n; i++)
{
L[i][i] = 1;
Way[i][i]=0;
}
// Build the table. Note that the lower diagonal values of table are
// useless and not filled in the process. The values are filled in a
// manner similar to Matrix Chain Multiplication DP solution (See
// http://www.geeksforgeeks.org/archives/15553). cl is length of
// substring
for (cl=2; cl<=n; cl++)
{
for (i=0; i<n-cl+1; i++)
{
j = i+cl-1;
if (str[i] == str[j] && cl == 2)
{
L[i][j] = 2;
Way[i][j]=0;
}
else if (str[i] == str[j])
{
L[i][j] = L[i+1][j-1] + 2;
Way[i][j]=0;
}
else
{
if(L[i][j-1]>L[i+1][j])
{
L[i][j]=L[i][j-1];
Way[i][j]=1;
}
else
{
L[i][j]=L[i+1][j];
Way[i][j]=2;
}
}
}
}
int index=0;
int s=0,e=n-1;
while(s<=e)
{
if(Way[s][e]==0)
{
result[index++]=str[s];
s+=1;
e-=1;
}
else if(Way[s][e]==1)e-=1;
else if(Way[s][e]==2)s+=1;
}
int endIndex=(L[0][n-1]%2)?index-1:index;
for(int k=0;k<endIndex;++k)result[L[0][n-1]-1-k]=result[k];
result[index+endIndex]='\0';
return L[0][n-1];
}
/* Driver program to test above functions */
int main()
{
char seq[] = "GEEKSFORGEEKS";
char result[20];
cout<<"The lnegth of the LPS is "<<lps(seq,result)<<":"<<endl;
cout<<result<<endl;
getchar();
return 0;
}
Hope it helps!
Below is the explanation:
Let X[0..n-1] be the input sequence of length n and L(0, n-1) be the length of the longest palindromic sub-sequence of X[0..n-1].
There are 5 cases in total.
1)Every single character is a palindrome of length 1.
L(i, i) = 1 for all indexes i in given sequence.
2)There are only 2 characters and both are same.
L(i, j) = 2.
3)There are more than two characters, and first and last characters are the same
L(i, j) = L(i + 1, j - 1) + 2
4)First and last characters are not the same and L(i + 1, j)< L(i, j - 1). L(i, j) = L(i, j - 1).
5)First and last characters are not the same and L(i + 1, j)>=L(i, j - 1). L(i, j) = L(i + 1, j).
We can observed that only in case 1,2 and 3, the character X[i] is included in the final result. We used a two-dimension auxiliary array to represent how the palindromic sub-sequence comes from.
value 0 for case 1,2,3; value 1 for case 4; value 2 for case 5.
With the auxiliary array Way. We can get the result as below:
Let two variables s=0 and e=n-1.
While s<=e
Loop
If Way[s][e]==0 Then X[s] should be included in the result and we store it in our result array.
Else if Way[s][e]==1 Then X[s] should not be include in the result and update e=e-1 (because our result comes from case 4).
Else if Way[s][e]==2 Then X[s] should not be include in the result and update s=s+1 (because our result comes from case 5).
The loop should be terminated when s>e. In that way we can get half part of the result and we can easily extend it to get the whole result.
Keep a backpointer as well as a value in your dynamic programming table for each cell. Then follow the traceback from the end of the table to reconstruct the subsequence.
The trick works like this:
save the reverse of your string in a temporary buffer
use the Longest Common Substring Algorithm to find the LCS.
Note that by definition of your second string, the LCS of both strings is the longest palindrome as well.
The below solution is pretty straight forward and requires no additional use of any other matrix.
Here we are just tracing back our path to generate the longest palindromic sub sequence.
int lps(char *str)
{
int n = strlen(str);
int i, j, cl;
int L[n][n];
for (i = 0; i < n; i++)
L[i][i] = 1;
for (cl=2; cl<=n; cl++)
{
for (i=0; i<n-cl+1; i++)
{
j = i+cl-1;
if (str[i] == str[j] && cl == 2)
L[i][j] = 2;
else if (str[i] == str[j])
L[i][j] = L[i+1][j-1] + 2;
else
L[i][j] = max(L[i][j-1], L[i+1][j]);
}
}
cout<<L[0][n-1]<<endl;
i = 0,j = n-1;
vector<char> result;
while(i<=j)
{
if(str[i]==str[j])
{
result.push_back(str[i]);
i++,j--;
}
else if(L[i][j-1]>L[i+1][j])
{
j--;
}
else
{
i++;
}
}
if(L[0][n-1]%2==0)
{
for(auto i = result.begin();i!=result.end();i++)
cout<<*i;
reverse(result.begin(),result.end());
for(auto i = result.begin();i!=result.end();i++)
cout<<*i;
}
else
{
for(auto i = result.begin();i!=result.end();i++)
cout<<*i;
reverse(result.begin(),result.end());
result.erase(result.begin());
for(auto i = result.begin();i!=result.end();i++)
cout<<*i;
}
}
A Java approach .Building the string from the LPS matrix generated during calculation of length of the palindromic sub-sequence.
private static void LongestPalindromicSubsequence(char a[])
{
int len=a.length;
int lps[][]=new int[len][len];
int l=1;
for(int i=0;i<len;i++)
{
lps[i][i]=1; //---------> Length of subsequence of string of length=1 is 1 <------------
}
for(int subsLen=2;subsLen<=len;subsLen++)
{
for( int i=0;i<(len-subsLen+1);i++)
{
int j=i+subsLen-1;
if(a[i]==a[j]&&subsLen==2)
{
lps[i][j]=2;
}
else
{
if(a[i]!=a[j])
{
lps[i][j]=Math.max(lps[i+1][j],lps[i][j-1]);
}
else
{
lps[i][j]=2+lps[i+1][j-1];
}
}
}
}
// System.out.println("Length of longest Palindromic subsequence: "+lps[0][len-1]);
printLongestPalindromicsubsequence(a,lps);
}
private static void printLongestPalindromicsubsequence(char[] a, int[][] lps)
{
int len=a.length;
int end=lps[0][len-1];
char str[]=new char[end+1];
str[end--]='\0';
int i=0,j=len-1;
while(end>=0&&i<=j)
{
if(a[i]==a[j])
{
str[end--]=a[i];
i++;
j--;
}
else
{
if(lps[i+1][j]>lps[i][j-1])
{
i++;
}
else
{
j--;
}
}
}
if(lps[0][len-1]%2!=0)
{
i=0;
int mid=lps[0][len-1]/2;
j=str.length-2;
while(j>mid)
{
str[i++]=str[j--];
}
}
else
{
i=0;
int mid=lps[0][len-1]/2;
j=str.length-2;
while(j>=mid)
{
str[i++]=str[j--];
}
}
for(i=0;i<str.length;i++)
System.out.print(str[i]);
}
A sample java implementation. Feel free to be brutal with your review comments.
public class LongestPalindrome {
public static void main(String... arguments) {
final String content = "GOBANANAS";
String palindrome = getLongestPalindrome(content);
System.out.println(palindrome);
}
private static String getLongestPalindrome(final String content) {
String lastPalindrome = "";
for (int lastIndex = content.length(); lastIndex >= 0; lastIndex--) {
for (int i = 0; i <= lastIndex; i++) {
String part = content.substring(i, lastIndex);
if (part.length() > lastPalindrome.length() && part.length() > 1) {
boolean isPalindrome = isPalindrome(part);
if (isPalindrome) {
lastPalindrome = part;
System.out.println(String.format("%s : %s", part, isPalindrome));
}
}
}
}
return lastPalindrome;
}
private static boolean isPalindrome(String string) {
String reverse = (new StringBuilder(string)).reverse().toString();
return (string.equals(reverse));
}
}

Run length encoding using O(1) space

Can we do the run-length encoding in place(assuming the input array is very large)
We can do for the cases such as AAAABBBBCCCCDDDD
A4B4C4D4
But how to do it for the case such as ABCDEFG?
where the output would be A1B1C1D1E1F1G1
My first thought was to start encoding from the end, so we will use the free space (if any), after that we can shift the encoded array to the start. A problem with this approach is that it will not work for AAAAB, because there is no free space (it's not needed for A4B1) and we will try to write AAAAB1 on the first iteration.
Below is corrected solution:
(let's assume the sequence is AAABBC)
encode all groups with two or more elements and leave the rest unchanged (this will not increase length of the array) -> A3_B2C
shift everything right eliminating empty spaces after first step -> _A3B2C
encode the array from the start (reusing the already encoded groups of course) -> A3B2C1
Every step is O(n) and as far as I can see only constant additional memory is needed.
Limitations:
Digits are not supported, but that anyway would create problems with decoding as Petar Petrov mentioned.
We need some kind of "empty" character, but this can be worked around by adding zeros: A03 instead of A3_
C++ solution O(n) time O(1) space
string runLengthEncode(string str)
{
int len = str.length();
int j=0,k=0,cnt=0;
for(int i=0;i<len;i++)
{
j=i;
cnt=1;
while(i<len-1 && str[i]==str[i+1])
{
i++;
cnt++;
}
str[k++]=str[j];
string temp =to_string(cnt);
for(auto m:temp)
str[k++] = m;
}
str.resize(k);
return str;
}
null is used to indicate which items are empty and will be ignored for encoding. Also you can't encode digits (AAA2222 => A324 => 324 times 'A', but it's A3;24). Your question opens more questions.
Here's a "solution" in C#
public static void Encode(string[] input)
{
var writeIndex = 0;
var i = 0;
while (i < input.Length)
{
var symbol = input[i];
if (symbol == null)
{
break;
}
var nextIndex = i + 1;
var offset = 0;
var count = CountSymbol(input, symbol, nextIndex) + 1;
if (count == 1)
{
ShiftRight(input, nextIndex);
offset++;
}
input[writeIndex++] = symbol;
input[writeIndex++] = count.ToString();
i += count + offset;
}
Array.Clear(input, writeIndex, input.Length - writeIndex);
}
private static void ShiftRight(string[] input, int nextIndex)
{
var count = CountSymbol(input, null, nextIndex, (a, b) => a != b);
Array.Copy(input, nextIndex, input, nextIndex + 1, count);
}
private static int CountSymbol(string[] input, string symbol, int nextIndex)
{
return CountSymbol(input, symbol, nextIndex, (a, b) => a == b);
}
private static int CountSymbol(string[] input, string symbol, int nextIndex, Func<string, string, bool> cmp)
{
var count = 0;
var i = nextIndex;
while (i < input.Length && cmp(input[i], symbol))
{
count++;
i++;
}
return count;
}
The 1st solution does not take care of single characters. For example - 'Hi!' will not work. I've used totally different approach, used 'insert()' functions to add inplace. This take care of everything, whether the total 'same' character is > 10 or >100 or = 1.
#include<iostream>
#include<algorithm>
using namespace std;
int main(){
string name = "Hello Buddy!!";
int start = 0;
char distinct = name[0];
for(int i=1;i<name.length()+1;){
if(distinct!=name[i]){
string s = to_string(i-start);
name.insert(start+1,s);
name.erase(name.begin() + start + 1 + s.length(),name.begin() + s.length() + i);
i=start+s.length()+1;
start=i;
distinct=name[start];
continue;
}
i++;
}
cout<<name;
}
Suggest me if you find anything incorrect.
O(n), in-place RLE, I couldn't think better than this. It will not place a number, if chars occurence is just 1. Will also place a9a2, if the character comes 11 times.
void RLE(char *str) {
int len = strlen(str);
int count = 1, j = 0;
for (int i = 0; i < len; i++){
if (str[i] == str[i + 1])
count++;
else {
int times = count / 9;
int rem = count % 9;
for (int k = 0; k < times; k++) {
str[j++] = str[i];
_itoa(9, &str[j++], 10);
count = count - 9;
}
if (count > 1) {
str[j++] = str[i];
_itoa(rem, &str[j++], 10);
count = 1;
}
else
str[j++] = str[i];
}
}
cout << str;
}
I/P => aaabcdeeeefghijklaaaaa
O/P => a3bcde4fghijkla5
Inplace solution using c++ ( assumes length of encoding string is not more than actual string length):
#include <bits/stdc++.h>
#include<stdlib.h>
using namespace std;
void replacePattern(char *str)
{
int len = strlen(str);
if (len == 0)
return;
int i = 1, j = 1;
int count;
// for each character
while (str[j])
{
count = 1;
while (str[j] == str[j-1])
{
j = j + 1;
count++;
}
while(count > 0) {
int rem = count%10;
str[i++] = to_string(rem)[0];
count = count/10;
}
// copy character at current position j
// to position i and increment i and j
if (str[j])
str[i++] = str[j++];
}
// add a null character to terminate string
if(str[len-1] != str[len-2]) {
str[i] = '1';
i++;
}
str[i] = '\0';
}
// Driver code
int main()
{
char str[] = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabccccc";
replacePattern(str);
cout << str;
return 0;
}

Longest Common Subsequence among 3 Strings

I've implemented the dynamic programming solution to find the longest common subsequence among 2 strings. There is apparently a way to generalize this algorithm to find the LCS among 3 strings, but in my research I have not found any information on how to go about this. Any help would be appreciated.
To find the Longest Common Subsequence (LCS) of 2 strings A and B, you can traverse a 2-dimensional array diagonally like shown in the Link you posted. Every element in the array corresponds to the problem of finding the LCS of the substrings A' and B' (A cut by its row number, B cut by its column number). This problem can be solved by calculating the value of all elements in the array. You must be certain that when you calculate the value of an array element, all sub-problems required to calculate that given value has already been solved. That is why you traverse the 2-dimensional array diagonally.
This solution can be scaled to finding the longest common subsequence between N strings, but this requires a general way to iterate an array of N dimensions such that any element is reached only when all sub-problems the element requires a solution to has been solved.
Instead of iterating the N-dimensional array in a special order, you can also solve the problem recursively. With recursion it is important to save the intermediate solutions, since many branches will require the same intermediate solutions. I have written a small example in C# that does this:
string lcs(string[] strings)
{
if (strings.Length == 0)
return "";
if (strings.Length == 1)
return strings[0];
int max = -1;
int cacheSize = 1;
for (int i = 0; i < strings.Length; i++)
{
cacheSize *= strings[i].Length;
if (strings[i].Length > max)
max = strings[i].Length;
}
string[] cache = new string[cacheSize];
int[] indexes = new int[strings.Length];
for (int i = 0; i < indexes.Length; i++)
indexes[i] = strings[i].Length - 1;
return lcsBack(strings, indexes, cache);
}
string lcsBack(string[] strings, int[] indexes, string[] cache)
{
for (int i = 0; i < indexes.Length; i++ )
if (indexes[i] == -1)
return "";
bool match = true;
for (int i = 1; i < indexes.Length; i++)
{
if (strings[0][indexes[0]] != strings[i][indexes[i]])
{
match = false;
break;
}
}
if (match)
{
int[] newIndexes = new int[indexes.Length];
for (int i = 0; i < indexes.Length; i++)
newIndexes[i] = indexes[i] - 1;
string result = lcsBack(strings, newIndexes, cache) + strings[0][indexes[0]];
cache[calcCachePos(indexes, strings)] = result;
return result;
}
else
{
string[] subStrings = new string[strings.Length];
for (int i = 0; i < strings.Length; i++)
{
if (indexes[i] <= 0)
subStrings[i] = "";
else
{
int[] newIndexes = new int[indexes.Length];
for (int j = 0; j < indexes.Length; j++)
newIndexes[j] = indexes[j];
newIndexes[i]--;
int cachePos = calcCachePos(newIndexes, strings);
if (cache[cachePos] == null)
subStrings[i] = lcsBack(strings, newIndexes, cache);
else
subStrings[i] = cache[cachePos];
}
}
string longestString = "";
int longestLength = 0;
for (int i = 0; i < subStrings.Length; i++)
{
if (subStrings[i].Length > longestLength)
{
longestString = subStrings[i];
longestLength = longestString.Length;
}
}
cache[calcCachePos(indexes, strings)] = longestString;
return longestString;
}
}
int calcCachePos(int[] indexes, string[] strings)
{
int factor = 1;
int pos = 0;
for (int i = 0; i < indexes.Length; i++)
{
pos += indexes[i] * factor;
factor *= strings[i].Length;
}
return pos;
}
My code example can be optimized further. Many of the strings being cached are duplicates, and some are duplicates with just one additional character added. This uses more space than necessary when the input strings become large.
On input: "666222054263314443712", "5432127413542377777", "6664664565464057425"
The LCS returned is "54442"

Resources