I am trying to solve the problem of finding the number of paths in a lattice (some grid) using recursion.
I wrote the following code which suppose to find total number of valid paths in a lattice/grid. In a valid path (to the bottom right corner of the grid), you can only move in one of two directions: right or down.
I'm not sure it is correct way of using recursion.
Is there any better way of solving this problem / using recursion to solve it?
Thanks
var array = [[0,0,0,0],[0,0,0,0],[0,0,0,0]];
var lastRowIndex=2;
var lastColIndex=3;
var count=0;
function pathCount(i,j){
if(!(array[i-1]==undefined) || !(array[i][j-1]==undefined)){
if(!(array[i-1]==undefined)){
--i;
pathCount(i,j);
i++;
}
if(!(array[i][j-1]==undefined)){
--j;
pathCount(i,j);
}
}else{
++count;
}
return count;
}
console.log(pathCount(lastRowIndex,lastColIndex));
Your code is fine. basically it does what it should.
Assuming a valid path is constructed only by moving down the grid or moving to the right,
notice you don't actually need the array, just a size parameter and a pointer to the current position traveled by your algorithm.
As any regression problem let us start by something simple, an induction basis.
First notice, in a linear grid (size 1xN or Nx1) there is only one valid path.
Now, if you are at the (i,j) square, you only have 2 possibilities of moving, hence
the total number of paths is a sum of two element:
The number of valid paths from square (i-1,j)
The number of valid paths from square (i,j-1)
(notice a validity check on these argument is needed, since they are bounded by the possible indices of the grid).
so a possible recursion is:
let size = 10;
let grid = {
width: size,
height: size
};
let currentPosition = {
x: size,
y: size
};
function validDecrement(value) {
return (value - 1 >= 1 ? value - 1 : 1);
}
function countValidPaths(gridObject, startingLocation) {
if (startingLocation.x === 1 || startingLocation.y === 1) {
return 1;
} else if (startingLocation.x > 1 && startingLocation.y > 1) {
return countValidPaths(gridObject, {
x: startingLocation.x,
y: validDecrement(startingLocation.y)
}) + countValidPaths(gridObject, {
x: validDecrement(startingLocation.x),
y: startingLocation.y
});
} else {
console.log(`invalid input: grid: ${gridObject}, startingLocation: ${startingLocation}`);
};
}
console.log(`Number of valid paths over a ${grid.height} by ${grid.width} grid is : ${countValidPaths(grid,currentPosition)}`);
Of course - there is a much better approach to solving this method rather than a recursion. the number you are seeking is simply the binomial coefficient C((grid.with-1)+(grid.height-1),(grid.width-1)) - lattice paths counting
Related
I'm working on the stonewall exercise of codility. Getting 100% on the correctness tests, but failing all of the performance tests. I'm having trouble envisiging why my solution may be fine for smaller inputs but is going so wrong for larger inputs. Is anyone able to offer feedback about what might be wrong with my solution? I've found this one quite challenging. Taken me a few days of revisiting just to get to this stage! Thanks in advance.
The problem
You are going to build a stone wall. The wall should be straight and N
meters long, and its thickness should be constant; however, it should
have different heights in different places. The height of the wall is
specified by an array H of N positive integers. H[I] is the height of
the wall from I to I+1 meters to the right of its left end. In
particular, H[0] is the height of the wall's left end and H[N−1] is
the height of the wall's right end.
The wall should be built of cuboid stone blocks (that is, all sides of
such blocks are rectangular). Your task is to compute the minimum
number of blocks needed to build the wall.
Write a function:
function solution(H);
that, given an array H of N positive integers specifying the height of
the wall, returns the minimum number of blocks needed to build it.
For example, given array H containing N = 9 integers: H[0] = 8
H[1] = 8 H[2] = 5 H[3] = 7 H[4] = 9 H[5] = 8 H[6] = 7
H[7] = 4 H[8] = 8
the function should return 7. The figure shows one possible
arrangement of seven blocks.
Write an efficient algorithm for the following assumptions:
N is an integer within the range [1..100,000];
each element of array H is an integer within the range [1..1,000,000,000].
My solution
function solution(H) {
let stones = 0
let absoluteMinimum = Infinity;
let prevStones = []
for (let i = 0; i < H.length; i++) {
if (H[i] < absoluteMinimum) {
stones ++
absoluteMinimum = H[i]
prevStones = [H[i]]
} else if (prevStones.includes(H[i])) {
while (prevStones.includes(H[i])) {
prevStones.pop()
}
prevStones.push(H[i])
} else if (H[i] != H[i-1]) {
prevStones.push(H[i])
stones ++
}
}
return stones
}
Here is the summary of my attempt including test results.
https://app.codility.com/demo/results/training2V8Y42-AUQ/
Following #Teemu's comment, and noting that the code simply is searching prevStones for the existence of a specific height, suggest creating another array that holds the counts of the heights in prevStonesCount.
Eg, if setting prevStones = [ 8 ] then set prevStonesCount[ 8 ] = 1, as there is one stone in the prevStones array of height 8.
Now, rather than having to perform prevStones.includes( 8 ), simply check if 0 < prevStonesCount[ 8 ]. (That is, .includes() searches the entire prevStones array for a height of 8, whereas prevStonesCount[ 8 ] in one step indicates whether any stones of height 8 are in the prevStones array.)
Thus, anytime performing a prevStones.push( x ) or prevStones.pop( x ), make the corresponding adjustment of prevStonesCount[ x ] += 1 or prevStonesCount[ x ] -= 1, respectively.
Note also that within the first if where prevStones = [H[i]], that the prevStones array is essentially cleared and set to an initial value. This means that the prevStonesCount array will also need to be cleared, and then set prevStonesCount[ H[i] ] = 1.
I'm following an exercise's tutorial but I cannot understand the logic.
The initial setup is a 3x3 board made of a 2D array. Each nested array will have 3 elements, and they will be objects with two properties: x and y, defining their position in the array. (x represent the index and y the position of each element in the nested array so it will be 0,1 or 2 since each nested array has 3 elements).
we define an object we will be using: it will be named player and, for now, will have x and y properties set to the following values:
const player = {
x: 1,
y: 1
};
So now the object is placed in the middle of our 3x3 board with position {1,1}
Our next logical step is to start writing some code and to define a function that will allow us, whenever called, depending on the given command (go left or go right) to change the position of the player on the board. To be able to affect the player’s properties and its position, our function has to have access to the player object. Also, we have to set some condition in order not to allow our player to leave the board. And that's the condition I do not understand:
if (thePlayer.y >= 0 && thePlayer.y < 2) {
if (command === 'l') {
thePlayer.y--;
} else {
thePlayer.y++;
}
console.log(`Player has position: x=${thePlayer.x}, y=${thePlayer.y}`);
} else {
console.log("You can't place player outside of the board!");
}
}
Why the first 'if' statement says >=0 and not >0 ?
if the value of y was 0, the player would be on the left side of the board, and then still able to move left because equal to zero and then would go out of the board.
What makes me totally blank is the following sentence:
Now, if our player’s property “y” is lower than 0, we’ll get a notification that the player left the board, and that is not allowed.
The exercise is right but I would like to understand!
This logic is wrong for me also, You will not be able to move 'player' when it will be on Y = 0, which is still correct position. I guess the better and clear solution will be first check the command and then check if command is valid or not, smthg like this:
const moveHandlers = {
'l': () => thePlayer.y--,
'r': () => thePlayer.y++,
}
const validCommands = Object.keys(moveHandlers);
if (!validCommands.includes(command)) {
throw new Error('Invalid command');
}
const invalidLeftMove = command === 'l' && thePlayer.y === 0;
const invalidRightMove = command === 'r' && thePlayer.y === 2;
if (invalidLeftMove || invalidRightMove) {
throw new Error("You can't place player outside of the board!");
}
moveHandlers[command]();
I am using a couple of functions from Snap.SVG, mainly path2curve and the functions around it to build a SVG morph plugin.
I've setup a demo here on Codepen to better illustrate the issue. Basically morphing shapes simple to complex and the other way around is working properly as of Javascript functionality, however, the visual isn't very pleasing.
The first shape morph looks awful, the second looks a little better because I changed/rotated it's points a bit, but the last example is perfect.
So I need either a better path2curve or a function to prepare the path string before the other function builds the curves array. Snap.SVG has a function called getClosest that I think may be useful but it's not documented.
There isn't any documentation available on this topic so I would appreciate any suggestion/input from RaphaelJS / SnapSVG / d3.js / three/js developers.
I've provided a runnable code snippet below that uses Snap.svg and that I believe demonstrates one solution to your problem. With respect to trying to find the best way to morph a starting shape into an ending shape, this algorithm essentially rotates the points of the starting shape one position at a time, sums the squares of the distances between corresponding points on the (rotated) starting shape and the (unchanged) ending shape, and finds the minimum of all those sums. i.e. It's basically a least squares approach. The minimum value identifies the rotation that, as a first guess, will provide the "shortest" morph trajectories. In spite of these coordinate reassignments, however, all 'rotations' should result in visually identical starting shapes, as required.
This is, of course, a "blind" mathematical approach, but it might help provide you with a starting point before doing manual visual analysis. As a bonus, even if you don't like the rotation that the algorithm chose, it also provides the path 'd' attribute strings for all the other rotations, so some of that work has already been done for you.
You can modify the snippet to provide any starting and ending shapes you want. The limitations are as follows:
Each shape should have the same number of points (although the point types, e.g. 'lineto', 'cubic bezier curve', 'horizontal lineto', etc., can completely vary)
Each shape should be closed, i.e. end with "Z"
The morph desired should involve only translation. If scaling or rotation is desired, those should be applied after calculating the morph based only on translation.
By the way, in response to some of your comments, while I find Snap.svg intriguing, I also find its documentation to be somewhat lacking.
Update: The code snippet below works in Firefox (Mac or Windows) and Safari. However, Chrome seems to have trouble accessing the Snap.svg library from its external web site as written (<script...github...>). Opera and Internet Explorer also have problems. So, try the snippet in the working browsers, or try copying the snippet code as well as the Snap library code to your own computer. (Is this an issue of accessing third party libraries from within the code snippet? And why browser differences? Insightful comments would be appreciated.)
var
s = Snap(),
colors = ["red", "blue", "green", "orange"], // colour list can be any length
staPath = s.path("M25,35 l-15,-25 C35,20 25,0 40,0 L80,40Z"), // create the "start" shape
endPath = s.path("M10,110 h30 l30,20 C30,120 35,135 25,135Z"), // create the "end" shape
staSegs = getSegs(staPath), // convert the paths to absolute values, using only cubic bezier
endSegs = getSegs(endPath), // segments, & extract the pt coordinates & segment strings
numSegs = staSegs.length, // note: the # of pts is one less than the # of path segments
numPts = numSegs - 1, // b/c the path's initial 'moveto' pt is also the 'close' pt
linePaths = [],
minSumLensSqrd = Infinity,
rotNumOfMin,
rotNum = 0;
document.querySelector('button').addEventListener('click', function() {
if (rotNum < numPts) {
linePaths.forEach(function(linePath) {linePath.remove();}); // erase any previous coloured lines
var sumLensSqrd = 0;
for (var ptNum = 0; ptNum < numPts; ptNum += 1) { // draw new lines, point-to-point
var linePt1 = staSegs[(rotNum + ptNum) % numPts]; // the new line begins on the 'start' shape
var linePt2 = endSegs[ ptNum % numPts]; // and finished on the 'end' shape
var linePathStr = "M" + linePt1.x + "," + linePt1.y + "L" + linePt2.x + "," + linePt2.y;
var linePath = s.path(linePathStr).attr({stroke: colors[ptNum % colors.length]}); // draw it
var lineLen = Snap.path.getTotalLength(linePath); // calculate its length
sumLensSqrd += lineLen * lineLen; // square the length, and add it to the accumulating total
linePaths[ptNum] = linePath; // remember the path to facilitate erasing it later
}
if (sumLensSqrd < minSumLensSqrd) { // keep track of which rotation has the lowest value
minSumLensSqrd = sumLensSqrd; // of the sum of lengths squared (the 'lsq sum')
rotNumOfMin = rotNum; // as well as the corresponding rotation number
}
show("ROTATION OF POINTS #" + rotNum + ":"); // display info about this rotation
var rotInfo = getRotInfo(rotNum);
show(" point coordinates: " + rotInfo.ptsStr); // show point coordinates
show(" path 'd' string: " + rotInfo.dStr); // show 'd' string needed to draw it
show(" sum of (coloured line lengths squared) = " + sumLensSqrd); // the 'lsq sum'
rotNum += 1; // analyze the next rotation of points
} else { // once all the rotations have been analyzed individually...
linePaths.forEach(function(linePath) {linePath.remove();}); // erase any coloured lines
show(" ");
show("BEST ROTATION, i.e. rotation with lowest sum of (lengths squared): #" + rotNumOfMin);
// show which rotation to use
show("Use the shape based on this rotation of points for morphing");
$("button").off("click");
}
});
function getSegs(path) {
var absCubDStr = Snap.path.toCubic(Snap.path.toAbsolute(path.attr("d")));
return Snap.parsePathString(absCubDStr).map(function(seg, segNum) {
return {x: seg[segNum ? 5 : 1], y: seg[segNum ? 6 : 2], seg: seg.toString()};
});
}
function getRotInfo(rotNum) {
var ptsStr = "";
for (var segNum = 0; segNum < numSegs; segNum += 1) {
var oldSegNum = rotNum + segNum;
if (segNum === 0) {
var dStr = "M" + staSegs[oldSegNum].x + "," + staSegs[oldSegNum].y;
} else {
if (oldSegNum >= numSegs) oldSegNum -= numPts;
dStr += staSegs[oldSegNum].seg;
}
if (segNum !== (numSegs - 1)) {
ptsStr += "(" + staSegs[oldSegNum].x + "," + staSegs[oldSegNum].y + "), ";
}
}
ptsStr = ptsStr.slice(0, ptsStr.length - 2);
return {ptsStr: ptsStr, dStr: dStr};
}
function show(msg) {
var m = document.createElement('pre');
m.innerHTML = msg;
document.body.appendChild(m);
}
pre {
margin: 0;
padding: 0;
}
<script src="//cdn.jsdelivr.net/snap.svg/0.4.1/snap.svg-min.js"></script>
<p>Best viewed on full page</p>
<p>Coloured lines show morph trajectories for the points for that particular rotation of points. The algorithm seeks to optimize those trajectories, essentially trying to find the "shortest" cumulative routes.</p>
<p>The order of points can be seen by following the colour of the lines: red, blue, green, orange (at least when this was originally written), repeating if there are more than 4 points.</p>
<p><button>Click to show rotation of points on top shape</button></p>
I'm trying to represent a Pareto chart with Highcharts, as you can see here.
The horizontal line shows the 80% value, but now I wanted to display a vertical line where that horizontal 80% line intersects with the "Acumulated" chart series.
This is an example of what I'm trying to achieve:
Is there a way to do it?
Another option would be to get the "x" value of the "Acumulated" spline where it's "y" value is "80", that way I could then draw the line manually.
Is this even possible with the Highcharts API?
I know that it's possible to get the values of a point in a series, but that isn't enough in this case:
var point = chart.get('accumulated').data[2];
I have find it for 80:20 calculation.
First I have find the first value in series from Spline data which greater than or equal to 80.
i.e. >= 80
Suppose it is DataX
Then find out the that index in array plus one for DataX.
i.e. DataX location is DataIndex = index+1
(as array start from 0th calculation need plus one)
formula is
DataX : DataIndex :: 80: ?
let the question mark is xIndexOf80
then xIndexOf80 = (DataIndex *80)/(DataX ).
xIndexOf80 is nothing but position of 80 on X axis.
which gives you exact marks on X-Axis
function findInetrSectionPoint(arrSplineData) {
var intLen = arrSplineData.length;
for (var index = 0; index < intLen; index++) {
if (arrSplineData[index] >= 80) {
interSectPoint = ((index + 1) * 80) / arrSplineData[index] - 1;
break;
}
}
return interSectPoint;
}
Here is the Plunker
You can calculate position of 80% point and then use http://api.highcharts.com/highstock#Renderer rect. Apart from that you can also check this option http://api.highcharts.com/highstock#Axis.addPlotLine() / http://api.highcharts.com/highstock#yAxis.plotLines
I trying to create a points calculating system with javascript, but the problem is with the mathematical part. I have saved on the server the points number, and based on that number I want to decide the level. Sorry for my bad english, I cant explain very well :D. I want something like: level 1 need 0 points
level 2 needs 100 points
level 3 needs 240 points
level 4 needs 420 points
level 5 needs 640 points
and so on....
I need a mathematical function to calculate each level with it. Something that if I know the level to calculate the points needed, and if I know only the points to calculate the level.
To generate the series you've provided use:
function getPoints(level)
{
return 20*(level-1)*(level+3);
}
To get the level from the points is a bit more tricky, you need to invert the above formula using the quadratic formula and then take the positive solution:
function getLevel(points)
{
var level = -1 + Math.sqrt(4 + points/20);
// Round down to nearest level
return Math.floor(level);
}
Also, in the future try and make your questions clearer. As you can see three people (at least) misunderstood your question - it wasn't clear that you set of levels was a mathematical series.
var levels = {
1: 0,
2: 100,
3: 240,
4: 420,
5: 640}
function get_level(points){
for (level in levels){
if (points < levels[level]){
return level - 1;
}
}
}
This simply takes the levels hash and itenerates through the levels, until the points is higher than the level's minimum, returning the last level.
ummm, I have a vague idea of what you're going for
var levels = [0, 100, 240, 420, 640];
function GetLevel(points)
{
for(i == levels.length - 1; i >= 0; i--)
{
if (points >= levels[i]) return i + 1;
}
}
points to next level
function PointsToNextLevel(currentPoints)
{
var level = GetLevel(currentPoints);
if (level == levels.length) return 0;
return levels[level - 1] - currentPoints;
}
this function should solve your problem and, to me, seems very easy to understand:
function getLevel(points)
{
var levels = [0,100, 240, 420, 640];
var maxLevel = levels.length;
var i;
for (i=0;i<maxLevel;i++) {
if (levels[i]>points) return i;
}
return maxLevel;
}