Trying to solve this problem with recursion and memoization but for input 7168 I'm getting wrong answer.
public int numSquares(int n) {
Map<Integer, Integer> memo = new HashMap();
List<Integer> list = fillSquares(n, memo);
if (list == null)
return 1;
return helper(list.size()-1, list, n, memo);
}
private int helper(int index, List<Integer> list, int left, Map<Integer, Integer> memo) {
if (left == 0)
return 0;
if (left < 0 || index < 0)
return Integer.MAX_VALUE-1;
if (memo.containsKey(left)) {
return memo.get(left);
}
int d1 = 1+helper(index, list, left-list.get(index), memo);
int d2 = 1+helper(index-1, list, left-list.get(index), memo);
int d3 = helper(index-1, list, left, memo);
int d = Math.min(Math.min(d1,d2), d3);
memo.put(left, d);
return d;
}
private List<Integer> fillSquares(int n, Map<Integer, Integer> memo) {
int curr = 1;
List<Integer> list = new ArrayList();
int d = (int)Math.pow(curr, 2);
while (d < n) {
list.add(d);
memo.put(d, 1);
curr++;
d = (int)Math.pow(curr, 2);
}
if (d == n)
return null;
return list;
}
I'm calling like this:
numSquares(7168)
All test cases pass (even complex cases), but this one fails. I suspect something is wrong with my memoization but cannot pinpoint what exactly. Any help will be appreciated.
You have the memoization keyed by the value to be attained, but this does not take into account the value of index, which actually puts restrictions on which powers you can use to attain that value. That means that if (in the extreme case) index is 0, you can only reduce what is left with one square (1²), which rarely is the optimal way to form that number. So in a first instance memo.set() will register a non-optimal number of squares, which later will get updated by other recursive calls which are pending in the recursion tree.
If you add some conditional debugging code, you'll see that map.set is called for the same value of left multiple times, and with differing values. This is not good, because that means the if (memo.has(left)) block will execute for cases where that value is not guaranteed to be optimal (yet).
You could solve this by incorporating the index in your memoization key. This increases the space used for memoization, but it will work. I assume you can work this out.
But according to Lagrange's four square theorem every natural number can be written as the sum of at most four squares, so the returned value should never be 5 or more. You can shortcut the recursion when you get passed that number of terms. This reduces the benefit of using memoization.
Finally, there is a mistake in fillSquares: it should add n itself also when it is a perfect square, otherwise you'll not find solutions that should return 1.
Not sure about your bug, here is a short dynamic programming Solution:
Java
public class Solution {
public static final int numSquares(
final int n
) {
int[] dp = new int[n + 1];
Arrays.fill(dp, Integer.MAX_VALUE);
dp[0] = 0;
for (int i = 1; i <= n; i++) {
int j = 1;
int min = Integer.MAX_VALUE;
while (i - j * j >= 0) {
min = Math.min(min, dp[i - j * j] + 1);
++j;
}
dp[i] = min;
}
return dp[n];
}
}
C++
// Most of headers are already included;
// Can be removed;
#include <iostream>
#include <cstdint>
#include <vector>
#include <algorithm>
// The following block might slightly improve the execution time;
// Can be removed;
static const auto __optimize__ = []() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout.tie(nullptr);
return 0;
}();
#define MAX INT_MAX
using ValueType = std::uint_fast32_t;
struct Solution {
static const int numSquares(
const int n
) {
if (n < 1) {
return 0;
}
static std::vector<ValueType> count_perfect_squares{0};
while (std::size(count_perfect_squares) <= n) {
const ValueType len = std::size(count_perfect_squares);
ValueType count_squares = MAX;
for (ValueType index = 1; index * index <= len; ++index) {
count_squares = std::min(count_squares, 1 + count_perfect_squares[len - index * index]);
}
count_perfect_squares.emplace_back(count_squares);
}
return count_perfect_squares[n];
}
};
int main() {
std::cout << std::to_string(Solution().numSquares(12) == 3) << "\n";
return 0;
}
Python
Here we can simply use lru_cache:
class Solution:
dp = [0]
#functools.lru_cache
def numSquares(self, n):
dp = self.dp
while len(dp) <= n:
dp += min(dp[-i * i] for i in range(1, int(len(dp) ** 0.5 + 1))) + 1,
return dp[n]
Here are LeetCode's official solutions with comments:
Java: DP
class Solution {
public int numSquares(int n) {
int dp[] = new int[n + 1];
Arrays.fill(dp, Integer.MAX_VALUE);
// bottom case
dp[0] = 0;
// pre-calculate the square numbers.
int max_square_index = (int) Math.sqrt(n) + 1;
int square_nums[] = new int[max_square_index];
for (int i = 1; i < max_square_index; ++i) {
square_nums[i] = i * i;
}
for (int i = 1; i <= n; ++i) {
for (int s = 1; s < max_square_index; ++s) {
if (i < square_nums[s])
break;
dp[i] = Math.min(dp[i], dp[i - square_nums[s]] + 1);
}
}
return dp[n];
}
}
Java: Greedy
class Solution {
Set<Integer> square_nums = new HashSet<Integer>();
protected boolean is_divided_by(int n, int count) {
if (count == 1) {
return square_nums.contains(n);
}
for (Integer square : square_nums) {
if (is_divided_by(n - square, count - 1)) {
return true;
}
}
return false;
}
public int numSquares(int n) {
this.square_nums.clear();
for (int i = 1; i * i <= n; ++i) {
this.square_nums.add(i * i);
}
int count = 1;
for (; count <= n; ++count) {
if (is_divided_by(n, count))
return count;
}
return count;
}
}
Java: Breadth First Search
class Solution {
public int numSquares(int n) {
ArrayList<Integer> square_nums = new ArrayList<Integer>();
for (int i = 1; i * i <= n; ++i) {
square_nums.add(i * i);
}
Set<Integer> queue = new HashSet<Integer>();
queue.add(n);
int level = 0;
while (queue.size() > 0) {
level += 1;
Set<Integer> next_queue = new HashSet<Integer>();
for (Integer remainder : queue) {
for (Integer square : square_nums) {
if (remainder.equals(square)) {
return level;
} else if (remainder < square) {
break;
} else {
next_queue.add(remainder - square);
}
}
}
queue = next_queue;
}
return level;
}
}
Java: Most efficient solution using math
Runtime: O(N ^ 0.5)
Memory: O(1)
class Solution {
protected boolean isSquare(int n) {
int sq = (int) Math.sqrt(n);
return n == sq * sq;
}
public int numSquares(int n) {
// four-square and three-square theorems.
while (n % 4 == 0)
n /= 4;
if (n % 8 == 7)
return 4;
if (this.isSquare(n))
return 1;
// enumeration to check if the number can be decomposed into sum of two squares.
for (int i = 1; i * i <= n; ++i) {
if (this.isSquare(n - i * i))
return 2;
}
// bottom case of three-square theorem.
return 3;
}
}
I was solving Leetcode 1044 and the answer is using binary search and rolling hash. Basically use binary search to select a length and then do a search for duplicate string of that length. Here rolling hash comes into play to save space (instead of using a set to store all substring, we store substring's hash). That is the background for the solution.
My question is in terms of the modulus used to prevent overflow. I chose Long.MAX_VALUE which I believe is big enough to handle it but the answer is not correct when I use Long.MAX_VALUE. However, when I use Long.MAX_VALUE / 26 or Math.pow(2, 32), they both work. Sorry I'm pretty bad about modulus and I think I definitely missed some things here. Could anyone shed some light on it? Thanks! The following is my solution:
public static long modulus = Long.MAX_VALUE / 26;
public String longestDupSubstring(String S) {
int n = S.length();
int l = 1;
int r = n - 1;
int index = -1;
while (l <= r) {
int m = l + (r - l) / 2;
int temp = findDuplicate(S, m);
if (temp != -1) {
index = temp;
l = m + 1;
}
else {
r = m - 1;
}
}
return index == -1 ? "" : S.substring(index, index + r);
}
private int findDuplicate(String s, int len) {
Set<Long> set = new HashSet<>();
long hash = 0;
long p = 1;
for (int i = 0; i < len; i++) {
hash = (hash * 26 + s.charAt(i) - 'a') % modulus;
p = (p * 26) % modulus;
}
set.add(hash);
for (int i = len; i < s.length(); i++) {
hash = (hash * 26 + (s.charAt(i) - 'a')
- (s.charAt(i - len) - 'a') * p) % modulus;
if (hash < 0) {
hash += modulus;
}
if (set.contains(hash)) {
return i - len + 1;
}
set.add(hash);
}
return -1;
}
26 is not part of the modulus, is part of hashing. If we would separate those in the algorithm, then we might see how it'd work. For modulus usually a large number would simply suffice, does not have to be a long:
public final class Solution {
int a = 26;
int mod = 1 << 29;
public final String longestDupSubstring(
final String s
) {
int lo = 1;
int hi = s.length() - 1;
while (lo <= hi) {
int mid = lo + ((hi - lo) >> 1);
int startIndex = search(s, mid);
if (startIndex == - 1) {
hi = mid - 1;
}
else {
lo = -~mid;
}
}
int startIndex = search(s, hi);
return startIndex == -1 ? "" : s.substring(startIndex, startIndex + hi);
}
public final int search(
final String s,
final int len
) {
long h = 0;
long aL = 1;
for (int i = 0; i < len; i++) {
h = (h * a % mod + s.charAt(i)) % mod;
aL = aL * a % mod;
}
HashMap<Long, List<Integer>> visited = new HashMap<>();
visited.put(h, new ArrayList<Integer>());
visited.get(h).add(0);
for (int i = 1; i < -~s.length() - len; i++) {
h = ((h * a % mod - s.charAt(i - 1) * aL % mod + mod) % mod + s.charAt(i + len - 1)) % mod;
if (visited.containsKey(h)) {
for (int start : visited.get(h)) {
if (s.substring(start, start + len).equals(s.substring(i, i + len))) {
return i;
}
}
} else {
visited.put(h, new ArrayList<Integer>());
}
visited.get(h).add(i);
}
return -1;
}
}
I am doing a simple MergeSort implementation taking it form a pseudocode. I use Java Generics for that purpose. However I get such exception on the last element in the first for-loop. I have already made some changes (hope for the better) but still this one inevitably comes up. Why is that so?
private Comparable[] mergesort(Comparable[] elements, int l, int r) {
if(l < r){
int m = (l + r - 1)/2;
mergesort(elements, l, m);
mergesort(elements, m + 1, r);
int i = l;
int j = m + 1;
int k = l;
Comparable[] elements1 = (Comparable[])new Comparable[l + r]; //changed from [l + r - 1] and in the function caller also mergesort(elements, elements.length - elements.length, elements.length - 1)
while(i <= m && j <= r){
if(elements[i].compareTo(elements[j]) <= 0 ){
elements1[k] = elements[i];
i++;
} else {
elements1[k] = elements[j];
j++;
}
k++;
}
for(int h = i; i <= m; h++){
elements[k + (h - i)] = elements[h];
//ArrayIndexOutOfBoundsException: 4(the length of the input array)
}
for(int h = j; h <= k - 1; h++){
elements[h] = elements1[h];
}
}
return elements;
}
While your code is hard to read, I think you are comparing the wrong value.
for(int h = i; i <= m; h++){
^
should be h
elements[k + (h - i)] = elements[h];
//ArrayIndexOutOfBoundsException: 4(the length of the input array)
}
You use:
for(int h = i; i <= m; h++) {
elements[k + (h - i)] = elements[h];
}
You always increase h but compare i <= m. Since you never change i you have an endless loop.
There is a variety of answers for the MaxProductOfThree task on codility.com, most of them involving a sorting algorithm.
The problem is:
A non-empty zero-indexed array A consisting of N integers is given.
The problem is to find the maximum product of 3 elements from given array.
The length of the array is between 3 and 100,000
each element of array A is an integer within the range [−1,000..1,000]
expected worst-case time complexity is O(N*log(N));
expected worst-case space complexity is O(1),
beyond input storage (not counting the storage required for input arguments).
Example:
a[0] = -3;
a[1] = 7;
a[2] = 2;
a[3] = 1;
a[4] = 5;
a[5] = 7;
the max product is a[1]*a[4]*a[5] = 245
Is there a linear-time solution to this problem, besides the O(n log n) approach that involves sorting?
/* The method get the max product of 3 consists in basically find the biggest 3 numbers from the array and the smallest 2 numbers from the array in just 1 iteration over the array. Here is the java code:*/
int solution(int[] a) {
/* the minimums initialized with max int to avoid cases with extreme max in array and false minims 0 minimums returned */
int min1 = Integer.MAX_VALUE;
int min2 = Integer.MAX_VALUE;
/* the same logic for maximum initializations but of course inverted to avoid extreme minimum values in array and false 0 maximums */
int max1 = Integer.MIN_VALUE;
int max2 = Integer.MIN_VALUE;
int max3 = Integer.MIN_VALUE;
//the iteration over the array
for (int i = 0; i < a.length; i++) {
//test if max1 is smaller than current array value
if (a[i] > max1) {
//if a[i] is greater than the biggest max then a chain reaction is started,
// max3 will be max2, max2 will be actual max1 and max1 will be a[i]
max3=max2;
max2=max1;
max1=a[i];
/* in case if current a[i] isn't bigger than max1 we test it to see maybe is bigger than second
max. Then the same logic from above is applied for the max2 amd max3 */
}else if(a[i]>max2){
max3 = max2;
max2 = a[i];
/* finally if current array value isn't bigger than max1 and max2 maybe is greater than max3 */
}else if(a[i]>max3){
max3 = a[i];
}
/* The logic from above with maximums is is applied here with minimums but of course inverted to
discover the 2 minimums from current array. */
if (a[i] < min1) {
min2 =min1;
min1=a[i];
} else if (a[i] < min2) {
min2 = a[i];
}
}
/* after we discovered the 3 greatest maximums and the 2 smallest minimums from the array
we do the 2 products of 3 from the greatest maximum and the 2 minimums . This is necessary
because mathematically the product of 2 negative values is a positive value, and because of
this the product of min1 * min2 * max1 can be greater than max1 * max2 * max3
and the product built from the the 3 maximums. */
int prod1 = min1 * min2 * max1;
int prod2 = max1 * max2 * max3;
//here we just return the biggest product
return prod1 > prod2 ? prod1 : prod2;
}
There are only two possible options for the max product in a sorted array.
1) The largest (the last) three elements
2) Combination of two smallest and the largest elements (in case of negative elements, a product of two negatives is positive which multiplied with the largest element, if positive, of an array can produce the largest product)
So the solution is a max of the two and nothing else. The below got 100/100 on Codility.
// you can also use imports, for example:
// import java.util.*;
// you can write to stdout for debugging purposes, e.g.
// System.out.println("this is a debug message");
import java.util.Arrays;
class Solution {
public int solution(int[] A) {
int N = A.length;
Arrays.sort(A);
/**
* When we sort an array there are two possible options for the largest product
* 1) The largest (the last) three elements
* 2) Combination of two smallest and the largest elements
* Logic of (1): Obvious
* Logic of (2): A pair of negatives multiplied returns a positive, which in combination with
* the largest positive element of the array can give the max outcome.
* Therefore we return the max of options (1) and (2)
*/
return Math.max(A[0] * A[1] * A[N - 1], A[N - 1] * A[N - 2] * A[N - 3]);
}
}
Cheers
Kotlin without sorting.
I wonder why so many answer here ignore the question title "without sorting"!
fun solution(A: IntArray): Int {
// write your code in Kotlin
if (A.size < 3) return -1
var max1: Int = Int.MIN_VALUE
var max2: Int = Int.MIN_VALUE
var max3: Int = Int.MIN_VALUE
var min1: Int = Int.MAX_VALUE
var min2: Int = Int.MAX_VALUE
A.forEach {
when {
it > max1 -> {
max3 = max2
max2 = max1
max1 = it
}
it > max2 -> {
max3 = max2
max2 = it
}
it > max3 -> {
max3 = it
}
}
when {
it < min1 -> {
min2 = min1
min1 = it
}
it < min2 -> {
min2 = it
}
}
}
return (min1 * min2 * max1).coerceAtLeast(max1 * max2 * max3)
}
Here's an O(n log n ) solution.
First we sort the array,
then knowing that two negatives with great value make a bigger positive we need to calculate the max at the left of the array, and the product of the 3 elements that are to the right of the array and compare which one is bigger.
Here's a sample code:
// [1,2,3,4] = 24
public int solution(int[] sortedArray) {
Arrays.sort(sortedArray);
int length = sortedArray.length;
int P, Q, R;
int maximumLeft = Integer.MIN_VALUE, maximumRight = Integer.MIN_VALUE;
P = sortedArray[length - 3];
Q = sortedArray[length - 2];
R = sortedArray[length - 1];
maximumRight = P * Q * R;
P = sortedArray[0];
Q = sortedArray[1];
R = sortedArray[length -1];
maximumLeft = P * Q * R;
return maximumRight > maximumLeft ? maximumRight : maximumLeft;
}
Don't forget to import java.util.Arrays;
See this link for the Java file.
Here you go it doesn't use sorting and still gets 100%.
#include<limits>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
int solution(vector<int> &A) {
//Keep the absolute value for max 2 -ve num . As their mul will be +ve
int abs1 = numeric_limits<int>::min();
int abs2 = numeric_limits<int>::min();
//Keep the max three num irrespective of sign
int max1 = numeric_limits<int>::min();
int max2 = numeric_limits<int>::min();
int max3 = numeric_limits<int>::min();
unsigned int size = A.size()-1;
for (unsigned int i = 0; i <= size ; ++i) {
if(A[i] > 0 ){
} else if(abs(A[i]) >= abs1 ) {
abs2 = abs1;
abs1 = abs(A[i]);
}else if(abs(A[i]) >= abs2 ) {
abs2 = abs(A[i]);
}
if(A[i] >= max1 ){
//Push max1s prev value to max2 and max2's prev val to max3
max3 = max2;
max2 = max1;
max1 = A[i];
} else if(A[i] >= max2 ) {
max3 = max2;
max2 = A[i];
}else if(A[i] > max3 ) {
max3 = A[i];
}
}
// Either max 3 multiplication , or Max 2 negative num whose mul is +ve and the regular max
return max(max1 * max2 * max3, abs1 * abs2 * max1);
}
int main(){
vector<int> test = {-3, 1, 2, -2, 5, 6};
cout << solution(test);
return 0;
}
There is a lot of great answers, but I think this one has some elegance in it, also gives 100% on codility.
public static int solution(int[] A) {
Arrays.sort(A);
int F = 0, L = A.length - 1;
int s1 = A[F] * A[F + 1] * A[F + 2];
int s2 = A[F] * A[F + 1] * A[L];
int s3 = A[F] * A[L - 1] * A[L];
int s4 = A[L - 2] * A[L - 1] * A[L];
return Math.max(Math.max(s1, s2), Math.max(s3, s4));
}
Here, is my solution, I have sorted only upto required one
https://app.codility.com/demo/results/training68T6KT-NY6/
public int solution(int[] A) {
// write your code in Java SE 8
int result;
for (int i = 0; i < 3; i++) {
for (int j = i; j < A.length; j++) {
if (A[i] < A[j]) {
int temp = A[i];
A[i] = A[j];
A[j] = temp;
}
}
}
for (int i = 0; i < 2; i++) {
for (int j = 0; j < A.length - i; j++) {
if (A[A.length - 1 - i] > A[j]) {
int temp = A[A.length - 1 - i];
A[A.length - 1 - i] = A[j];
A[j] = temp;
}
}
}
if ((A[A.length - 1] < 0) && A[A.length - 1] * A[A.length - 2] > 0) {
result = A[0] * A[A.length - 1] * A[A.length - 2];
if (result > A[0] * A[1] * A[2])
return result;
}
return A[0] * A[1] * A[2];
}
This might work:
int solution(vector<int>& A) {
// write your code in C++14 (g++ 6.2.0)
int missing = 1;
vector<int> count(A.size());
for (int n = 0; n < A.size(); n++) {
if (A[n] > 0 && A[n] < (A.size() + 1)) {
count[A[n] - 1]++;
}
}
for (int n = 0; n < A.size(); n++) {
if (count[n] == 0) {
break;
}
missing++;
}
return missing;
}
Python solution - 100%
def solution(A):
A.sort()
return max(A[0] * A[1] * A[-1] , A[-3] * A[-2] * A[-1])
private static int[] rev(int[] validData) {
for (int i = 0; i < validData.length / 2; i++) {
int temp = validData[i];
validData[i] = validData[validData.length - i - 1];
validData[validData.length - i - 1] = temp;
}
return validData;
}
public static int solution(int[] A) {
// write your code in Java SE 8
long p = 0, q = 0, r = 0, max1 = Integer.MAX_VALUE, max2 = Integer.MAX_VALUE, res = 0;
Arrays.sort(A);
A = rev(A);
int start = 0, end = A.length;
//upper bound
p = A[start];
q = A[start + 1];
r = A[start + 2];
max1 = p * q * r;
//lower bound
q = A[end - 1];
r = A[end - 2];
max2 = p * q * r;
return (int) Math.max(max1, max2);
}
kinda late, but this approach is less efficient, but still fast. it reverses the array, then the logic is , the upper bound is the first element * two consectives, or either first element * two last consecutives, either one of the two should yield the maximaum.
here is my solution applied to the problem got 100%.
import java.util.*;
// you can write to stdout for debugging purposes, e.g.
// System.out.println("this is a debug message");
class Solution {
public int solution(int[] A) {
Arrays.sort(A);
int length = A.length;
int max =0;
if(A[0]>0||A[length-1]<0){
max = (A[length-1]*A[length-2]*A[length-3]);
return max;
}else{
int lastMultiPlier = A[length-1];
if((A[0]*A[1])>(A[length-2]*A[length-3])){
max=A[0]*A[1]*lastMultiPlier;
}else{
max=A[length-2]*A[length-3]*lastMultiPlier;
}
return max;
}
}
}
It's ok to use sorting in the Codility problem. here is a solution that gives you 100%. Without sorting it becomes messy but definitely possible.
#include<limits>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
int solution(vector<int> &A) {
int abs1 = numeric_limits<int>::min();
int abs2 = numeric_limits<int>::min();
sort(A.begin(), A.end());
unsigned int size = A.size()-1;
int temp;
for (unsigned int i = 0; i <= size ; ++i) {
if(A[i] > 0 ) continue;
if(abs(A[i]) >= abs1 ) {
temp = abs1;
abs1 = abs(A[i]);
abs2 = temp;
}else if(abs(A[i]) >= abs2 ) {
abs2 = abs(A[i]);
}
}
return max(A[size] * A[size-1] * A[size-2], abs1 * abs2 * A[size]);
}
int main(){
vector<int> test = {-4, -6, 3, 4, 5};
cout << solution(test);
return 0;
}
With JavaScript (Node.js 8.9.4):
function solution(A) {
// first we order it
A.sort((a, b) => (a - b));
// we see the first two possibilities and we compare them
let val1 = A[A.length - 1] * A[A.length - 2] * A[A.length - 3]
let val2 = A[A.length - 1] * A[0] * A[1]
// we return the higher value
if (val1 > val2) { return val1 } else { return val2 }
}
python 3, thank you DanutClapa, I did first the positives well but your clarification on last 2 negatives was the solution.
def solution(arr):
if not arr:
return 0
if len(arr) == 3:
m = 1
for i in arr:
m *= i
return m
else:
max_num = min(arr)
second_max = min(arr)
tercero_max = min(arr)
min_num = max(arr)
min_num_2 = max(arr)
for i in range(0, len(arr)):
if (arr[i] > max_num):
tercero_max = second_max
second_max = max_num
max_num = arr[i]
elif arr[i] > second_max:
tercero_max = second_max
second_max = arr[i]
elif arr[i] > tercero_max:
tercero_max = arr[i]
if arr[i] < min_num:
min_num_2 = min_num
min_num = arr[i]
elif arr[i] < min_num_2:
min_num_2 = arr[i]
return max( max_num * second_max * tercero_max, max_num * min_num * min_num_2)
No sort ... ES6, but honestly: why no sort?
find the biggest number {max[0] > max[1] > max[2]}
find the 2 smallest {min[0] < min[1]} (explained above as 2 negative number)
return max of [max[0] * max[1] * max[0], max[0] * max[1] * max[2]]
function answer(A) {
maxA = [...A]
minA = [...A]
max = [];
min = [];
max.push(Math.max(...maxA)); maxA.pop()
max.push(Math.max(...maxA)); maxA.pop()
max.push(Math.max(...maxA));
min.push(Math.min(...minA)); minA.pop()
min.push(Math.min(...minA))
return Math.max(max[0] * max[1] * max[0], max[0] * max[1] * max[2])
}
Here is my c# solution. First order the array, for max product max integers required.
For negative integers we need to look first two element of sorted array.
This solution gets 100%
public int solution(int[] A)
{
var sorted = A.ToList();
sorted.Sort();
var last = sorted[sorted.Count-1]*sorted[sorted.Count-2]*sorted[sorted.Count-3];
var firsttwo = sorted[0]*sorted[1]*sorted[sorted.Count-1];
return Math.Max(last,firsttwo);
}
Python solution with 100% Score
import sys
def solution(A):
if len(A) < 3:
return 0
min_value = sys.maxsize*-1
max_value = sys.maxsize
positive_nus = [min_value]*3
negative_nus =[max_value]*2
for i in range(0,len(A)):
if A[i]> positive_nus[0]:
positive_nus[2] = positive_nus[1]
positive_nus[1]= positive_nus[0]
positive_nus[0] = A[i]
elif A[i] > positive_nus[1]:
positive_nus[2] = positive_nus[1]
positive_nus[1]= A[i]
elif A[i] > positive_nus[2]:
positive_nus[2] = A[i]
if A[i] < negative_nus[0]:
negative_nus[1] = negative_nus[0]
negative_nus[0] = A[i]
elif A[i] < negative_nus[1]:
negative_nus[1] = A[i]
sol1 = positive_nus[0]*positive_nus[1]*positive_nus[2]
sol2 = positive_nus[0]*negative_nus[0]*negative_nus[1]
return max(sol1,sol2)
JavaScript Solution from #Slobodan Antonijević Answer
function solution(A) {
let N = A.length;
/* some time sort doesn't work as expected try passing your own
sorting function to sort it in ascending order
*/
A = A.sort((a,b) => (a-b));
return Math.max(A[0] * A[1] * A[N - 1], A[N - 1] * A[N - 2] * A[N - 3]);
}
In case anyone cares about C.
I tried quicksort before , but got 88% result due to performance issue.
So i ended up with an efficient (100%) yet messy code:
https://app.codility.com/demo/results/trainingGT8RQR-FBM/
int solution(int A[], int N) {
int NEG[3]; NEG[0]=0; NEG[1] = 0; NEG[2]=0; int p=-1;
int POS[3]; POS[0] = 0; POS[1] =0; POS[2] = 0; int n=-1;
int MAXIM[3]; MAXIM[0]=-1001; MAXIM[1]=-1001; MAXIM[2]=-1001; int m = -1;
int i =0;
for(i = 0 ; i < N ; i++)
{
if(A[i] < 0 && A[i] < NEG[2])
{
if(A[i] < NEG[0]) { NEG[2] = NEG[1]; NEG[1] = NEG[0];NEG[0] = A[i];}
else if(A[i] < NEG[1]) { NEG[2] = NEG[1]; NEG[1] = A[i];}
else if(A[i] < NEG[2]) NEG[2] = A[i];
if(n < 2) n++;
}
else if(A[i] >= 0 && A[i] > POS[2])
{
if(A[i] > POS[0]) {POS[2] = POS[1]; POS[1] = POS[0]; POS[0]=A[i];}
else if(A[i] > POS[1]) {POS[2] = POS[1]; POS[1] = A[i];}
else POS[2] = A[i];
if(p < 2) p++;
}
if(A[i] <= 0 )
{
if(A[i] > MAXIM[0]){ MAXIM[2]=MAXIM[1];MAXIM[1]=MAXIM[0]; MAXIM[0]=A[i]; if(m<2)m++;}
else if(A[i]>MAXIM[1]){MAXIM[2]=MAXIM[1]; MAXIM[1]=A[i];if(m<2)m++;}
else if(A[i]>MAXIM[2]){MAXIM[2]=A[i]; if(m<2)m++;}
}
}
int max =0, val_set =0;;
if( n >=1 && p>=0 )
{
int tmp = NEG[0] * NEG[1] * POS[0];
if(val_set == 0)
{ max = tmp;
val_set =1;
}
else
if(tmp > max){
max = tmp;
}
}
if( p > 1 )
{
int tmp = POS[0] * POS[1] * POS[2];
if(val_set == 0)
{ max = tmp;
val_set =1;
}
else
if(tmp > max )
{max = tmp;}
}
else
if( n > 1)
{
int tmp = NEG[0] * NEG[1] * NEG[2];
if(val_set == 0)
{ max = tmp;
val_set =1;
}
else
if(tmp > max ){
max = tmp;}
}
if(m>1){
int temp = MAXIM[0] * MAXIM[1] * MAXIM[2];
if(val_set == 0)
{ max = temp;
val_set =1;
}
else if(temp > max){
max = temp;}
}
return max;
}
Sort the array in Ascending order.
Product1 = Product of last 3 numbers of the sorted array
Product2 = Product of last number and the first 2 numbers of the sorted array
Return the maximum of two above products
O(n) solution in Javascript could be:
function solution(A) {
let sorted = A.sort((a, b) => a-b);
let max1 = A[A.length - 1] * A[A.length - 2] * A[A.length - 3];
let max2 = A[0] * A[1] * A[A.length - 1];
return Math.max(max1, max2);
}
I created my own implementation of merge sort, I tested it that it works. How ever I am not sure if it's O(N Log(N)) as it should be, or it's O(N^2), can you please look at my code and tell?
SortedList
public abstract class SortedList {
public final ArrayList<Integer> params = new ArrayList<Integer>();
public void add(int... params) {
for (int parameter : params) {
this.params.add(parameter);
}
}
abstract public void sort();
public void print() {
for (int parameter : params) {
System.out.print(parameter + " ");
}
System.out.println();
}
}
MargeSort
public class MargeSort extends SortedList{
private int buffer[];
#Override
public void sort() {
buffer = new int[params.size()];
for(int i = 1; i < params.size(); i *= 2){
sort(i);
}
}
private void sort(int interval) {
for(int i = 0; i < params.size() - interval; i += interval * 2){
sort(i, i + interval, interval);
}
}
private void sort(int index1, int index2, int interval) {
int startingIndex = index1;
int index1MaxValue = index1 + interval;
int index2MaxValue = index2 + interval;
if(index2MaxValue >= params.size()){
index2MaxValue = params.size();
}
int counter = 0;
for(counter = 0; index1 < index1MaxValue && index2 < index2MaxValue; counter++){
int param1 = params.get(index1);
int param2 = params.get(index2);
if(param1 < param2){
buffer[counter] = param1;
index1++;
}
else{
buffer[counter] = param2;
index2++;
}
}
int index, indexMaxValue;
if(index1 < index1MaxValue){
index = index1;
indexMaxValue = index1MaxValue;
}
else{
index = index2;
indexMaxValue = index2MaxValue;
}
while(index < indexMaxValue){
int param = params.get(index);
buffer[counter] = param;
index++;
counter++;
}
for(int i = 0; i < interval * 2 && i + startingIndex < params.size(); i++){
params.set(i + startingIndex, buffer[i]);
}
}
}
sort(int) is called lg N times, where N = params.size(). [lg N here and everywhere further means ceil(lg N)]
Loop in sort(int) loops N / (interval / 2) times, where interval in [1 .. lgN], calling sort(...), which takes nr of steps, which is lineary depends on its' interval arg.
So, nr of steps is:
Sigma(k in from 1 to lgN): (N / (interval / 2)) * (C * interval) = C * N/2 * Sigma(1..lgN) 1 = C * N * lgN /2
[ C is constant for accounting of inner sort(...) cost ]