I am solving Codility problem CountSemiprimes: Count the semiprime numbers in the given range [a..b].
Task description
A prime is a positive integer X that has exactly two distinct divisors: 1 and X. The first few prime integers are 2, 3, 5, 7, 11 and 13.
A semiprime is a natural number that is the product of two (not necessarily distinct) prime numbers. The first few semiprimes are 4, 6, 9, 10, 14, 15, 21, 22, 25, 26.
You are given two non-empty arrays P and Q, each consisting of M integers. These arrays represent queries about the number of semiprimes within specified ranges.
Query K requires you to find the number of semiprimes within the range (P[K], Q[K]), where 1 ≤ P[K] ≤ Q[K] ≤ N.
Write an efficient algorithm for the following assumptions:
N is an integer within the range [1..50,000];
M is an integer within the range [1..30,000];
each element of arrays P, Q is an integer within the range [1..N];
P[i] ≤ Q[i].
My solution
My current score is 66% and problem is preformance for large data set:
large random, length = ~30,000
all max ranges
Test says, that it should take about 2sec, but my solution takes over 7sec.
This is my current solution
class Solution {
private static List<Integer> getPrimes(int max) {
List<Integer> primes = new ArrayList<>(max / 2);
for (int i = 0; i < max; i++)
if (isPrime(i))
primes.add(i);
return primes;
}
private static boolean isPrime(int val) {
if (val <= 1)
return false;
if (val <= 3)
return true;
for (int i = 2, sqrt = (int)Math.sqrt(val); i <= sqrt; i++)
if (val % i == 0)
return false;
return true;
}
private static boolean[] getSemiPrimes(int N) {
List<Integer> primes = getPrimes(N);
boolean[] semiPrimes = new boolean[N + 1];
for (int i = 0; i < primes.size(); i++) {
if (primes.get(i) > N)
break;
for (int j = i; j < primes.size(); j++) {
if (primes.get(j) > N || N / primes.get(i) < primes.get(j))
break;
int semiPrime = primes.get(i) * primes.get(j);
if (semiPrime <= N)
semiPrimes[semiPrime] = true;
}
}
return semiPrimes;
}
public static int[] solution(int N, int[] P, int[] Q) {
boolean[] semiPrimes = getSemiPrimes(N);
int[] res = new int[P.length];
for (int i = 0; i < res.length; i++)
for (int j = P[i]; j <= Q[i]; j++)
if (semiPrimes[j])
res[i]++;
return res;
}
}
Any ideas about improving performance? My last one was to remove Set for holding semi-primes with array. It helped me to solve couple of performance tests.
A Java solution which scores 100% is as follow:
Find the set of prime numbers which their products is not greater than N
create semi-prime from them as a bit wise array of 0 and 1
create a prefix sum of the semi-primes
calculate the queries from P[i] to Q[i] in O(M)
The whole algorithm is of O(N * log(log(N)) + M) stated by the Codility's test result evaluation.
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class CountSemiPrime {
public static void main(String[] args) {
int[] P = new int[] {1, 4, 16};
int[] Q = new int[] {26, 10, 20};
System.out.println( Arrays.toString( new CountSemiPrime().solution( 26, P, Q ) ) );
}
public int[] solution(int N, int[] P, int[] Q) {
Integer[] primes = sieve(N/2+1);
int[] temp = new int[N+1];
for (int i = 0; i < primes.length; i++) {
for (int j = 0; j < primes.length; j++) {
int semiPrime = primes[i] * primes[j];
if(semiPrime <= N)
temp[semiPrime] = 1;
}
}
int[] prefix = new int[N+1];
for (int i = 1; i < temp.length; i++) {
prefix[i] = temp[i] + prefix[i-1];
}
int[] retVal = new int[P.length];
for (int i = 0; i < retVal.length; i++) {
retVal[i] = prefix[Q[i]] - prefix[P[i]-1];
}
return retVal;
}
public Integer[] sieve(int n) {
boolean[] temp = new boolean[n+1];
for (int i = 0; i < temp.length; i++) {
temp[i] = true;
}
temp[0] = temp[1] = false;
int i = 2;
while (i * i <= n) {
removeProducts( temp, i );
i++;
}
List<Integer> ret = new ArrayList<>();
for (int j = 0; j < temp.length; j++) {
if(temp[j])
ret.add( j );
}
return ret.toArray( new Integer[ret.size()] );
}
private void removeProducts(boolean[] temp, int i) {
for (int j = i*i; j < temp.length; j++) {
if(temp[j] && j % i == 0) {
temp[j] = false;
}
}
}
}
You can precompute an array A of size N+1, which stores at A[i] the number of semiprimes less than or equal to i. Then a query p, q can be computed immediately: the number of semiprimes between p and q (inclusive) is A[q] - A[p-1].
This array can be computed efficiently: let P be an array of primes less than or equal to N/2. Then (in java-like pseudocode):
A = new int[N+1]
for (int p : P) {
for (int q : P) {
if (p*q > N || q > p) break;
A[p*q] = 1
}
}
for (int i = 1; i <= N; i++)
A[i] += A[i-1]
This works by marking the semiprimes with a 1 in the array, and then taking a cumulative sum. It runs in better than O(N^2) and worse than O(N) time -- there's about N/2logN primes in P, so the first part is O((N/logN)^2), and the summing-up is O(N). [Note: I guess the first part has better complexity than O((N/log N)^2) because of the early termination of the inner loop, but I've not proved that]. Computing the primes in P is O(N log log N) using the sieve of Erastothenes.
A Python version of this program takes 0.07s to precompute A for N=50000, and to perform 30000 queries. It gets a perfect score (100) when run on codility, and codility reports that it detects the code to be have complexity O(N log(log(N)) + M).
Ruby 100% solution
require 'prime'
require 'set'
def solution(n, p, q)
primes = Prime::EratosthenesGenerator.new.take_while {|i| i <= n/2 }
sqrt = Math.sqrt(n)
semiprimes = primes.each_with_index.inject(Set.new) do |acc, (e,i)|
break acc if e > sqrt.to_i
primes[i..-1].each{ |pr| e*pr > n ? break : acc << e*pr }
acc
end
offsets = semiprimes.sort.each_with_index.inject([]) {|acc,(el,i)| acc[el] = i+1;acc }
p.each_with_index.inject([]) do |acc, (el,i)|
next acc << 0 unless offsets[el..q[i]]
left = offsets[el..q[i]].detect{|a| a}
next acc << 0 unless left
right = offsets[el..q[i]].reverse_each.detect{|a| a}
acc << ((left..right).size)
end
end
My solution uses Sieve of Eratosthenes such that smallest prime factor of number N is stored in the array Factor[N].
Then if Factor[N/Factor[N]] = 0, we have a semi prime number incrementing a sum scan.
The entry r of the returned array will then be:
A[r]=Inclusive_scan[Q[r]]-Inclusive_scan[P[r]-1].
Here the corresponding python code (100% task score):
def solution(N, P, Q):
A=len(P)*[0]
if N<4:
return A
#Minimum prime factor of n stored in Factor[n]
Factor = [0] * (N + 1)
i = 2
while (i * i <= N):
if (Factor[i] == 0):
k = i * i
while (k <= N):
if (Factor[k] == 0):
Factor[k] = i;
k += i
i += 1
#Count semi prime numbers and store
#sum scan in array Incluse_scan
Incluse_scan=[0] * (N + 1)
cnt_semi=0
for k in range(4,N+1):
if Factor[k]!=0:
d=int(k/Factor[k])
if Factor[d]==0:
cnt_semi+=1
Incluse_scan[k]=cnt_semi
#Do the difference of semi prime counters
for r in range(0,len(P)):
if(P[r]<=4):
min_inclusive=0
else:
min_inclusive=P[r]-1
A[r]=Incluse_scan[Q[r]]-Incluse_scan[min_inclusive]
return A
this is my 100% solution in C++. you can find other answers in my github in cpp:
vector<int> getFactArr(int n) {
vector<int> f(n+1, 0);
f[1] = 1;
int i = 2;
while (i * i <= n) {
if (f[i] == 0) {
int k = i * i;
while (k <= n) {
if (f[k] == 0)
f[k] = i;
k+=i;
}
}
i++;
}
return f;
}
vector<int> solution(int N, vector<int> &P, vector<int> &Q) {
vector<int> F = getFactArr(N);
vector<int> prefix_semi_primes(N + 1, 0);
for (int x = 1; x <= N; x++) {
if (F[x] > 0 && F[x / F[x]] == 0)
prefix_semi_primes[x]++;
prefix_semi_primes[x] += prefix_semi_primes[x - 1];
}
const int M = P.size();
vector<int> ans(M, 0);
for (int i = 0; i < M; i++) {
ans[i] = prefix_semi_primes[Q[i]] - prefix_semi_primes[P[i] - 1];
}
return ans;
}
This was an interesting problem. I tried it and got 88% score.
Here is my strategy:
I used Sieve of Eratosthenes for getting a BitSet for primes.
Now I looped over that BitSet and added all the primes in a primeList.
My strategy for finding semi-primes was a bit interesting and I reached to this strategy incrementally.
private static boolean isSemiPrime(int n) {
if(n==1 || n==0 || primeBitSet.get(n))
return false;
int firstFactor = findFirstFactor(n);
if(firstFactor==0 || firstFactor==1)
return false;
return isPrime(n / firstFactor);
}
private static int findFirstFactor(int n) {
for (int i = 0; i < primeList.size(); i++) {
if (n % primeList.get(i) == 0)
return primeList.get(i);
}
// should never be the case
return 0;
}
I'm not very sure why I got 88% score. (What I'm missing)
But the most interesting and worth noting part was the strategy to check whether a given number is Semi-prime or not:
Find the first prime factor of the given number
Then checking that the quotient of the given number and the first-prime-factor is a prime or not.
If it is prime, then the given number is a semi-prime, otherwise the given number is not a semi prime.
Note that I also did a very naive form of book-keeping where I made a cumulative array which stores the total number of semi-primes till index x. One time filling this array and answering each of the query in O(1) is again obvious optimization.
Not related to the solution, but my Task Score was 88%, Correctness 100% and Performance 80%. I'll be happy to hear suggestions and anything that I missed.
Hope this helps. :)
const isSemiPrime = (num) => {
let cnt = 0
for (let i = 2; cnt < 2 && i * i <= num; ++i) {
while (num % i == 0) {
num /= i
++cnt
}
}
if (num > 1)++cnt
return cnt == 2 ? true : false
}
console.log(
[4, 6, 9, 10, 14, 15, 21, 22, 25, 26, 33, 34, 35, 38, 39, 46, 49, 51, 55].filter(isSemiPrime)
.length
)
Here the Javascript version of the solution, but it is 55%:
function solution(N, P, Q) {
function isPrime(num) {
for(var i = 2; i < num; i++)
if(num % i === 0) return false;
return num > 1;
}
const min = Math.min(...P)
const max = Math.max(...Q)
const A = []
for(let i=min;i<max;i++) {
for(let j=min;j<max;j++) {
if (isPrime(i) && isPrime(j)) {
const prod = j * i
if (prod > max) break
if (A.includes(prod)) continue
A.push(j * i)
}
}
}
const result = []
for(let i=0;i<P.length;i++) {
for(let j=P[i];j<=Q[i];j++) {
result[i] = result[i] || 0
if (A.includes(j)) {
result[i]++
}
}
}
return result
}
I would like to mention that the method you use for finding primes is inefficient.
Your code:
private static List<Integer> getPrimes(int max) {
List<Integer> primes = new ArrayList<>(max / 2);
** for (int i = 0; i < max; i++)
** if (isPrime(i))
** primes.add(i);
return primes;
}
private static boolean isPrime(int val) {
if (val <= 1)
return false;
if (val <= 3)
return true;
** for (int i = 2, sqrt = (int)Math.sqrt(val); i <= sqrt; i++)
** if (val % i == 0)
** return false;
return true;
}
I have marked the lines to pay attention to.
I would do something like this:
private static List<Integer> getPrimes(int max) {
List<Integer> primes = new ArrayList<>(max / 2);
primes.add(2);
for (int i = 3; i < max; i++)
if (isPrime(i, primes))
primes.add(i);
return primes;
}
private static boolean isPrime(int val, List<Integer> primes) {
int sqrtv = Math.sqrt(val);
for (int i = 0; i < primes.length(); i++)
{
int prime = primes.get(i);
if (val % primes.get(i) == 0)
{
return false;
} else if (prime > sqrtv) {
return true;
}
}
return true;
}
This plays on the fact that:
the only call to isPrime is from getPrimes. getPrimes will always call val in ascending order.
by the time isPrime is called with the parameter val, getPrimes has already got a list of all primes that are smaller than val.
there's no point in dividing with non-primes when determining primes. If we already know that a number 'a' is not divisible by 2, then why bother with dividing it by 4, 6, 8 or 10? If we know it isn't divisible by 3, then it won't be divisible by 9... so all of the non-prime checks are filtered by using the previously calculated primes only to perform the checking.
Here is my 100% in c++. I'm using prefixSum. Time complexity O(N * log(log(N)) + M).
#include <iostream>
#include <vector>
#include <cmath>
using namespace std;
vector<int> solution(int N, vector<int> &P, vector<int> &Q)
{
vector<bool> sieve(N, true);
vector<int> ret;
sieve[0] = sieve[1] = false;
int i = 2;
while (i * i <= N)
{
if (sieve[i])
{
int k = i * i;
while (k <= N)
{
sieve[k] = false;
k += i;
}
}
i++;
}
vector<int> prefixSum(N + 1, 0);
for (int i = 2; i <= sqrt(N); i++)
if (sieve[i])
for (int j = i; j <= N; j++)
{
if (j * i > N)
break;
if (sieve[j])
prefixSum[j * i]++;
}
int carry;
for (unsigned int i = 5; i < prefixSum.size(); i++)
{
carry = prefixSum[i - 1];
prefixSum[i] += carry;
}
for (unsigned int i = 0; i < P.size(); i++)
ret.push_back(prefixSum[Q[i]] - prefixSum[P[i] - 1]);
return ret;
}
A 100% solution broken down. https://app.codility.com/demo/results/trainingGVNHKU-MA5/
Firstly use the sieve of Eratosthenes to workout what is prime.
def get_sieve(n):
# Use the sieve or Eratosthenes to produce an array of primes
# where factor[n] == 0 indicates a prime number
factors = [0] * (n+1)
i=2
i2 = i*i
while (i2 <= n):
if not factors[i]:
k = i2
while k <= n:
if not factors[k]:
factors[k] = i
k += i
i += 1
i2 = i*i
return factors
Next, determine if the number is semi prime. If both its factors are prime its semiprime.
def is_semi_prime(n, factors):
if factors[n]: # Check its not a prime
for r in range(int(n**.5)+1, 1, -1):
if not n%r:
d = n//r
return (not factors[d]) and (not factors[r])
return False
Then scan the range up to N numbers to count slope of increasing semi primes. simply measure the slope within a slice to see how many semi primes occur during that slice.
def solution(N, P, Q):
# produce a slope of increasing semi primes
factors = get_sieve(N)
slope = [0] * (N+1)
for i in range(1, N+1):
slope[i] = slope[i-1] + is_semi_prime(i, factors) # Auto casting!! :-)
# Optimus Prime!
# print(list(enumerate(slope)))
return [slope[Q[j]] - slope[P[j]-1] for j in range(len(P))]
https://github.com/niall-oc/things/blob/master/codility/count_semiprimes.py
and more at
https://github.com/niall-oc/things/blob/master/codility/
I took a slightly different approach. The other efficient solutions in this thread builds a regular Sieve of Eratosthenes (F) with a twist of recording the smallest prime factor in the slot, so semiprimes are those x for which F[x] > 0 and F[x // F[x]] == 0, i.e. dividing by the smallest prime factor yields another prime number.
My approach is a little slower but does not use division, and builds an interesting intermediate: a sieve that computes exactly how many factors make up the prime factorization of the number (and zeros at the primes). For each prime p, I would increment the sieve at position 2p, 3p, 4p,... but also count a factor for p^2, 2p^2, 3p^2..., p^3, 2p^3, 3p^3, 4p^3,... and so forth. The slot for 16 stores the value 4 (prime factorization: 2*2*2*2), because the slot gets hit by visits from 2, 2^2, 2^3 and 2^4.
Then the semiprimes are those positions having exactly 2 prime factors.
After that I build a prefix count of semiprimes with which to answer the queries in constant time.
def solution(N, P, Q):
num_factors = [0] * (N+1)
for i in range(2, N+1):
if num_factors[i] == 0:
# Count visits to multiples of i by adding i each time
add_visit = i+i
while add_visit < N+1:
num_factors[add_visit] += 1
add_visit += i
# But squares of prime count as 2 factors, cubes count as 3 etc,
# so also run visits for multiples of the squares, cubes, etc.
power_prime = i*i
while power_prime < N+1:
visit = power_prime
while visit < N+1:
num_factors[visit] += 1
visit += power_prime
power_prime *= i
semiprime_prefix_count = [0] * (N+1)
for i in range(1, N+1):
semiprime_prefix_count[i] = semiprime_prefix_count[i-1]
if num_factors[i] == 2:
semiprime_prefix_count[i] += 1
results = []
for p, q in zip(P, Q):
results.append(semiprime_prefix_count[q] - semiprime_prefix_count[p-1])
#print(list(zip(range(N+1),num_factors)))
#print(list(zip(range(N+1),semiprime_prefix_count)))
return results
Use the usual sieve to get the prime numbers up to N.
Use the prime number to get semi-prime numbers up to N. You can do this by checking any number for two prime factors.
Create prefix sums to store the number of semi-primes up to a particular index.
Finally, get the semi prime counts by subtracting the numbers at the query end and start.
vector<int> solution(int N, vector<int> &P, vector<int> &Q)
{
vector<int> sieve(N, 0);
for (int prime = 2; prime * prime <= N; ++prime) {
for (int composite = prime * prime; composite <= N; composite += prime) {
if (!sieve[composite - 1]) sieve[composite - 1] = prime;
}
}
vector<int> semi_primes;
for (int i = 3; i < N; ++i) {
const int e = sieve[i];
if (e > 0 && !sieve[i / e]) semi_primes.push_back(i + 1);
}
if (semi_primes.empty()) semi_primes.push_back(0);
vector<int> prefix_sums(N + 1, 0);
for (int i = 1, spi = 0; i <= N; ++i) {
prefix_sums[i] = ((semi_primes[spi] != i) ? spi : ++spi);
}
int M = P.size();
vector<int> semi_prime_counts(M, 0);
for (int i = 0; i < M; ++i) {
semi_prime_counts[i] = prefix_sums[Q[i]] - prefix_sums[P[i] - 1];
}
return semi_prime_counts;
}
function solution(N, P, Q) {
// write your code in JavaScript (Node.js 8.9.4)
let pr =[];let fn =[]
for(var i=2;i<=N;i++){
if(isPrime(i)){
pr.push(i)
}
}
let spr = [],mul,br=0
for(var i=0;i<pr.length;i++){
for(var j=0; j <pr.length;j++){
mul = pr[i] * pr[j];
if(mul <= N) {
spr.push(mul)
}else{
br =1;
break;
}
}
// if(br==1) break;
}
let nm = [];
//let o =0
for(var i=0;i<=N;i++){
if(spr.indexOf(i) >=0){
// ++o
nm.push(1)
}else{
nm.push(0)
}
}
// spr = Array.from(new Set(spr))
// spr.sort((a,b)=> a- b)
let a,b,c
for(var i =0;i<P.length;i++){
// a= findme(P[i],spr)
// b= findme(Q[i],spr)
// a= nm[P[i]]
// b= nm[Q[i]]
c= nm.slice(P[i],Q[i]+1).reduce((a,b)=> a+b)
// c=c <=0 ? 0 : c+1
// fn.push(b - a + 1)
fn.push(c)
}
return fn
}
function findme(a,arr){
for(var i= 0; i< arr.length;i++){
if(a <= arr[i]) return i;
}
}
function isPrime(num){
if (num ===2) return true
for(var i = 2; i < num; i++)
if(num % i === 0) return false;
return num > 1;
}
/**
* https://app.codility.com/demo/results/trainingPBRVXK-28Q/
* time complexity: O(N * log(log N) + M
* space complexity: O(2N + N)
*/
public class CountSemiPrime {
/**
* 2D array for sieving numbers 1..N
* 1 - prime, 2 - semiprime, 3 - composite
*/
public int[][] sieve(int N) {
int[][] sieve = new int[N+1][1];
for (int i=1; i<=N; i++) {
sieve[i][0] = 1; // make prime default
}
for (int i=2; i<= N; i++) {
if (sieve[i][0] == 1) { // if this num is prime, tag its multiples as semi-prime
int next_number = i + i;
while (next_number <= N) {
sieve[next_number][0] = 2;
next_number += i;
}
}
// if this num is semi-prime, tag its multiples as composite
else if (sieve[i][0] == 2) {
int next_number = i + i;
while (next_number <= N) {
sieve[next_number][0] = 3;
next_number += i;
}
}
}
return sieve;
}
public int[] solution(int N, int[] P, int[] Q) {
// first, we need to establish prime and semi-prime numbers from 1 to N, in a sieve
int[][] sieve = sieve(N);
int[] prefix_sum_of_sieve = new int[sieve.length];
for (int i=1; i<sieve.length; i++) {
if (sieve[i][0]==2) {
prefix_sum_of_sieve[i] = prefix_sum_of_sieve[i-1] + 1;
}
else {
prefix_sum_of_sieve[i] = prefix_sum_of_sieve[i-1];
}
}
int[] results = new int[P.length];
// we count the semiprime of N from P and Q, for each P & Q from the prefix sum
for (int i=0; i < P.length; i++) {
results[i] = prefix_sum_of_sieve[Q[i]] - prefix_sum_of_sieve[P[i]-1];
}
return results;
}
}
Hope the explanation / comments are easy to understand.
Related
I want to calculate the amount of different prime factors of every integer up to n. For example, 12 = 2 * 2 * 3, so it has 2 different prime factors, 2 and 3. I want to store each of these values in an array result[], of size n+1, in which result[i] contains the number of different prime factors of the integer i.
I have to use the following external method in my solution:
List<Integer> getPrimes(int n) {
// create array to determine which numbers are prime
boolean isPrime[] = new boolean[n+1];
for(int i=2; i<=n; i++)
isPrime[i] = true; // assume all are prime, we'll filter below
for(int i=3; i*i<=n; i+=2) {
if (isPrime[i]) { // i is prime, so...
for(int j=i*i; j<=n; j+=i) // remove all its multiples
isPrime[j] = false; // by updating array
}
}
// create list with only the prime numbers
List<Integer> primes = new LinkedList<>();
primes.add(2);
for(int i=3; i<=n; i+=2)
if (isPrime[i])
primes.add(i);
return primes;
}
which uses the Sieve of Eratosthenes to return a List of all prime numbers up to n. This was my solution:
int[] getNumPrimeFactors(int n) {
int[] result = new int[n + 1];
int counter; // counts the number of different prime factors
boolean isPrime = true;
List<Integer> primeList = getPrimes(n);
for (int i = 2; i < result.length; i++) {
counter = 0;
// checks if i is prime
if (i % 2 == 0) {
isPrime = false;
} else {
for (int j = 3; j * j <= i; j += 2) {
if (i % j == 0)
isPrime = false;
}
}
// if i isnt prime, counts how many different prime factors it has
if (!isPrime) {
for (int prime : primeList) {
if (i % prime == 0)
counter++;
}
result[i] = counter;
} else {
result[i] = 1;
}
}
return result;
}
This algorithm produces the correct results, however, I want to be able to test for n <= 5_000_000, and it isn't efficient enough. Is there any way I can improve the code for very large instances of n? Here are some example test results:
Thank you very much for your help :)
This is definitely not the most effective algorithm, but on my old computer (i5 3570K) it works up to 5_000_000 slightly more than 10 seconds. Sum of result array for 5_000_000 is 14838426.
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class Main {
public static List<Integer> primeFactors(int number) {
int n = number;
List<Integer> factors = new ArrayList<Integer>();
for (int i = 2; i <= n / i; i++) {
while (n % i == 0) {
factors.add(i);
n /= i;
}
}
if (n > 1) {
factors.add(n);
}
return factors;
}
public static void main(String[] args) {
int[] result = new int[5_000_001];
for (int i = 0; i < result.length; i++) {
result[i] = (int) primeFactors(i).stream().distinct().count();
}
System.out.println(Arrays.stream(result).sum());
}
}
One standard "improvement" I often find useful on sieving in this way is set up least prime factors for all the values (instead of just a "true/false" value). Then the "is it prime" decision is a check on whether the least prime factor lpf is less than the value. This is basically nearly as quick as the prime sieve but then gives a more direct route to factorizing numbers in range.
In Python:
lim = 5000000+1
# precalc all least prime factors for composites in range
lpf = [i for i in range(lim)]
for m in range(4,lim,2):
lpf[m] = 2
k = 3
while k*k <= lim:
if lpf[k] == k:
for m in range(k*k, lim, 2*k):
if lpf[m] == m:
lpf[m] = k
k += 2
print('lpf done',lim) ############
# find number of distinct prime factors for each
result = [0]*lim
for a in range(2,lim):
pf = lpf[a]
fc = 1
res = a
while pf < res:
res //= pf
if pf != lpf[res]:
fc += 1
pf = lpf[res]
result[a] = fc
print(result[:11])
print(sum(result[:10+1]))
print(sum(result[:1234+1]))
print(sum(result[:1000000+1]))
The sieve here takes just over two seconds, which is about a quarter of the total time.
There is a natural number n. You have to find a pair of natural numbers x, y whose sum is n and also have the least energy among other pair having the sum n.
Energy(x) = sum of all digits of x
Total Energy = Energy(x) + Energy(y)
1 <= n <= 10^9
For eg,
n = 10000
A few pairs:
5000 + 5000 -> Energy = 10
1000 + 9000 -> Energy = 10
9999 + 1 -> Energy = 37
2999 + 7001 -> Energy = 37
So possible answers are:
(5000, 5000), (1000, 9000) etc
I have tried the solution noted above so far but it is not an optimized approach
I will loop from 1 to n-1 and and try all pairs and check their sum of digits but it will take too much time for big numbers.
e.g.
n= 50
1,49--> energy 14
2,48--> energy 14
3,47--> energy 14
4,46--> energy 14
5,45--> energy 14
.
.
.
.
10,40-->energy 5
(Edited) After some thought, I arrived at the following solution. Would appreciate if somebody can come up with a better solution
public int sum(int n) {
String s = String.valueOf(n);
if (isNonZeroOnlyOne(n)) {
int num = getNonZeroNo(n);
if (num == 1)
return 10;
return num;
}
return calculateEnergy(s);
}
private int calculateEnergy(String s) {
int sum = 0;
for(int i=0; i<s.length(); i++)
sum += s.charAt(i) - '0';
return sum;
}
private int getNonZeroNo(int n) {
String s = String.valueOf(n);
for(int i=0; i<s.length(); i++) {
char c = s.charAt(i);
if (c != '0')
return c-'0';
}
return '0';
}
private boolean isNonZeroOnlyOne(int n) {
String s = String.valueOf(n);
int count = 0;
for(int i=0; i<s.length(); i++) {
char c = s.charAt(i);
if (c != '0')
count++;
if (count > 1)
return false;
}
return true;
}
It's simple.
if n is of type 10^x then the answer is 10. otherwise answer is the sum of digits of n.
The idea here is to break down the number into a pair containing digits less than that are present in n. if you break down into smaller digits then sum remains the same as the original number.
example for 7= 1-6,2-5,3-4.
for a number like 100, 1000....
digit 1 can't be broken down into further pairs, so we try to make 10 as the sum of digit so that the sum becomes n.
like for 10=5-5,2-8,3-7
100=20-80,40-60
for other numbers, like 123
it can be broken into 100-23, 120-3, 111-12... all will give you sum 6. which is the sum of digits of the original number.
if you try to break down into further pairs like 80-43, 52-71, you will see that the digit sum increases as you broken down to a number containing digits which is higher than those are present in n. like 8 4,5,7 are greater than 3.
The least energy can be derived by a simple formula.
1) Given N > 100, the pair can be N-100 and 100 , and the energy will be same as the energy of N.
eg : N = 500 ; Pair = 400 and 100 ; Energy = 5
2) N >=10 and N <=100 , pair = N-10 and 10
eg : N = 50 ; Pair = 40 and 10 ; Energy = 5
3) N >=2 and N <=10 , pair = N-1 and 1
eg : N = 5 ; Pair = 4 and 1 ; Energy = 5
I spent more than 1 hour on this problem. What should be answer for n = 1? So I think n should be greater than 1. I am assuming n > 1.
So brute-force solution won't work here because n is huge enough. So you need more optimized solution. You need to think think about how many times you have to carry 1 in the sum to make n. It is at most 9 times!
If you have some basic idea with digit-dp(Dynamic Programming) then this problem is easy. Try to place all possible digit on a place of n and take minimum energy among them. This problem is easy when you fully understand digit-dp technique. You can learn it from here and here.
For practice, you can find a lot of problems here (Dynamic programming section).
For your references, I wrote this code just now and it is working properly. Hope you can use this as a reference.
#include <bits/stdc++.h>
using namespace std;
const string INF_STRING = "9999999";
const int INF_INT = 9999999;
pair<string, int> INF = make_pair(INF_STRING, INF_INT);
int nod;
int digits[10];
int num_of_digits(int a) {
int cnt = 0;
while(a) {
digits[cnt] = a % 10;
a = a / 10;
cnt++;
}
return cnt;
}
pair<string, int> dp[10][2][2][2];
pair<string, int> solve(int ind, int carry, bool is1, bool is2) {
if(ind >= nod) {
if(carry != 0 || !is1 || !is2) return INF;
return make_pair("", 0);
}
pair<string, int> &ret = dp[ind][carry][is1][is2];
if(ret.second != -1) return ret;
ret = INF;
for(int i = 0; i < 10; i++) {
for(int j = 0; j < 10; j++) {
int s = (i + j + carry);
pair<string, int> cur = INF;
if(s % 10 == digits[ind]) {
cur = solve(ind + 1, s / 10, is1 || (i > 0? 1:0), is2 || (j > 0? 1:0));
}
if((cur.second + i + j) < ret.second) {
ret.second = cur.second + i + j;
ret.first = cur.first + (char)(i + '0');
}
}
}
return ret;
}
int stringToInt(string num) {
stringstream ss;
ss<<num;
int ret;
ss >> ret;
return ret;
}
int main() {
int i, t, cases = 1, j, k, pos;
int n;
scanf("%d", &n);
nod = num_of_digits(n);
for(int i = 0; i < 10; i++) {
for(int j = 0; j < 2; j++) {
dp[i][j][0][0] = make_pair(INF_STRING, -1);
dp[i][j][0][1] = make_pair(INF_STRING, -1);
dp[i][j][1][0] = make_pair(INF_STRING, -1);
dp[i][j][1][1] = make_pair(INF_STRING, -1);
}
}
pair<string, int> res = solve(0, 0, 0, 0);
string num1_str = res.first;
int num1 = stringToInt(num1_str);
int num2 = n - num1;
printf("Minimum Energy: %d\n", res.second);
printf("Num1 = %d, Num2 = %d\n", num1, num2);
return 0;
}
/*
Input:
10000
Output:
Minimum energy: 10
Num1 = 1000, Num2 = 9000
*/
Here is the answer in javascript in simple way.
function calculateEnergy(n) {
let e = 0
while(n > 0) {
e += n % 10
n = Math.floor(n / 10)
}
return e
}
function countMinEnergy(n) {
let minE = n
let i = 1
while(i <= n/2) {
let e = calculateEnergy(i) + calculateEnergy(n - i)
minE = e < minE ? e : minE
i++
}
return minE
}
countMinEnergy(4325)
Here is scala solution
object LeastEnergyPair extends App {
private def getCountOfPair(array: Array[Int],sum: Int): mutable.Set[(Int, Int)] = {
val seen = mutable.Set[Int]()
val out = mutable.Set[(Int,Int)]()
array map { x =>
val target = sum - x
if (seen.contains(target) || target*2 == sum)
out += ((Math.min(x,target),Math.max(x,target)))
else
seen += x
}
println(out)
out
}
private def sum(i:Int): Int = i.toString.toCharArray.map(_.asDigit).sum
def findLeastEnergyPair(a: mutable.Set[(Int,Int)]): (Int,Int) = {
var min = Int.MaxValue
var minPair = (0,0)
a.foreach {
case (i,j) =>
if (sum(i) + sum(j) < min) {
min = sum(i) + sum(j)
minPair = (i,j)
println(s"$min ----- $minPair")
}
}
minPair
}
println(findLeastEnergyPair(getCountOfPair((1 to 10000).toArray, 10000)))
}
The below logic will cover all scenarios
if (N%10 == 0) {
x1= (N/10);
x2 = N-x1
}else{
x1 = N-10;
x2 = 10;
}
I need to count all the divisors for every number in the range 1 to n. I have written down below an implementation for, given an integer num, it counts the number of divisors of num. Its complexity is O(sqrt(n)). So over all complexity comes out to be O(n * sqrt(n)). Can it be reduced? If YES, then can you give an algorithm for that?
CODE :
public static int countDivisors(int num)
{
int limit = (int)Math.sqrt(num);
int count = 2;
for(int i = 2 ; i <= limit ; i++)
{
if(num % i == 0)
{
count++;
if(num / i != i)
{
count++;
}
}
}
return count;
}
PS:
This function will be called n times.
You can improve upon the naive approach using kind of a generalized Sieve of Eratosthenes. Instead of just marking the number as composite also store its first divisor that you found (I do this in the function computeDivs below).
class Main
{
// using Sieve of Eratosthenes to factorize all numbers
public static int[] computeDivs(int size) {
int[] divs = new int[size + 1];
for (int i = 0; i < size + 1; ++i) {
divs[i] = 1;
}
int o = (int)Math.sqrt((double)size);
for (int i = 2; i <= size; i += 2) {
divs[i] = 2;
}
for (int i = 3; i <= size; i += 2) {
if (divs[i] != 1) {
continue;
}
divs[i] = i;
if (i <= o) {
for (int j = i * i; j < size; j += 2 * i) {
divs[j] = i;
}
}
}
return divs;
}
// Counting the divisors using the standard fomula
public static int countDivisors(int x, int[] divs) {
int result = 1;
int currentDivisor = divs[x];
int currentCount = 1;
while (currentDivisor != 1) {
x /= currentDivisor;
int newDivisor = divs[x];
if (newDivisor != currentDivisor) {
result *= currentCount + 1;
currentDivisor = newDivisor;
currentCount = 1;
} else {
currentCount++;
}
}
if (x != 1) {
result *= currentCount + 1;
}
return result;
}
public static int countAllDivisors(int upTo) {
int[] divs = computeDivs(upTo + 1);
int result = 0;
for (int i = 1; i <= upTo; ++i) {
result += countDivisors(i, divs);
}
return result;
}
public static void main (String[] args) throws java.lang.Exception {
System.out.println(countAllDivisors(15));
}
}
You can also see the code executed on ideone here.
In short I use the sieve to compute the biggest prime factor for each number. Using this I can compute the factor decomposition of every number very efficiently (and I use this in countDivisors).
It is hard to compute the complexity of the sieve but a standard estimate is O(n * log(n)). Also I am pretty confident it is not possible to improve on that complexity.
You can do much better than O(n.sqrt(n)) by using simple iteration. The code is in C++, but you can easily get the idea.
#include <iostream>
#include <vector>
using namespace std;
void CountDivisors(int n) {
vector<int> cnts(n + 1, 1);
for (int i = 2; i <= n; ++i) {
for (int j = i; j <= n; j += i) {
cnts[j]++;
}
}
for (int i = 1; i <= n; ++i) {
cout << cnts[i] << " \n"[i == n];
}
}
int main() {
CountDivisors(100);
return 0;
}
Running time is n/1 + n/2 + n/3 + n/4 + ... + n/n which can be approximated by O(nH(n)), where H(n) is the harmonic series. I think the value is not bigger than O(nlog(n)).
Using iteration is OK for relatively small numbers. As soon as the number of divisors is getting bigger (over 100-200), the iteration is going to take a significant amount of time.
A better approach would be to count the number of divisors with help of prime factorization of the number.
So, express the number with prime factorization like this:
public static List<Integer> primeFactorizationOfTheNumber(long number) {
List<Integer> primes = new ArrayList<>();
var remainder = number;
var prime = 2;
while (remainder != 1) {
if (remainder % prime == 0) {
primes.add(prime);
remainder = remainder / prime;
} else {
prime++;
}
}
return primes;
}
Next, given the prime factorization, express it in the exponent form, get exponents and add 1 to each of them. Next, multiply resulting numbers. The result will be the count of divisors of a number. More on this here.
private long numberOfDivisorsForNumber(long number) {
var exponentsOfPrimeFactorization = primeFactorizationOfTheNumber(number)
.stream()
.collect(Collectors.groupingBy(Integer::intValue, Collectors.counting()))
.values();
return exponentsOfPrimeFactorization.stream().map(n -> n + 1).reduce(1L, Math::multiplyExact);
}
This algorithm works very fast. For me, it finds a number with 500 divisors within less than a second.
I am trying to write a DP solution for the problem: count total number of sub-sequences possible of an array whose elements' sum is divisible by k.
I have written the following solution. But it is not giving the correct result. Like in the following code snippet, the array is {1, 2, 1} and k = 3. So expected total number of sub sequences divisible by 3 is 2, but the actual result is 3 which is clearly incorrect.
Please point out my mistake.
private int countDP(int[] a, int k)
{
int L = a.length;
int[][] DP = new int[L][k];
for(int i = 0; i < DP.length; i++)
{
for(int j = 0; j < DP[0].length; j++)
DP[i][j] = -1;
}
int res = _countDP(a, k, DP, 0, 0);
return res;
}
private int _countDP(int[] a, int k, int[][] DP, int idx, int m) //Not giving the correct result.
{
if(idx == a.length)
return m == 0 ? 1 : 0;
if(DP[idx][m] != -1)
return DP[idx][m];
int ans = 0;
ans = _countDP(a, k, DP, idx + 1, m);
ans += _countDP(a, k, DP, idx + 1, (m + a[idx]) % k);
return DP[idx][m] = ans;
}
public static void main(String[] args)
{
CountSubnsequences cs = new CountSubnsequences();
int[] a = {1, 2, 1};
int k = 3;
int total1 = cs.countDP(a, k);
System.out.println("Total numeber of sub sequences: " + total1);
}
Let s denote a sequence of length N, and K be a given divisor.
dp[i][j] = the number of subsequences of s[0..i] with remainder equal to j. We will compute dp for all 0 <= i < N and 0 <= j < K.
dp[i][j] = 0 for all (i, j)
dp[0][0] += 1
dp[0][s[0] mod K] += 1
for i = 1 .. N - 1
for j = 0 .. K - 1
dp[i][j] = dp[i - 1][j]
for j = 0 .. K - 1
dp[i][(j + s[i]) mod K] += dp[i - 1][j]
The result is dp[N - 1][0]
Python code of #piotrekg2 solution.
Looks good!
from typing import List
# dp[i][j] = the number of subsequences of length i with remainder equal to j.
def count_subseq(s: List[int],k):
n = len(s)
dp = [0]*k
dp[0] = 1 # i=0, remainder=0, only 1 subseq
for i in range(1,n+1):
dp2 = dp.copy() # copy previous i-length results: results without s[i] in subseq
for j in range(k):
dp2[(j+s[i-1])%k] += dp[j]
dp = dp2
return dp[0]
if __name__ == '__main__':
print(count_subseq([2,3,5,8],5))
print(count_subseq([5,5,5],5))
Faced the same issue. But ended up getting an answer.
The answer returning will be always 1 more than the total possible subsequences. This is because we know that 0 is always being a valid answer. So, if let's say you do not pick any single element from the array, then also the sum=0. So, it considers it as a valid answer and increments our answer by 1. So, to get the actual answer Just decrement the returned value by 1.
int fun(int i,int s)
{
if(i==1){
if(s-a[i]!=0 && (s-a[i])%k==0)
return 1;
else
return 0;}
else{
if((s-a[i])%k==0){
return 1+fun(i-1,s-a[i])+fun(i-1,s);
}
else{
return fun(i-1,s-a[i])+fun(i-1,s);
}
}
}
Recently, I tried to solve the Max Double Slice Sum problem in codility which is a variant of max slice problem. My Solution was to look for a slice that has maximum value when its minimum value is taken out. So I implemented max slice, but on the current slice took out the minimum number.
My score was 61 of 100 as it failed during some of the tests, mainly the tests on array including both negative and position numbers.
Could you help me to figure out why the code failed or if there is a better solution for the problem?
The problem is as follows:
A non-empty zero-indexed array A consisting of N integers is given.
A triplet (X, Y, Z), such that 0 ≤ X < Y < Z < N, is called a double slice.
The sum of double slice (X, Y, Z) is the total of A[X + 1] + A[X + 2] + ... + A[Y − 1]+ A[Y + 1] + A[Y + 2] + ... + A[Z − 1].
For example, array A such that:
A[0] = 3
A[1] = 2
A[2] = 6
A[3] = -1
A[4] = 4
A[5] = 5
A[6] = -1
A[7] = 2
contains the following example double slices:
double slice (0, 3, 6), sum is 2 + 6 + 4 + 5 = 17,
double slice (0, 3, 7), sum is 2 + 6 + 4 + 5 − 1 = 16,
double slice (3, 4, 5), sum is 0.
The goal is to find the maximal sum of any double slice.
Write a function:
class Solution { public int solution(int[] A); }
that, given a non-empty zero-indexed array A consisting of N integers, returns the maximal sum of any double slice.
For example, given:
A[0] = 3
A[1] = 2
A[2] = 6
A[3] = -1
A[4] = 4
A[5] = 5
A[6] = -1
A[7] = 2
the function should return 17, because no double slice of array A has a sum of greater than 17.
Assume that:
N is an integer within the range [3..100,000];
each element of array A is an integer within the range [−10,000..10,000].
Complexity:
expected worst-case time complexity is O(N);
expected worst-case space complexity is O(N), beyond input storage (not counting the storage required for input arguments).
Elements of input arrays can be modified.
Copyright 2009–2013 by Codility Limited. All Rights Reserved. Unauthorized copying, publication or disclosure prohibited.
And my code is as follows:
public class Solution {
public int solution(int[] A) {
int currentSliceTotal=0;
Integer currentMin=null, SliceTotalBeforeMin =0;
int maxSliceTotal= Integer.MIN_VALUE;
for(int i= 1; i<A.length-1; i++){
if( currentMin==null || A[i] < currentMin ){
if(currentMin!=null ){
if(SliceTotalBeforeMin+currentMin <0){
currentSliceTotal-=SliceTotalBeforeMin;
} else {
currentSliceTotal += currentMin;
}
}
currentMin = A[i];
SliceTotalBeforeMin =currentSliceTotal;
if( SliceTotalBeforeMin<0){
SliceTotalBeforeMin = 0;
currentMin = null;
currentSliceTotal = 0;
}
} else {
currentSliceTotal+= A[i];
}
maxSliceTotal = Math.max(maxSliceTotal, currentSliceTotal);
}
return maxSliceTotal;
}
}
If I have understood the problem correctly, you want to calculate the maximum sum subarray with one element missing.
Your algorithm shall not work for the following case:
1 1 0 10 -100 10 0
In the above case, your algorithm shall identify 1, 1, 0, 10 as the maximum sum sub array and leave out 0 to give 12 as the output. However, you can have 1, 1, 0, 10, -100, 10 as the answer after leaving out -100.
You can use a modified form of Kadane's algorithm that calculates the MAX Sum subarray ending at each index.
For each index, calculate the max_sum_ending_at[i] value by using Kadane's algorithm in forward direction.
For each index, calculate the max_sum_starting_from[i] value by using Kadane's algorithm in reverse direction.
Iterate these arrays simultaneously and choose the 'Y' that has the maximum value of
max_sum_ending_at[Y-1] + max_sum_starting_from[Y+1]
Hello this implementacion has 100 score
int i,n ;
n = A.size();
if (3==n) return 0;
vector<int> max_sum_end(n,0);
vector<int> max_sum_start(n,0);
for (i=1; i< (n-1); i++) // i=0 and i=n-1 are not used because x=0,z=n-1
{
max_sum_end[i] = max ( 0 , max_sum_end[i-1] + A[i] );
}
for (i=n-2; i > 0; i--) // i=0 and i=n-1 are not used because x=0,z=n-1
{
max_sum_start[i] = max ( 0 , max_sum_start[i+1] + A[i] );
}
int maxvalue,temp;
maxvalue = 0;
for (i=1; i< (n-1); i++)
{
temp = max_sum_end[i-1] + max_sum_start[i+1];
if ( temp > maxvalue) maxvalue=temp;
}
return maxvalue ;
This is a Java 100/100 Solution:
https://codility.com/demo/results/demoVUMMR9-JH3/
class Solution {
public int solution(int[] A) {
int[] maxStartingHere = new int[A.length];
int[] maxEndingHere = new int[A.length];
int maxSum = 0, len = A.length;
for(int i = len - 2; i > 0; --i ) {
maxSum = Math.max(0, A[i] + maxSum);
maxStartingHere[i] = maxSum;
}
maxSum = 0;
for(int i = 1; i < len - 1; ++i ) {
maxSum = Math.max(0, A[i] + maxSum);
maxEndingHere[i] = maxSum;
}
int maxDoubleSlice = 0;
for(int i = 0; i < len - 2; ++i) {
maxDoubleSlice = Math.max(maxDoubleSlice, maxEndingHere[i] + maxStartingHere[i+2]);
}
return maxDoubleSlice;
}
}
You can find more information going to this Wikipedia link and in the Programming Pearls book.
Here is my solution
https://github.com/dinkar1708/coding_interview/blob/master/codility/max_slice_problem_max_double_slice_sum.py
Codility 100% in Python
def solution(A):
"""
Idea is use two temporary array and store sum using Kadane’s algorithm
ending_here_sum[i] - the maximum sum contiguous sub sequence ending at index i
starting_here_sum[i] - the maximum sum contiguous sub sequence starting with index i
Double slice sum should be the maximum sum of ending_here_sum[i-1]+starting_here_sum[i+1]
Reference -
https://rafal.io/posts/codility-max-double-slice-sum.html
The sum of double slice (X, Y, Z) is the total of A[X + 1] + A[X + 2] + ... + A[Y - 1] + A[Y + 1] + A[Y + 2] + ... + A[Z - 1].
A[0] = 3
A[1] = 2
A[2] = 6
A[3] = -1
A[4] = 4
A[5] = 5
A[6] = -1
A[7] = 2
contains the following example double slices:
double slice (0, 3, 6), sum is 2 + 6 + 4 + 5 = 17,
double slice (0, 3, 7), sum is 2 + 6 + 4 + 5 - 1 = 16,
double slice (3, 4, 5), sum is 0.
"""
ar_len = len(A)
ending_here_sum = [0] * ar_len
starting_here_sum = [0] * ar_len
# the maximum sum contiguous sub sequence ending at index i
for index in range(1, ar_len - 2): # A[X + 1] + A[X + 2] + ... + A[Y - 1]
ending_here_sum[index] = max(ending_here_sum[index - 1] + A[index], 0)
# the maximum sum contiguous sub sequence starting with index i
for index in range(ar_len - 2, 1, -1): # A[Y + 1] + A[Y + 2] + ... + A[Z - 1]
starting_here_sum[index] = max(starting_here_sum[index + 1] + A[index], 0)
# Double slice sum should be the maximum sum of ending_here_sum[i-1]+starting_here_sum[i+1]
max_slice_sum = ending_here_sum[0] + starting_here_sum[2]
for index in range(1, ar_len - 1):
max_slice_sum = max(max_slice_sum, ending_here_sum[index - 1] + starting_here_sum[index + 1])
return max_slice_sum
C# solution 100/100
public int solution(int[] A) {
int[] forw = new int[A.Length];
int[] rewi = new int[A.Length];
bool isAllNeg = true;
for (int i = 1; i < A.Length; i++)
{
forw[i] = Math.Max(0, forw[i - 1] + A[i]);
if (A[i] > 0 && isAllNeg) isAllNeg = false;
}
if (isAllNeg)
return 0;
for (int i = A.Length - 2; i >= 0; i--)
{
rewi[i] = Math.Max(0, rewi[i + 1] + A[i]);
}
int maxsum = 0;
for (int i = 1; i < A.Length - 1; i++)
{
maxsum = Math.Max(maxsum, forw[i - 1] + rewi[i + 1]);
}
return maxsum;
}
Without using extra memory, 100/100 C++:
#include <algorithm>
int solution(vector<int> &A) {
int max_slice = 0;
int max_slice_i = 0;
int min_val = 0;
int mss = 0;
int mse = 0;
int s = 1;
int msmv = 0;
int max_slice_i_orig = 0;
int os = 1;
for(size_t i = 1;i < A.size() - 1;i++)
{
int v = max_slice_i;
if(max_slice_i > 0 && A[i] < 0)
{
if(A[i] < min_val)
{
v = max_slice_i_orig;
s = os;
min_val = std::max(A[i], -max_slice_i_orig);
} else
{
v = max_slice_i + A[i];
}
} else
{
v = max_slice_i + A[i];
}
int new_orig_v = max_slice_i_orig + A[i];
if(new_orig_v < 0)
{
max_slice_i_orig = 0;
os = i + 1;
} else
{
max_slice_i_orig = new_orig_v;
}
if(v > 0)
{
max_slice_i = v;
} else {
max_slice_i = 0;
min_val = 0;
s = i + 1;
}
if(max_slice_i > max_slice)
{
mss = s;
mse = i;
msmv = min_val;
max_slice = max_slice_i;
}
}
// if all are positive
if(msmv == 0)
{
if(mss == 1 && mse == A.size() - 2)
{
int min = 10001;
for(int j = mss;j <= mse;j++)
{
if(A[j] < min)
min = A[j];
}
max_slice -= min;
}
}
return max_slice;
}
Javascript implementation based on Abhishek Bansal's solution.100/100 on Codility.
function solution(A) {
let maxsum=0;
let max_end_at=Array(A.length);
let max_start_at=Array(A.length);
max_end_at[0]=max_start_at[A.length-1]=max_end_at[A.length-1]=max_start_at[0]=0;
let {max}=Math;
for(let i=1;i<A.length-1;i++){
max_end_at[i]=max(0,max_end_at[i-1]+A[i]);
}
for(let n=A.length-2;n>0;n--){
max_start_at[n]=max(0,max_start_at[n+1]+A[n]);
}
for(let m=1;m<A.length-1;m++){
maxsum=max(maxsum,max_end_at[m-1]+max_start_at[m+1]);
}
return maxsum;
}
The most clear Python solution among others:
def solution(A):
mid = 1
total = 0
max_slice = 0
for idx, end in enumerate(A[2:-1], start=2):
if total < 0:
mid = idx
total = 0
elif total == 0 and A[idx - 1] > A[mid]:
mid = idx - 1
total = end
else:
if A[mid] > end:
total += A[mid]
mid = idx
else:
total += end
max_slice = max(max_slice, total)
return max_slice
Using the idea from http://en.wikipedia.org/wiki/Maximum_subarray_problem
and Abhishek Bansal's answer above. 100% test pass:
public class Solution {
public int solution(int[] A) {
int[] maxEndingHere = maxEndingHere(A);
int[] maxStartingHere = maxStartingHere(A);
int maxSlice = 0;
for (int i = 1; i < A.length-1;i++) {
maxSlice = Math.max(maxSlice, maxEndingHere[i-1]+maxStartingHere[i+1]);
}
return maxSlice;
}
/**
* Precalculate ending subarrays. Take into account that first and last element are always 0
* #param input
* #return
*/
public static int[] maxEndingHere(int[] input) {
int[] result = new int[input.length];
result[0] = result[input.length-1] = 0;
for (int i = 1; i < input.length-1; i++) {
result[i] = Math.max(0, result[i-1] + input[i]);
}
return result;
}
/**
* Precalculate starting subarrays. Take into account that first and last element are always 0
* #param input
* #return
*/
public static int[] maxStartingHere(int[] input) {
int[] result = new int[input.length];
result[0] = result[input.length-1] = 0;
for (int i = input.length-2; i >= 1; i--) {
result[i] = Math.max(0, result[i+1] + input[i]);
}
return result;
}
}
Vb.net version of the above solution is as below:
Private Function solution(A As Integer()) As Integer
' write your code in VB.NET 4.0
Dim Slice1() As Integer = Ending(A)
Dim slice2() As Integer = Starting(A)
Dim maxSUM As Integer = 0
For i As Integer = 1 To A.Length - 2
maxSUM = Math.Max(maxSUM, Slice1(i - 1) + slice2(i + 1))
Next
Return maxSUM
End Function
Public Shared Function Ending(input() As Integer) As Integer()
Dim result As Integer() = New Integer(input.Length - 1) {}
result(0) = InlineAssignHelper(result(input.Length - 1), 0)
For i As Integer = 1 To input.Length - 2
result(i) = Math.Max(0, result(i - 1) + input(i))
Next
Return result
End Function
Public Shared Function Starting(input() As Integer) As Integer()
Dim result As Integer() = New Integer(input.Length - 1) {}
result(0) = InlineAssignHelper(result(input.Length - 1), 0)
For i As Integer = input.Length - 2 To 1 Step -1
result(i) = Math.Max(0, result(i + 1) + input(i))
Next
Return result
End Function
Private Shared Function InlineAssignHelper(Of T)(ByRef target As T, value As T) As T
target = value
Return value
End Function
View result on codility
Here is an alternative solution to the proposed by me before, more readable and understandable:
int solution(vector<int> & A){
if(A.size() < 4 )
return 0;
int maxSum = 0;
int sumLeft = 0;
unordered_map<int, int> leftSums;
leftSums[0] = 0;
for(int i = 2; i < A.size()-1; i++){
sumLeft += A[i-1];
if(sumLeft < 0)
sumLeft = 0;
leftSums[i-1] = sumLeft;
}
int sumRight = 0;
unordered_map<int, int> rightSums;
rightSums[A.size()-1] = sumRight;
for( int i = A.size() - 3; i >= 1; i--){
sumRight += A[i+1];
if(sumRight < 0)
sumRight = 0;
rightSums[i+1] = sumRight;
}
for(long i = 1; i < A.size() - 1; i++){
if(leftSums[i-1] + rightSums[i+1] > maxSum)
maxSum = leftSums[i-1] + rightSums[i+1];
}
return maxSum;
}
Well, I have my solution, may be not the best one bit 100%/100%, according to codility requierments.
#include<vector>
#include<unordered_map>
#include<algorithm>
using namespace std;
int solution(vector<int> &A) {
unordered_map<size_t, int> maxSliceLeftToRight;
maxSliceLeftToRight[1] = 0;
unordered_map<size_t, int> maxSliceRightToLeft;
maxSliceRightToLeft[A.size() - 2] = 0;
int sum = 0;
for (size_t i = 2; i < A.size() - 1; i++) {
int tmpSum = max(sum + A[i - 1], 0);
sum = max(A[i - 1], tmpSum);
maxSliceLeftToRight[i] = sum;
}
sum = 0;
for (size_t i = A.size() - 3; i > 0; i--) {
int tmpSum = max(sum + A[i + 1], 0);
sum = max(A[i + 1], tmpSum);
maxSliceRightToLeft[i] = sum;
}
int maxDoubleSliceSum = 0;
for (auto & entry : maxSliceLeftToRight) {
int maxRight = maxSliceRightToLeft[entry.first];
if (entry.second + maxRight > maxDoubleSliceSum)
maxDoubleSliceSum = entry.second + maxRight;
}
return maxDoubleSliceSum;
}
Here 100% in python,
might not be as elegant as some other solutions above, but considers all possible cases.
def solution(A):
#Trivial cases
if len(A)<=3:
return 0
idx_min=A.index(min(A[1:len(A)-1]))
minval=A[idx_min]
maxval=max(A[1:len(A)-1])
if maxval<0:
return 0
if minval==maxval:
return minval*(len(A)-3)
#Regular max slice if all numbers > 0
if minval>=0:
max_ending=0
max_slice=0
for r in range(1,len(A)-1):
if (r!=idx_min):
max_ending=max(0,A[r]+max_ending)
max_slice = max(max_slice, max_ending)
return max_slice
#Else gets more complicated
else :
#First remove negative numbers at the beginning and at the end
idx_neg=1
while A[idx_neg] <= 0 and idx_neg<len(A) :
A[idx_neg]=0
idx_neg+=1
idx_neg=len(A)-2
#<0 , 0
while A[idx_neg] <= 0 and idx_neg > 0 :
A[idx_neg]=0
idx_neg-=1
#Compute partial positive sum from left
#and store it in Left array
Left=[0]*len(A)
max_left=0
for r in range(1,len(A)-1):
max_left=max(0,A[r]+max_left)
Left[r]=max_left
#Compute partial positive sum from right
#and store it in Right array
max_right=0
Right=[0]*len(A)
for r in range(len(A)-2,0,-1):
max_right=max(0,A[r]+max_right)
Right[r]=max_right
#Compute max of Left[r]+Right[r+2].
#The hole in the middle corresponding
#to Y index of double slice (X, Y, Z)
max_slice=0
for r in range(1,len(A)-3):
max_slice=max(max_slice,Left[r]+Right[r+2])
return max_slice
pass
Think I got it based on Moxis Solution. Tried to point out the Intension.
class Solution {
public int solution(int[] A) {
int n = A.length - 1;
// Array with cummulated Sums when the first Subarray ends at Index i
int[] endingAt = new int[A.length];
int helperSum = 0;
// Optimal Subtotal before all possible Values of Y
for(int i = 1; i < n; ++i ) {
helperSum = Math.max(0, A[i] + helperSum);
endingAt[i] = helperSum;
}
// Array with cummulated Sums when the second Subarray starts at Index i
int[] startingAt = new int[A.length];
helperSum = 0;
// Optimal Subtotal behind all possible Values of Y
for(int i = (n - 1); i > 0; --i ) {
helperSum = Math.max(0, A[i] + helperSum);
startingAt[i] = helperSum;
}
//Searching optimal Y
int sum = 0;
for(int i = 0; i < (n - 1); ++i) {
sum = Math.max(sum, endingAt[i] + startingAt[i+2]);
}
return sum;
}
}
Here is the Python version of the proposed solution with complexity O(N) and %100 correctness and performance.
#Find the maximal sum of any double slice.
#https://app.codility.com/programmers/lessons/9-
#maximum_slice_problem/max_double_slice_sum/
import sys
def solution(A):
n=len(A)
max_sum_endingat=[0]*n
max_sum_startat=[0]*n
if(n<=3):
return 0
else:
for i in range(1,n-1):
max_sum_endingat[i] =max(0,max_sum_endingat[i-1] + A[i])
for i in range(n-2,0,-1):
max_sum_startat[i] =max(0,max_sum_startat[i+1] + A[i])
max_double=-sys.maxsize
for k in range(1,n-1):
max_double=max(max_double,max_sum_endingat[k-1]+max_sum_startat[k+1])
return max_double
This is my solution. It got 92%. Its a modified version of the original concept except I'm keep track of a minimal value to use as the position Y, and I'm shifting the sum of the entire interval accordingly.
Note: If anyone has any idea why it's only 92% feel free to let me know
class Solution {
public int solution(int[] A) {
// write your code in Java SE 8
int max = -10001, sum = 0, min=A[1];
for(int i = 1; i < A.length-1; i++){
sum += A[i];
min = Math.min(A[i], min);
max = Math.max(sum-min, max);
if(sum - min < 0){
sum = 0;
min = A[i+1];
}
}
return max;
}
}
Single-loop, no extra memory dynamic programming solution in Python:
def solution(A):
max_gap_sum = 0
gapless_sum, gap_sum = 0, float("-inf")
for v in A[1:-1]:
gapless_sum, gap_sum = max(gapless_sum + v, 0), max(gap_sum + v, gapless_sum)
max_gap_sum = max(max_gap_sum, gap_sum)
return max_gap_sum
Java solution, 100/100
class Solution {
public int solution(int[] A) {
// write your code in Java SE 8
int maxEnd = 0, maxSlice = Integer.MIN_VALUE;
for(int val : A) {
maxEnd = Math.max(val, maxEnd + val);
maxSlice = Math.max(maxSlice, maxEnd);
}
return maxSlice;
}
}