-
-
Save mkozakov/59af0fd5bddbed1a0399 to your computer and use it in GitHub Desktop.
/* package whatever; // don't place package name! */ | |
import java.util.*; | |
import java.lang.*; | |
import java.io.*; | |
/* Name of the class has to be "Main" only if the class is public. */ | |
class Ideone | |
{ | |
public static void main (String[] args) throws java.lang.Exception | |
{ | |
int[] myIntArray = {2, 5, 1, 2, 3, 4, 7, 7, 6}; | |
System.out.println(calculateVolume(myIntArray)); | |
} | |
public static int calculateVolume(int[] land) { | |
int leftMax = 0; | |
int rightMax = 0; | |
int left = 0; | |
int right = land.length - 1; | |
int volume = 0; | |
while(left < right) { | |
if(land[left] > leftMax) { | |
leftMax = land[left]; | |
} | |
if(land[right] > rightMax) { | |
rightMax = land[right]; | |
} | |
if(leftMax >= rightMax) { | |
volume += rightMax - land[right]; | |
right--; | |
} else { | |
volume += leftMax - land[left]; | |
left++; | |
} | |
} | |
return volume; | |
} | |
} |
Another Python solution - https://gist.github.com/joneschris/8049901
Here is a solution using C# and one lambda
using System;
using System.Linq;
namespace TwitterInterviewAnswer
{
class Program
{
static void Main(string[] args)
{
//the data
int[] wallHeights = {2, 5, 1, 2, 3, 4, 7, 7, 6};
//the lambda expression
Func<int[], int> volume = walls => walls.Skip(1).Take(walls.Count() - 2)
.Select((s, i) => new {s, i})
.Select(v => new[]
{
walls.Take(v.i + 1)
.Max(),
walls
.Skip(v.i + 2)
.Max()
}
.Min() - v.s)
.Where(w => w > 0)
.Sum();
//the output
Console.WriteLine("The volume is: {0}", volume.Invoke(wallHeights));
Console.ReadKey();
}
}
}
@jbojcic your code won't work for something like [7,3,2,4].
You will fill in water that should spill out
@mkozakov it won't fill up water that should spill out but it will spill out everything, which is also wrong
# Actually the original implementation is as following which is done in n-pass:
def water_vol_orig(a):
lv = rv = -1
result = lmax = rmax = l = 0
r = len(a)-1 # no pass on array
while (l < r):
lv = a[l]
if lv > lmax:
lmax = lv
rv = a[r]
if rv > rmax:
rmax = rv
if lmax >= rmax:
result += rmax - rv
r -= 1
else:
result += lmax - lv
l += 1
return result
# This implementation avoids the lookup for the max item in the array to finish in n-pass.
# However, it is doing 3 comparisons inside the inner loop and in dynamic languages like Python/Java
# indexed access to an array is expensive, using enumerators is far more effective.
# So more efficient way of doing this in Python may be:
#1) find the max item
#2) approach to max item from left and right.
def water_vol_fast(a):
def _imax(x): # find max in single pass, faster than max(..,itemgetter(..))
max_idx = max_val = 0
for i, v in enumerate(a):
if v > max_val:
max_val = v
max_idx = i
return max_idx
def _volp(x):
max = result = 0
for e in x:
if e > max:
max = e
else:
result += max - e
return result
imax = _imax(a) # n-pass
return _volp(a[:imax]) + _volp(reversed(a[imax:])) # n pass
# This version will have 2N comparisons(1N for finding max and 1N for calculating the volume) and no index
# based access to any array.
# If these are profiled, one can see the difference:
# water_vol_orig takes 0.405603 CPU Secs, and water_vol will take 0.265202 which is nearly %80 faster.
# You can test above by:
# for test:
import random
a = [int(1000*random.random()) for i in range(10000)]
assert water_vol_orig(a) == water_vol_fast(a)
Hm... tried to run original solution against the data with 3 maximums and it didn't work...
public class TestTest {
public static void main (String[] args) throws java.lang.Exception
{
int[] testData1 = {1, 2, 1, 3, 2, 1, 0, 2, 4, 3, 1, 5, 3, 1, 4, 1, 2, 1, 0};
int expectedResult1 = 17;
int[] testData2 = {4, 1, 2, 1, 3, 2, 1, 0, 2, 4, 3, 1, 5, 3, 1, 4, 1, 2, 1, 0};
int expectedResult2 = 40;
int[] testData3 = {1, 3, 4, 1, 2, 1, 3, 2, 1, 0, 2, 4, 3, 1, 5, 3, 1, 4, 1, 2, 1, 0};
int expectedResult3 = 40;
int[] testData4 = {2, 1, 3, 4, 1, 2, 1, 3, 2, 1, 0, 2, 4, 3, 1, 5, 3, 1, 4, 1, 2, 1, 0};
int expectedResult4 = 41;
int[] testData5 = {2, 1, 3, 4, 1, 2, 1, 3, 2, 1, 0, 2, 4, 3, 1, 5, 3, 1, 4, 1, 2, 1, 0, 5, 2, 1, 3};
int expectedResult5 = 61;
test(expectedResult1, testData1);
test(expectedResult2, testData2);
test(expectedResult3, testData3);
test(expectedResult4, testData4);
test(expectedResult5, testData5); //[ERROR] Test failure! Expected: 61 but was: 62
}
public static void test(int expected, int[] array){
int result = calculateVolume(array);
if(result != expected) {
System.out.println("[ERROR] Test failure! Expected: " + expected + " but was: " + result);
} else {
System.out.println("[INFO] Test successful!");
}
}
public static int calculateVolume(int[] land) {
int leftMax = 0;
int rightMax = 0;
int left = 0;
int right = land.length - 1;
int volume = 0;
while(left < right) {
if(land[left] > leftMax) {
leftMax = land[left];
}
if(land[right] > rightMax) {
rightMax = land[right];
}
if(leftMax >= rightMax) {
volume += rightMax - land[right];
right--;
} else {
volume += leftMax - land[left];
left++;
}
}
return volume;
}
}
@Mak-Sym Original implementation returns 51 and your expectation should not be 61. 51 is the correct volume for input set: {2, 1, 3, 4, 1, 2, 1, 3, 2, 1, 0, 2, 4, 3, 1, 5, 3, 1, 4, 1, 2, 1, 0, 5, 2, 1, 3}.
Please do not forget the fact that water will spill from left/right if there is no surrounding block.
Thanks!
There is typo in my post - sorry about that
I meant this one:
int[] testData5 = {2, 1, 3, 5, 1, 2, 1, 3, 2, 1, 0, 2, 4, 3, 1, 5, 3, 1, 4, 1, 2, 1, 0, 5, 2, 1, 3}; //should be 61, but was 62
Whoops - found bug in my calculations - it should be 62 (not sure how I missed this during numerous manual verifications and my v1 impl :) )
unspoiled solution; I think mine works the same way as yours.
https://gist.github.com/Pranz/45eff77d201ef1e2dc61
This seems to work ...
https://gist.github.com/bourneagain/0cb90851106756746933
here is an alternate but simple nlog(n) solution
https://gist.github.com/isaiah-perumalla/105b72e6b99f69b599ec
just an F# solution for aestetic pleasure
let oneWayCapacity a =
let mutable max = 0
a |> List.map (fun e -> if e > max then max <- e; 0 else max - e)
let totalCapacity a =
let aL = a |> oneWayCapacity
let aR = a |> List.rev |> oneWayCapacity |> List.rev
List.map2 min aL aR |> List.sum
let test a =
a |> totalCapacity |>
printfn "totalCapacity %A = %i" a
let () =
[1; 2; 1; 3; 5; 3; 1; 2; 4; 1] |> test
[2; 5; 10; 7; 3; 8; 5; 2] |> test
[2; 5; 1; 2; 3; 4; 7; 7; 6] |> test
https://gist.github.com/harry-tallbelt/cc236e710c9edf858853c118bc38c9ad
one-pass solution in js
const assert = require('assert')
// original walls, expect 17
const walls1 = [ 2, 5, 1, 3, 1, 2, 1, 7, 7, 6 ]
// case when some water spills over the right edge, expect 12
const walls2 = [ 2, 5, 1, 3, 1, 2, 1, 4, 4, 3 ]
// should be 51
const walls3 = [ 2, 1, 3, 4, 1, 2, 1, 3, 2, 1, 0, 2, 4, 3, 1, 5, 3, 1, 4, 1, 2, 1, 0, 5, 2, 1, 3 ]
function volume(walls) {
let level = 0
let acc = 0
let result = 0
let prev = 0
let level_pos = -1
for(let i = 0; i < walls.length; i++) {
if ( walls[i] >= level ) {
// new high-water level mark, flush accumulated volume into final result
level = walls[i]
level_pos = i
result = result + acc
acc = 0
}
if ( walls[i] < level ) {
// water accumulation
let delta = level - walls[i]
acc = acc + delta
if ( walls[i] > prev ) {
// this a local extremum
let above = (level - walls[i]) * (i - level_pos)
let pond = acc - above
result = result + pond
acc = above
// get water pond by local extremum and add to final result,
// accumulated volume is now the water above the extremum
}
}
prev = walls[i]
}
return result
}
assert(volume(walls1), 17)
console.log(volume(walls1))
assert(volume(walls2), 12)
console.log(volume(walls2))
assert(volume(walls3), 51)
console.log(volume(walls3))
Short JS solution:
https://gist.github.com/allumbra/8035125
1 pass. Keeps track of last time wall height was seen.