Hourglass sum in 2D array - c++

We are given a (6*6) 2D array of which we have to find largest sum of a hourglass in it.
For example, if we create an hourglass using the number 1 within an array full of zeros, it may look like this:
The sum of an hourglass is the sum of all the numbers within it. The sum for the hourglasses above are 7, 4, and 2, respectively.
I had written a code for it as follows.It is basically a competitive programming question and as I am new to the field,I have written the code with a very bad compplexity..perhaps so much that the program could not produce the desired output within the stipulated period of time.Below is my code:
int main(){
vector< vector<int> > arr(6,vector<int>(6));
for(int arr_i = 0;arr_i < 6;arr_i++)
{
for(int arr_j = 0;arr_j < 6;arr_j++)
{
cin >> arr[arr_i][arr_j];
}
} //numbers input
int temp; //temporary sum storing variable
int sum=INT_MIN; //largest sum storing variable
for(int i=0;i+2<6;i++) //check if at least3 exist at bottom
{
int c=0; //starting point of traversing column wise for row
while(c+2<6) //three columns exist ahead from index
{
int f=0; //test case variable
while(f!=1)
{ //if array does not meet requirements,no need of more execution
for(int j=c;j<=j+2;j++)
{ //1st and 3rd row middle element is 0 and 2nd row is non 0.
//condition for hourglass stucture
if((j-c)%2==0 && arr[i+1][j]==0||((j-c)%2==1 && arr[i+1][j]!=0)
//storing 3 dimensional subarray sum column wise
temp+=arr[i][j]+arr[i+1][j]+arr[i+2][j]; //sum storage
else
f=1; //end traversing further on failure
if(sum<temp)
sum=temp;
f=1;//exit condition
}//whiel loop of test variable
temp=0; //reset for next subarray execution
c++; /*begin traversal from one index greater column wise till
condition*/
}// while loop of c
}
}
cout<<sum;
return 0;
}
This is my implementation of the code which failed to process in the time interval.Please suggest a better solution considering the time complexity and feel free to point out any mistakes from my side in understanding the problem.The question is from Hackerrank.
Here is the link if you need it anyways:
https://www.hackerrank.com/challenges/2d-array

The solution for your problem is:
#include <cstdio>
#include <iostream>
#include <climits>
int main() {
int m[6][6];
// Read 2D Matrix-Array
for (int i = 0; i < 6; ++i) {
for (int j = 0; j < 6; ++j) {
std:: cin >> m[i][j];
}
}
// Compute the sum of hourglasses
long temp_sum = 0, MaxSum = LONG_MIN;
for (int i = 0; i < 6; ++i) {
for (int j = 0; j < 6; ++j) {
if (j + 2 < 6 && i + 2 < 6) {
temp_sum = m[i][j] + m[i][j + 1] + m[i][j + 2] + m[i + 1][j + 1] + m[i + 2][j] + m[i + 2][j + 1] + m[i + 2][j + 2];
if (temp_sum >= MaxSum) {
MaxSum = temp_sum;
}
}
}
}
fprintf(stderr, "Max Sum: %ld\n", MaxSum);
return 0;
}
The algorithm is simple, it sums all the Hourglasses starting of the upper left corner and the last 2 columns and 2 rows are not processed because it can not form hourglasses.

The above code is almost correct, but it does not work for a negative array elements.We should not take max sum as 0 as negative numbers array might not reach their max sum total >=0. In this case, initializing max sum to INT_MIN is a better option.

I have solved in Python 3.0 and passed all test cases in HackerRank:
Idea: in just 3 simple steps:
To extract all 16 3X3 in 6X6 matrix. Get each sub-matrix sum Find
the max of all sub-matrix sum
I have initialized max as -1000 for negative values you can also initialize it with Minimum_Integer value
# Complete the hourglassSum function below.
def hourglassSum(arr):
max = -1000
s= []
sub_array = []
for m in range(4)://Move vertically down the rows like(012,123,234,345 and taking 3 values horizontally)
for col in range(4):
for row in range(3):
sub_array.append(arr[row+m][col:col+3])
s = sub_array//Extracting all 16 3X3 matrices
hour_sum = sum_list(s[0])+s[1][1]+sum_list(s[2])//Mask array for hour_glass index[[1,1,1],[0,1,1],[1,1,1]]
if (max<hour_sum):
max = hour_sum
sub_array = []
return max
def sum_list(list1):
total = 0
for ele in range(0, len(list1)):
total = total + list1[ele]
return total
"""
Extra: Try replacing this in your Spyder for lesser lines of code
Instead of
Existing: without numpy
hour_sum = sum_list(s[0])+s[1][1]+sum_list(s[2])//Mask array for hour_glass index[[1,1,1],[0,1,1],[1,1,1]]
if (max<hour_sum):
max = hour_sum
With numpy:
import numpy as np
import numpy.ma as ma
hour_glass = ma.array(sub_array, mask=mask)
sum = hour_glass.data.sum()
"""

Swift 4 version:
func hourglassSum(arr matrix: [[Int]]) -> Int {
let h = matrix.count
if h < 3 {
return 0
}
let w = matrix[0].count
if w < 3 {
return 0
}
var maxSum: Int?
for i in 0 ..< h - 2 {
for j in 0 ..< w - 2 {
// Considering matrix[i][j] as top left cell of hour glass.
let sum = matrix[i][j] + matrix[i][j+1] + matrix[i][j+2]
+ matrix[i+1][j+1]
+ matrix[i+2][j] + matrix[i+2][j+1] + matrix[i+2][j+2]
// If previous sum is less then current sum then update new sum in maxSum
if let maxValue = maxSum {
maxSum = max(maxValue, sum)
} else {
maxSum = sum
}
}
}
return maxSum ?? 0
}

#JavaScript(Nodejs)
function hourglassSum(arr) {
// Write your code here
let count = -63;
for(let i = 0; i <= 3; i++){
for(let j = 0; j <= 3; j++){
let sum = arr[i][j] + arr[i][j+1] + arr[i][j+2] + arr[i+1][j+1]
+ arr[i+2][j] + arr[i+2][j+1] + arr[i+2][j+2]
if(sum > count){
count = sum
}
}
}
return count;
}

Here is python implementation of this algorithm.
arr = []
for _ in xrange(6):
arr.append(map(int, raw_input().rstrip().split()))
maxSum = -99999999
for row in range(len(arr)):
tempSum = 0
for col in range(len(arr[row])):
if col+2 >= len(arr[row]) or row+2 >= len(arr[col]):
continue
tempSum = arr[row][col] + arr[row][col+1] + arr[row][col+2] + arr[row+1][col+1] + arr[row+2][col] + arr[row+2][col+1] + arr[row+2][col+2]
if maxSum < tempSum:
maxSum = tempSum
print(maxSum)

Basic solution for java;
static int hourglassSum(int[][] arr) {
int sum = 0;
for(int i = 2; i<6; i++){
for(int j = 2; j<6; j++){
int up = arr[i-2][j-2] + arr[i-2][j-1] + arr[i-2][j];
int mid = arr[i-1][j-1];
int down = arr[i][j-2] + arr[i][j-1] + arr[i][j];
if(up+mid+down > sum){
sum = up+mid+down;
}
}
}
return sum;
}

Python clean and fast solution
def hourglassSum(arr):
arr_sum = -5000
tmp_sum = 0
for i in range(0, 6-2):
for j in range (0, 6-2):
tmp_sum = arr[i][j] + arr[i][j+1] + arr[i][j+2] + \
+ arr[i+1][j+1] + \
arr[i+2][j] + arr[i+2][j+1] + arr[i+2][j+2]
if arr_sum < tmp_sum:
arr_sum = tmp_sum
return arr_sum

Just avoided four for loop iterations
int main()
{
int arr[6][6],max=-1,sum;
for(int arr_i = 0; arr_i < 6; arr_i++){
for(int arr_j = 0; arr_j < 6; arr_j++){
scanf("%d",&arr[arr_i][arr_j]);
if(arr[arr_i][arr_j]<-9||arr[arr_i][arr_j]>9)
exit(0);
}
}
for(int arr_i = 0; arr_i <4; arr_i++)
{
sum=0;
for(int arr_j = 0; arr_j < 4; arr_j++){
sum=arr[arr_i][arr_j]+arr[arr_i][arr_j+1]+arr[arr_i][arr_j+2]+arr[arr_i+1][arr_j+1]+arr[arr_i+2][arr_j]+arr[arr_i+2][arr_j+1]+arr[arr_i+2][arr_j+2];
if(sum>max)
max=sum;
}
}
printf("%d",max);
return 0;
}

int main(){
vector< vector<int> > arr(6,vector<int>(6));
for(int arr_i = 0;arr_i < 6;arr_i++){
for(int arr_j = 0;arr_j < 6;arr_j++){
cin >> arr[arr_i][arr_j];
}
}
int sum=-100, temp;
for(int arr_i = 0;arr_i < 4;arr_i++){
for(int arr_j = 0;arr_j < 4;arr_j++){
temp=(arr[arr_i][arr_j]+arr[arr_i][arr_j+1]+arr[arr_i][arr_j+2]+arr[arr_i+1][arr_j+1]+arr[arr_i+2][arr_j]+arr[arr_i+2][arr_j+1]+arr[arr_i+2][arr_j+2]);
if(temp>sum)
sum=temp;
}
}
cout << sum;
return 0;
}

def hourglassSum(arr)
maxHourGlass = -82
counter = 0
for i in 1..4
for j in 1..4
acc = arr[i][j]
counter= counter +1
for x in -1..1
acc = acc + arr[i-1][j+x] + arr[i+1][j+x]
end
maxHourGlass = acc if acc > maxHourGlass
end
end
maxHourGlass
end

This is written in C++14 and passes all nine test cases. I think someone could improve it to use more C++14 features.
int hourglassSum(vector<vector<int>> arr)
{
if(arr.size() < 3 || arr[0].size() < 3 )
return -1;
int rowSize = arr[0].size();
int sum = -9 * 6; // smallest negative sum possible;
for( int i = 1; i < arr.size()-1; i++ )
{
int tmp_sum = 0;
for( int j = 1; j < rowSize-1; j++ )
{
tmp_sum = (arr[i - 1][j - 1] + arr[i - 1][j] + arr[i - 1][j + 1] );
tmp_sum += (arr[i ][j ]);
tmp_sum += (arr[i + 1][j - 1] + arr[i + 1][j] + arr[i + 1][j + 1]);
sum = max(tmp_sum, sum);
}
}
return sum;
}

class Solution {
static void Main(string[] args) {
int[][] arr = new int[6][];
for (int i = 0; i < 6; i++) {
arr[i] = Array.ConvertAll(Console.ReadLine().Split(' '), arrTemp => Convert.ToInt32(arrTemp));
}
int[] sum=new int[16];
int j;
int count=0;
for(int i=0; i<4; i++)
{
for(j=0;j<4;j++)
{
if(count<16)
{
sum[count]=arr[i][j]+arr[i][j+1]+arr[i][j+2]+arr[i+1][j+1]+arr[i+2][j]+arr[i+2][j+1]+arr[i+2][j+2];
count++;
}
}
}
int max=sum.Max();
Console.WriteLine(max);
}
}

Largest (maximum) hourglass sum found in the array will be -63 as the element cannot be greater than -9 i.e. -9*7 = -63
C#
int max_hourglass_sum = -63;
for (int i = 0; i <arr.Length-2; i++) { //row
for (int j = 0 ; j<arr.Length-2; j++) { //column
int current_hourglass_sum = arr[i][j] + arr[i][j+1] + arr[i][j+2] //1st row
+ arr[i+1][j+1] //2nd row
+ arr[i+2][j] + arr[i+2][j+1] + arr[i+2][j+2] ;//3rd row
max_hourglass_sum = Math.Max(max_hourglass_sum , current_hourglass_sum);
}
}

static int hourglassSum(int[][] arr) {
int result = int.MinValue;
int rowLength = arr.GetLength(0);
int colLength = arr.Length;
for (int i = 0; i < rowLength - 2; i++)
{
for(int j=0; j< colLength - 2; j++)
{
int sum = 0;
sum = arr[i][j] + arr[i][j+1] + arr[i][j+2]+ arr[i+1][j+1]
+ arr[i+2][j] + arr[i+2][j+1] + arr[i+2][j+2];
result = Math.Max(result,sum);
}
}
return result;
}

function hourglassSum(arr) {
const hourGlass = [];
for (let i = 0; i < 4; i++) {
for (let x = 0; x < 4; x++) {
let hourGlassSumValue = arr[i][x] + arr[i][x + 1] + arr[i][x + 2] + arr[i + 1][x + 1] + arr[i + 2]enter code here[x] + arr[i + 2][x + 1] + arr[i + 2][x + 2];
hourGlass.push(hourGlassSumValue);
}
}
return Math.max(...hourGlass);
}
console.log(hourglassSum(cars));

Related

How to access (and modify) the elements of the same matrix using p threads?

I have a matrix Image MxN and I want to apply on it a matrix filter of 5x5 (like in this gif https://de.wikipedia.org/wiki/Datei:2D_Convolution_Animation.gif)
I am taking an element from position i,j in the matrix, add the filter on it and its surrounding elements and calculate the new product.
I'm using p threads to do that and each threads gets assigned what columns/rows it will apply the filter to.
Currently I have 2 matrices: - image for the given MxN matrix (that gets 2 borders on each side copying the elements on the side to make the filter application easier).
- filteredImage, where I store the result of the filter applied on each element of the image
My question is: how can I modify my functions below to stop using filteredImage and to operate directly on the matrix Image?
int operation(int x_coord, int y_coord) {
int res = 0;
int offset = n / 2;
for (int x = 0; x < n; x++) {
for (int y = 0; y < m; y++) {
res += image[x_coord - offset + x][y_coord - offset + y] * filter[x][y];
}
}
return res;
}
void threadTask(int start, int end) {
if (M > N) {
for (int j = start; j < end; j++) {
for (int i = 2; i < N + 2; i++) {
filteredImage[i][j] = operation(i, j);
}
}
}
else
{
for (int i = start; i < end; i++) {
for (int j = 2; j < M + 2; j++) {
filteredImage[i][j] = operation(i, j);
}
}
}
}
void paralel() {
thread threads[16]; //max nr of p
int start = 2;
int end;
int nrMax;
int operationsPerThread;
int rest;
nrMax = max(N, M);
operationsPerThread = nrMax / p;
rest = nrMax % p;
for (int i = 0; i < p; i++)
{
end = start + operationsPerThread;
if (rest > 0) {
rest--;
end++;
}
threads[i] = thread(threadTask, start, end);
start = end;
}
for (int i = 0; i < p; i++) {
threads[i].join();
}
}
---
bordering:
image[0][0] = image[0][1] = image[1][0] = image[1][1] = image[2][2];
image[N + 3][0] = image[N + 2][0] = image[N + 3][1] = image[N + 2][1] = image[N + 1][2];
image[0][M + 2] = image[1][M + 2] = image[0][M + 3] = image[1][M + 3] = image[2][M + 1];
image[N + 2][M + 2] = image[N + 3][M + 2] = image[N + 3][M + 3] = image[N + 3][M + 2] = image[N + 2][M + 3] = image[N + 1][M + 1];
the matrices:
int image[N + 4][M + 4], filter[n][m], filteredImage[N + 4][M + 4];
I was thinking of using a barrier so that:
Each threads copies each frontier/the elements it needs to use, there's a barrier and it waits for the other threads to reach the barrier, then the elements in Image are updated using the copied elements.
The only function I need to change is threadTask.
I'm not quite sure how to implement this and I also don't know if this is the most efficient method (I want to copy as few elements as possible).
Any help is very appreciated. Thank you

Codility MinAbsSum

I tried this Codility test: MinAbsSum.
https://codility.com/programmers/lessons/17-dynamic_programming/min_abs_sum/
I solved the problem by searching the whole tree of possibilities. The results were OK, however, my solution failed due to timeout for large input. In other words the time complexity was not as good as expected. My solution is O(nlogn), something normal with trees. But this coding test was in the section "Dynamic Programming", and there must be some way to improve it. I tried with summing the whole set first and then using this information, but always there is something missing in my solution. Does anybody have an idea on how to improve my solution using DP?
#include <vector>
using namespace std;
int sum(vector<int>& A, size_t i, int s)
{
if (i == A.size())
return s;
int tmpl = s + A[i];
int tmpr = s - A[i];
return min (abs(sum(A, i+1, tmpl)), abs(sum(A, i+1, tmpr)));
}
int solution(vector<int> &A) {
return sum(A, 0, 0);
}
I could not solve it. But here's the official answer.
Quoting it:
Notice that the range of numbers is quite small (maximum 100). Hence,
there must be a lot of duplicated numbers. Let count[i] denote the
number of occurrences of the value i. We can process all occurrences
of the same value at once. First we calculate values count[i] Then we
create array dp such that:
dp[j] = −1 if we cannot get the sum j,
dp[j] >= ­ 0 if we can get sum j.
Initially, dp[j] = -1 for all of j (except dp[0] = 0). Then we scan
through all the values a appearing in A; we consider all a such
that count[a]>0. For every such a we update dp that dp[j] denotes
how many values a remain (maximally) after achieving sum j. Note
that if the previous value at dp[j] >= 0 then we can set dp[j] =
count[a] as no value a is needed to obtain the sum j. Otherwise we
must obtain sum j-a first and then use a number a to get sum j. In
such a situation dp[j] = dp[j-a]-1. Using this algorithm, we can
mark all the sum values and choose the best one (closest to half of S,
the sum of abs of A).
def MinAbsSum(A):
N = len(A)
M = 0
for i in range(N):
A[i] = abs(A[i])
M = max(A[i], M)
S = sum(A)
count = [0] * (M + 1)
for i in range(N):
count[A[i]] += 1
dp = [-1] * (S + 1)
dp[0] = 0
for a in range(1, M + 1):
if count[a] > 0:
for j in range(S):
if dp[j] >= 0:
dp[j] = count[a]
elif (j >= a and dp[j - a] > 0):
dp[j] = dp[j - a] - 1
result = S
for i in range(S // 2 + 1):
if dp[i] >= 0:
result = min(result, S - 2 * i)
return result
(note that since the final iteration only considers sums up until S // 2 + 1, we can save some space and time by only creating a DP Cache up until that value as well)
The Java answer provided by fladam returns wrong result for input [2, 3, 2, 2, 3], although it gets 100% score.
Java Solution
import java.util.Arrays;
public class MinAbsSum{
static int[] dp;
public static void main(String args[]) {
int[] array = {1, 5, 2, -2};
System.out.println(findMinAbsSum(array));
}
public static int findMinAbsSum(int[] A) {
int arrayLength = A.length;
int M = 0;
for (int i = 0; i < arrayLength; i++) {
A[i] = Math.abs(A[i]);
M = Math.max(A[i], M);
}
int S = sum(A);
dp = new int[S + 1];
int[] count = new int[M + 1];
for (int i = 0; i < arrayLength; i++) {
count[A[i]] += 1;
}
Arrays.fill(dp, -1);
dp[0] = 0;
for (int i = 1; i < M + 1; i++) {
if (count[i] > 0) {
for(int j = 0; j < S; j++) {
if (dp[j] >= 0) {
dp[j] = count[i];
} else if (j >= i && dp[j - i] > 0) {
dp[j] = dp[j - i] - 1;
}
}
}
}
int result = S;
for (int i = 0; i < Math.floor(S / 2) + 1; i++) {
if (dp[i] >= 0) {
result = Math.min(result, S - 2 * i);
}
}
return result;
}
public static int sum(int[] array) {
int sum = 0;
for(int i : array) {
sum += i;
}
return sum;
}
}
I invented another solution, better than the previous one. I do not use recursion any more.
This solution works OK (all logical tests passed), and also passed some of the performance tests, but not all. How else can I improve it?
#include <vector>
#include <set>
using namespace std;
int solution(vector<int> &A) {
if (A.size() == 0) return 0;
set<int> sums, tmpSums;
sums.insert(abs(A[0]));
for (auto it = begin(A) + 1; it != end(A); ++it)
{
for (auto s : sums)
{
tmpSums.insert(abs(s + abs(*it)));
tmpSums.insert(abs(s - abs(*it)));
}
sums = tmpSums;
tmpSums.clear();
}
return *sums.begin();
}
This solution (in Java) scored 100% for both (correctness and performance)
public int solution(int[] a){
if (a.length == 0) return 0;
if (a.length == 1) return a[0];
int sum = 0;
for (int i=0;i<a.length;i++){
sum += Math.abs(a[i]);
}
int[] indices = new int[a.length];
indices[0] = 0;
int half = sum/2;
int localSum = Math.abs(a[0]);
int minLocalSum = Integer.MAX_VALUE;
int placeIndex = 1;
for (int i=1;i<a.length;i++){
if (localSum<half){
if (Math.abs(2*minLocalSum-sum) > Math.abs(2*localSum - sum))
minLocalSum = localSum;
localSum += Math.abs(a[i]);
indices[placeIndex++] = i;
}else{
if (localSum == half)
return Math.abs(2*half - sum);
if (Math.abs(2*minLocalSum-sum) > Math.abs(2*localSum - sum))
minLocalSum = localSum;
if (placeIndex > 1) {
localSum -= Math.abs(a[indices[placeIndex--]]);
i = indices[placeIndex];
}
}
}
return (Math.abs(2*minLocalSum - sum));
}
this solution treats all elements like they are positive numbers and it's looking to reach as close as it can to the sum of all elements divided by 2 (in that case we know that the sum of all other elements will be the same delta far from the half too -> abs sum will be minimum possible ).
it does so by starting with the first element and successively adding others to the "local" sum (and recording indices of elements in the sum) until it reaches sum of x >= sumAll/2. if that x is equal to sumAll/2 we have an optimal solution. if not, we go step back in the indices array and continue picking other element where last iteration in that position ended. the result will be a "local" sum having abs((sumAll - sum) - sum) closest to 0;
fixed solution:
public static int solution(int[] a){
if (a.length == 0) return 0;
if (a.length == 1) return a[0];
int sum = 0;
for (int i=0;i<a.length;i++) {
a[i] = Math.abs(a[i]);
sum += a[i];
}
Arrays.sort(a);
int[] arr = a;
int[] arrRev = new int[arr.length];
int minRes = Integer.MAX_VALUE;
for (int t=0;t<=4;t++) {
arr = fold(arr);
int res1 = findSum(arr, sum);
if (res1 < minRes) minRes = res1;
rev(arr, arrRev);
int res2 = findSum(arrRev, sum);
if (res2 < minRes) minRes = res2;
arrRev = fold(arrRev);
int res3 = findSum(arrRev, sum);
if (res3 < minRes) minRes = res3;
}
return minRes;
}
private static void rev(int[] arr, int[] arrRev){
for (int i = 0; i < arrRev.length; i++) {
arrRev[i] = arr[arr.length - 1 - i];
}
}
private static int[] fold(int[] a){
int[] arr = new int[a.length];
for (int i=0;a.length/2+i/2 < a.length && a.length/2-i/2-1 >= 0;i+=2){
arr[i] = a[a.length/2+i/2];
arr[i+1] = a[a.length/2-i/2-1];
}
if (a.length % 2 > 0) arr[a.length-1] = a[a.length-1];
else{
arr[a.length-2] = a[0];
arr[a.length-1] = a[a.length-1];
}
return arr;
}
private static int findSum(int[] arr, int sum){
int[] indices = new int[arr.length];
indices[0] = 0;
double half = Double.valueOf(sum)/2;
int localSum = Math.abs(arr[0]);
int minLocalSum = Integer.MAX_VALUE;
int placeIndex = 1;
for (int i=1;i<arr.length;i++){
if (localSum == half)
return 2*localSum - sum;
if (Math.abs(2*minLocalSum-sum) > Math.abs(2*localSum - sum))
minLocalSum = localSum;
if (localSum<half){
localSum += Math.abs(arr[i]);
indices[placeIndex++] = i;
}else{
if (placeIndex > 1) {
localSum -= Math.abs(arr[indices[--placeIndex]]);
i = indices[placeIndex];
}
}
}
return Math.abs(2*minLocalSum - sum);
}
The following is a rendering of the official answer in C++ (scoring 100% in task, correctness, and performance):
#include <cmath>
#include <algorithm>
#include <numeric>
using namespace std;
int solution(vector<int> &A) {
// write your code in C++14 (g++ 6.2.0)
const int N = A.size();
int M = 0;
for (int i=0; i<N; i++) {
A[i] = abs(A[i]);
M = max(M, A[i]);
}
int S = accumulate(A.begin(), A.end(), 0);
vector<int> counts(M+1, 0);
for (int i=0; i<N; i++) {
counts[A[i]]++;
}
vector<int> dp(S+1, -1);
dp[0] = 0;
for (int a=1; a<M+1; a++) {
if (counts[a] > 0) {
for (int j=0; j<S; j++) {
if (dp[j] >= 0) {
dp[j] = counts[a];
} else if ((j >= a) && (dp[j-a] > 0)) {
dp[j] = dp[j-a]-1;
}
}
}
}
int result = S;
for (int i =0; i<(S/2+1); i++) {
if (dp[i] >= 0) {
result = min(result, S-2*i);
}
}
return result;
}
You are almost 90% to the actual solution. It seems you understand recursion very well. Now, You should apply dynamic programming here with your program.
Dynamic Programming is nothing but memoization to the recursion so that we will not calculate same sub problems again and again. If same sub problems encounter , we return the previously calculated and memorized value. Memorization can be done with the help of a 2D array , say dp[][], where first state represent current index of array and second state represent summation.
For this problem specific, instead of giving calls to both states from each state, you sometimes can greedily take decision to skip one call.
I would like to provide the algorithm and then my implementation in C++. Idea is more or less the same as the official codility solution with some constant optimisation added.
Calculate the maximum absolute element of the inputs.
Calculate the absolute sum of the inputs.
Count the number of occurrence of each number in the inputs. Store the results in a vector hash.
Go through each input.
For each input, goes through all possible sums of any number of inputs. It is a slight constant optimisation to go only up to half of the possible sums.
For each sum that has been made before, set the occurrence count of the current input.
Check for each potential sum equal to or greater than the current input whether this input has already been used before. Update the values at the current sum accordingly. We do not need to check for potential sums less than the current input in this iteration, since it is evident that it has not been used before.
The above nested loop will fill in each possible sum with a value greater than -1.
Go through this possible sum hash again to look for the closest sum to half that is possible to make. Eventually, the min abs sum will be the difference of this from the half multiplied by two as the difference will be added up in both groups as the difference from the median.
The runtime complexity of this algorithm is O(N * max(abs(A)) ^ 2), or simply O(N * M ^ 2). That is because the outer loop is iterating M times and the inner loop is iterating sum times. The sum is basically N * M in worst case. Therefore, it is O(M * N * M).
The space complexity of this solution is O(N * M) because we allocate a hash of N items for the counts and a hash of S items for the sums. S is N * M again.
int solution(vector<int> &A)
{
int M = 0, S = 0;
for (const int e : A) { M = max(abs(e), M); S += abs(e); }
vector<int> counts(M + 1, 0);
for (const int e : A) { ++counts[abs(e)]; }
vector<int> sums(S + 1, -1);
sums[0] = 0;
for (int ci = 1; ci < counts.size(); ++ci) {
if (!counts[ci]) continue;
for (int si = 0; si < S / 2 + 1; ++si) {
if (sums[si] >= 0) sums[si] = counts[ci];
else if (si >= ci and sums[si - ci] > 0) sums[si] = sums[si - ci] - 1;
}
}
int min_abs_sum = S;
for (int i = S / 2; i >= 0; --i) if (sums[i] >= 0) return S - 2 * i;
return min_abs_sum;
}
Let me add my 50 cent, how to come up with the score 100% solution.
For me it was hard to understand the ultimate solution, proposed earlier in this thread.
So I started with warm-up solution with score 63%, because its O(NxNxM),
and because it doesn't use the fact that M is quite small value, and there are many duplicates in big arrays
here the key part is to understand how array isSumPossible is filled and interpreted:
how to fill array isSumPossible using numbers in input array:
if isSumPossible[sum] >= 0, i.e. sum is already possible, even without current number, then let's set it's value to 1 - count of current number, that is left unused for this sum, it'll go to our "reserve", so we can use it later for greater sums.
if (isSumPossible[sum] >= 0) {
isSumPossible[sum] = 1;
}
if isSumPossible[sum] <= 0, i.e. sum is considered not yet possible, with all input numbers considered previously, then let's check maybe
smaller sum sum - number is already considered as possible, and we have in "reserve" our current number (isSumPossible[sum - number] == 1), then do following
else if (sum >= number && isSumPossible[sum - number] == 1) {
isSumPossible[sum] = 0;
}
here isSumPossible[sum] = 0 means that we have used number in composing sum and it's now considered as possible (>=0), but we have no number in "reserve", because we've used it ( =0)
how to interpret filled array isSumPossible after considering all numbers in input array:
if isSumPossible[sum] >= 0 then the sum is possible, i.e. it can be reached by summation of some numbers in given array
if isSumPossible[sum] < 0 then the sum can't be reached by summation of any numbers in given array
The more simple thing here is to understand why we are searching sums only in interval [0, maxSum/2]:
because if find a possible sum, that is very close to maxSum/2,
ideal case here if we've found possible sum = maxSum/2,
if so, then it's obvious, that we can somehow use the rest numbers in input array to make another maxSum/2, but now with negative sign, so as a result of annihilation we'll get solution = 0, because maxSum/2 + (-1)maxSum/2 = 0.
But 0 the best case solution, not always reachable.
But we, nevertheless, should seek for the minimal delta = ((maxSum - sum) - sum),
so this we seek for delta -> 0, that's why we have this:
int result = Integer.MAX_VALUE;
for (int sum = 0; sum < maxSum / 2 + 1; sum++) {
if (isSumPossible[sum] >= 0) {
result = Math.min(result, (maxSum - sum) - sum);
}
}
warm-up solution
public int solution(int[] A) {
if (A == null || A.length == 0) {
return 0;
}
if (A.length == 1) {
return A[0];
}
int maxSum = 0;
for (int i = 0; i < A.length; i++) {
A[i] = Math.abs(A[i]);
maxSum += A[i];
}
int[] isSumPossible = new int[maxSum + 1];
Arrays.fill(isSumPossible, -1);
isSumPossible[0] = 0;
for (int number : A) {
for (int sum = 0; sum < maxSum / 2 + 1; sum++) {
if (isSumPossible[sum] >= 0) {
isSumPossible[sum] = 1;
} else if (sum >= number && isSumPossible[sum - number] == 1) {
isSumPossible[sum] = 0;
}
}
}
int result = Integer.MAX_VALUE;
for (int sum = 0; sum < maxSum / 2 + 1; sum++) {
if (isSumPossible[sum] >= 0) {
result = Math.min(result, maxSum - 2 * sum);
}
}
return result;
}
and after this we can optimize it, using the fact that there are many duplicate numbers in big arrays, and we come up with the solution with 100% score, its O(Mx(NxM)), because maxSum = NxM at worst case
public int solution(int[] A) {
if (A == null || A.length == 0) {
return 0;
}
if (A.length == 1) {
return A[0];
}
int maxNumber = 0;
int maxSum = 0;
for (int i = 0; i < A.length; i++) {
A[i] = Math.abs(A[i]);
maxNumber = Math.max(maxNumber, A[i]);
maxSum += A[i];
}
int[] count = new int[maxNumber + 1];
for (int i = 0; i < A.length; i++) {
count[A[i]]++;
}
int[] isSumPossible = new int[maxSum + 1];
Arrays.fill(isSumPossible, -1);
isSumPossible[0] = 0;
for (int number = 0; number < maxNumber + 1; number++) {
if (count[number] > 0) {
for (int sum = 0; sum < maxSum / 2 + 1; sum++) {
if (isSumPossible[sum] >= 0) {
isSumPossible[sum] = count[number];
} else if (sum >= number && isSumPossible[sum - number] > 0) {
isSumPossible[sum] = isSumPossible[sum - number] - 1;
}
}
}
}
int result = Integer.MAX_VALUE;
for (int sum = 0; sum < maxSum / 2 + 1; sum++) {
if (isSumPossible[sum] >= 0) {
result = Math.min(result, maxSum - 2 * sum);
}
}
return result;
}
I hope I've made it at least a little clear
Kotlin solution
Time complexity: O(N * max(abs(A))**2)
Score: 100%
import kotlin.math.*
fun solution(A: IntArray): Int {
val N = A.size
var M = 0
for (i in 0 until N) {
A[i] = abs(A[i])
M = max(M, A[i])
}
val S = A.sum()
val counts = MutableList(M + 1) { 0 }
for (i in 0 until N) {
counts[A[i]]++
}
val dp = MutableList(S + 1) { -1 }
dp[0] = 0
for (a in 1 until M + 1) {
if (counts[a] > 0) {
for (j in 0 until S) {
if (dp[j] >= 0) {
dp[j] = counts[a]
} else if (j >= a && dp[j - a] > 0) {
dp[j] = dp[j - a] - 1
}
}
}
}
var result = S
for (i in 0 until (S / 2 + 1)) {
if (dp[i] >= 0) {
result = minOf(result, S - 2 * i)
}
}
return result
}

General formula for pairing members of array?

Hello guys I am having the following problem:
I have an array with a lenght that is a multiple of 4 e.g:
{1,2,3,4,5,6,7,8}
I want to know how can i get the numbers in the following pairs: {1,4},{2,3},{5,8},{6,7}.....(etc)
Suppose i loop through them and i want to get the index of the pair member from my current index
int myarr[8]={1,2,3,4,5,6,7,8};
for(int i=0;i<8;i++)
**j= func(i)**
I have thought of something like this:
f(1)=4
f(4)=1
and i would be taking: **f(i)=a * i + b** (i think a linear function is enough) It would result: f(i)=j=-i+5 .How can i generalise this for more then 4 members? What do you do in cases where you need a general formula for pairing elements?
Basically, if i is odd j would be i+3, otherwise j = i+1;
int func(int i) {
if(i%2 != 0)
return i+3;
else
return i+1;
}
This will generate
func(1) = 4, func(2) = 3, func(5) = 8, func(6) = 7 // {1,4},{2,3},{5,8},{6,7}.
You could do it as follows by keeping the incremental iteration but use a function depending on the current block and the remainder as follows.
int myarr[8]={1,2,3,4,5,6,7,8};
int Successor(int i)
{
int BlockStart = i / 4;
int Remainder = i % 4;
int j = 0;
if ( Remainder == 0 )
j = 0;
else if ( Remainder == 1 )
j = 3;
else if ( Remainder == 2 )
j = 1;
else if ( Remainder == 3 )
j = 2
return BlockStart + j;
}
for(int i = 0; i < 8; i++)
{
j = f(i);
// usage of the index
}
About the generalization, this should do it:
auto pairs(const vector<int>& in, int groupLength = 4) {
vector<pair<int, int>> result;
int groups = in.size() / groupLength;
for (int group = 0; group < groups; ++group) {
int i = group * groupLength;
int j = i + groupLength - 1;
while (i < j) {
result.emplace_back(in[i++], in[j--]);
}
}
return result;
}
You can run this code online.
If you are just looking for a formula to calculate the indices, then in general case it's:
int f(int i, int k = 4) {
return i + k - 2 * (i % k) - 1;
}
Turns out your special case (size 4) is sequence A004444 in OEIS.
In general you have "nimsum n + (size-1)".

MaxDoubleSliceSum Codility Algorithm

I stumbled upon this problem on Codility Lessons, here is the description:
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:
int solution(vector &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.
I have already read about the algorithm with counting MaxSum starting at index i and ending at index i, but I don't know why my approach sometimes gives bad results. The idea is to compute MaxSum ending at index i, ommiting the minimum value at range 0..i. And here is my code:
int solution(vector<int> &A) {
int n = A.size();
int end = 2;
int ret = 0;
int sum = 0;
int min = A[1];
while (end < n-1)
{
if (A[end] < min)
{
sum = max(0, sum + min);
ret = max(ret, sum);
min = A[end];
++end;
continue;
}
sum = max(0, sum + A[end]);
ret = max(ret, sum);
++end;
}
return ret;
}
I would be glad if you could help me point out the loophole!
My solution based on bidirectional Kadane's algorithm. More details on my blog here. Scores 100/100.
public int solution(int[] A) {
int N = A.length;
int[] K1 = new int[N];
int[] K2 = new int[N];
for(int i = 1; i < N-1; i++){
K1[i] = Math.max(K1[i-1] + A[i], 0);
}
for(int i = N-2; i > 0; i--){
K2[i] = Math.max(K2[i+1]+A[i], 0);
}
int max = 0;
for(int i = 1; i < N-1; i++){
max = Math.max(max, K1[i-1]+K2[i+1]);
}
return max;
}
Here is my code:
int get_max_sum(const vector<int>& a) {
int n = a.size();
vector<int> best_pref(n);
vector<int> best_suf(n);
//Compute the best sum among all x values assuming that y = i.
int min_pref = 0;
int cur_pref = 0;
for (int i = 1; i < n - 1; i++) {
best_pref[i] = max(0, cur_pref - min_pref);
cur_pref += a[i];
min_pref = min(min_pref, cur_pref);
}
//Compute the best sum among all z values assuming that y = i.
int min_suf = 0;
int cur_suf = 0;
for (int i = n - 2; i > 0; i--) {
best_suf[i] = max(0, cur_suf - min_suf);
cur_suf += a[i];
min_suf = min(min_suf, cur_suf);
}
//Check all y values(y = i) and return the answer.
int res = 0;
for (int i = 1; i < n - 1; i++)
res = max(res, best_pref[i] + best_suf[i]);
return res;
}
int get_max_sum_dummy(const vector<int>& a) {
//Try all possible values of x, y and z.
int res = 0;
int n = a.size();
for (int x = 0; x < n; x++)
for (int y = x + 1; y < n; y++)
for (int z = y + 1; z < n; z++) {
int cur = 0;
for (int i = x + 1; i < z; i++)
if (i != y)
cur += a[i];
res = max(res, cur);
}
return res;
}
bool test() {
//Generate a lot of small test cases and compare the output of
//a brute force and the actual solution.
bool ok = true;
for (int test = 0; test < 10000; test++) {
int size = rand() % 20 + 3;
vector<int> a(size);
for (int i = 0; i < size; i++)
a[i] = rand() % 20 - 10;
if (get_max_sum(a) != get_max_sum_dummy(a))
ok = false;
}
for (int test = 0; test < 10000; test++) {
int size = rand() % 20 + 3;
vector<int> a(size);
for (int i = 0; i < size; i++)
a[i] = rand() % 20;
if (get_max_sum(a) != get_max_sum_dummy(a))
ok = false;
}
return ok;
}
The actual solution is get_max_sum function(the other two are a brute force solution and a tester functions that generates a random array and compares the output of a brute force and actual solution, I used them for testing purposes only).
The idea behind my solution is to compute the maximum sum in a sub array that that starts somewhere before i and ends in i - 1, then do the same thing for suffices(best_pref[i] and best_suf[i], respectively). After that I just iterate over all i and return the best value of best_pref[i] + best_suf[i]. It works correctly because best_pref[y] finds the best x for a fixed y, best_suf[y] finds the best z for a fixed y and all possible values of y are checked.
def solution(A):
n = len(A)
K1 = [0] * n
K2 = [0] * n
for i in range(1,n-1,1):
K1[i] = max(K1[i-1] + A[i], 0)
for i in range(n-2,0,-1):
K2[i] = max(K2[i+1]+A[i], 0)
maximum = 0;
for i in range(1,n-1,1):
maximum = max(maximum, K1[i-1]+K2[i+1])
return maximum
def main():
A = [3,2,6,-1,4,5,-1,2]
print(solution(A))
if __name__ == '__main__': main()
Ruby 100%
def solution(a)
max_starting =(a.length - 2).downto(0).each.inject([[],0]) do |(acc,max), i|
[acc, acc[i]= [0, a[i] + max].max ]
end.first
max_ending =1.upto(a.length - 3).each.inject([[],0]) do |(acc,max), i|
[acc, acc[i]= [0, a[i] + max].max ]
end.first
max_ending.each_with_index.inject(0) do |acc, (el,i)|
[acc, el.to_i + max_starting[i+2].to_i].max
end
end

Laguerre interpolation algorithm, something's wrong with my implementation

This is a problem I have been struggling for a week, coming back just to give up after wasted hours...
I am supposed to find coefficents for the following Laguerre polynomial:
P0(x) = 1
P1(x) = 1 - x
Pn(x) = ((2n - 1 - x) / n) * P(n-1) - ((n - 1) / n) * P(n-2)
I believe there is an error in my implementation, because for some reason the coefficents I get seem way too big. This is the output this program generates:
a1 = -190.234
a2 = -295.833
a3 = 378.283
a4 = -939.537
a5 = 774.861
a6 = -400.612
Description of code (given below):
If you scroll the code down a little to the part where I declare array, you'll find given x's and y's.
The function polynomial just fills an array with values of said polynomial for certain x. It's a recursive function. I believe it works well, because I have checked the output values.
The gauss function finds coefficents by performing Gaussian elimination on output array. I think this is where the problems begin. I am wondering, if there's a mistake in this code or perhaps my method of veryfying results is bad? I am trying to verify them like that:
-190.234 * 1.5 ^ 5 - 295.833 * 1.5 ^ 4 ... - 400.612 = -3017,817625 =/= 2
Code:
#include "stdafx.h"
#include <conio.h>
#include <iostream>
#include <iomanip>
#include <math.h>
using namespace std;
double polynomial(int i, int j, double **tab)
{
double n = i;
double **array = tab;
double x = array[j][0];
if (i == 0) {
return 1;
} else if (i == 1) {
return 1 - x;
} else {
double minusone = polynomial(i - 1, j, array);
double minustwo = polynomial(i - 2, j, array);
double result = (((2.0 * n) - 1 - x) / n) * minusone - ((n - 1.0) / n) * minustwo;
return result;
}
}
int gauss(int n, double tab[6][7], double results[7])
{
double multiplier, divider;
for (int m = 0; m <= n; m++)
{
for (int i = m + 1; i <= n; i++)
{
multiplier = tab[i][m];
divider = tab[m][m];
if (divider == 0) {
return 1;
}
for (int j = m; j <= n; j++)
{
if (i == n) {
break;
}
tab[i][j] = (tab[m][j] * multiplier / divider) - tab[i][j];
}
for (int j = m; j <= n; j++) {
tab[i - 1][j] = tab[i - 1][j] / divider;
}
}
}
double s = 0;
results[n - 1] = tab[n - 1][n];
int y = 0;
for (int i = n-2; i >= 0; i--)
{
s = 0;
y++;
for (int x = 0; x < n; x++)
{
s = s + (tab[i][n - 1 - x] * results[n-(x + 1)]);
if (y == x + 1) {
break;
}
}
results[i] = tab[i][n] - s;
}
}
int _tmain(int argc, _TCHAR* argv[])
{
int num;
double **array;
array = new double*[5];
for (int i = 0; i <= 5; i++)
{
array[i] = new double[2];
}
//i 0 1 2 3 4 5
array[0][0] = 1.5; //xi 1.5 2 2.5 3.5 3.8 4.1
array[0][1] = 2; //yi 2 5 -1 0.5 3 7
array[1][0] = 2;
array[1][1] = 5;
array[2][0] = 2.5;
array[2][1] = -1;
array[3][0] = 3.5;
array[3][1] = 0.5;
array[4][0] = 3.8;
array[4][1] = 3;
array[5][0] = 4.1;
array[5][1] = 7;
double W[6][7]; //n + 1
for (int i = 0; i <= 5; i++)
{
for (int j = 0; j <= 5; j++)
{
W[i][j] = polynomial(j, i, array);
}
W[i][6] = array[i][1];
}
for (int i = 0; i <= 5; i++)
{
for (int j = 0; j <= 6; j++)
{
cout << W[i][j] << "\t";
}
cout << endl;
}
double results[6];
gauss(6, W, results);
for (int i = 0; i < 6; i++) {
cout << "a" << i + 1 << " = " << results[i] << endl;
}
_getch();
return 0;
}
I believe your interpretation of the recursive polynomial generation either needs revising or is a bit too clever for me.
given P[0][5] = {1,0,0,0,0,...}; P[1][5]={1,-1,0,0,0,...};
then P[2] is a*P[0] + convolution(P[1], { c, d });
where a = -((n - 1) / n)
c = (2n - 1)/n and d= - 1/n
This can be generalized: P[n] == a*P[n-2] + conv(P[n-1], { c,d });
In every step there is involved a polynomial multiplication with (c + d*x), which increases the degree by one (just by one...) and adding to P[n-1] multiplied with a scalar a.
Then most likely the interpolation factor x is in range [0..1].
(convolution means, that you should implement polynomial multiplication, which luckily is easy...)
[a,b,c,d]
* [e,f]
------------------
af,bf,cf,df +
ae,be,ce,de, 0 +
--------------------------
(= coefficients of the final polynomial)
The definition of P1(x) = x - 1 is not implemented as stated. You have 1 - x in the computation.
I did not look any further.