Related
Ok, so I'm trying to code a Rectangle with multiple triangle strips joined together. according to:
http://www.corehtml5.com/trianglestripfundamentals.php
You need to take care of the triangles wrapping around when you have more than one row. However using the suggested algorithm in my code example I'm getting incorrect indice results.
Here is my example, with outputs.
I've tried copy/pasting the suggested algorithm but it doesn't seem to be returning correct results.
// Create the Index Points for the buffer array.
var rows=2;
var cols=3;
var grid = rows*cols;
var offset;
var pos = [];
var index = 0;
var mpOffset = 1;
for (var row = 0; row <= rows; ++row)
{
offsetY = row * (mpOffset / rows);
for (var col = 0; col <= cols; ++col)
{
offsetX = col * (mpOffset / cols);
pos[index+0] = (offsetX);
pos[index+1] = (offsetY);
index+=2;
}
}
log.info("pos="+JSON.stringify(pos)); // <-- Correct working good.
log.info("pos.length="+pos.length);
function initializeGrid(cols,rows)
{
var trianglestrip = [];
var RCvertices=2*cols*(rows-1);
var TSvertices=2*cols*(rows-1)+2*(rows-2);
var numVertices=TSvertices;
var j=0;
for(var i = 1; i <= RCvertices; i += 2)
{
trianglestrip[ j ] = (1 +i)/2;
trianglestrip[ j +1 ] = (cols*2 + i + 1) / 2;
if( trianglestrip[ j +1 ] % cols == 0)
{
if( trianglestrip[ j +1 ] != cols && trianglestrip[ j +1 ] != cols*rows )
{
trianglestrip[ j +2 ] = trianglestrip[ j +1 ];
trianglestrip[ j +3 ] = (1 + i + 2) / 2;
j += 2;
}
}
j += 2;
}
return trianglestrip;
}
var triStrip = initializeGrid(cols,rows);
log.info("triStrip="+JSON.stringify(triStrip)); // <-- Bad Not working.
log.info("triStrip.length="+triStrip.length);
// Generating the actual Point strip.
var actualStrip = [];
for (var i = 0 ; i < triStrip.length; ++i)
{
actualStrip.push(pos[(triStrip[i]-1)*2+0]);
actualStrip.push(pos[(triStrip[i]-1)*2+1]);
}
log.info("actualStrip="+JSON.stringify(actualStrip));
log.info("actualStrip.length="+actualStrip.length);
Indices should be:
1, 5, 2, 6, 3, 7, 4, 8, 8, 5, 5, 9, 6, 10, 7, 11, 8, 12
I ended up re-creating the function to calculate the triangle strip indices. Have not fully tested it but it can re-create the 3x2 grid in the example from the website.
Here is the code:
// This calculates the triangle points in a rectangular triangle strip.
// Used for 3D Webgl texture mapping.
// Copyright Joshua Langley 2019.
var rows=2;
var cols=3;
var grid = rows*cols;
var offset;
var pos = [];
var index = 0;
var mpOffset = 1;
var offsetX, offsetY;
for (var row = 0; row <= rows; ++row)
{
offsetY = row * (mpOffset / rows);
for (var col = 0; col <= cols; ++col)
{
offsetX = col * (mpOffset / cols);
pos[index+0] = (offsetX);
pos[index+1] = (offsetY);
index+=2;
}
}
log.info("pos="+JSON.stringify(pos));
log.info("pos.length="+pos.length);
var rows=rows+1,cols=cols+1; // Important this counting Points not Squares.
var grid = rows*cols;
var offset;
var indices = [];
var indice = 0;
var offset;
var doublePoints = false;
var tPoint, bPoint;
for (var row = 0; row < rows; ++row)
{
for (var col = 0; col < (cols-1); ++col)
{
offset = row * rows + col;
tPoint = offset+1;
bPoint = offset+cols+1;
if (bPoint > grid)
continue;
indices.push(tPoint);
indices.push(bPoint);
if (offset > 0 && (bPoint+1) < grid && (offset+1) % cols == 0)
{
indices.push(bPoint);
indices.push(tPoint+1);
}
}
}
log.info("indices="+JSON.stringify(indices)); // Expected Result
log.info("indices.length="+indices.length);
var actualStrip = [];
for (var i = 0 ; i < indices.length; ++i)
{
actualStrip.push(pos[(indices[i]-1)*2+0]);
actualStrip.push(pos[(indices[i]-1)*2+1]);
}
log.info("actualStrip="+JSON.stringify(actualStrip));
log.info("actualStrip.length="+actualStrip.length);
To create a path in pathfinding3d.js, we have to add all nodes and their neighbors.
var nodes = [
new PF.Node(0,0,0),
new PF.Node(1,0,0),
new PF.Node(2,0,0),
];
nodes[0].neighbors.push(nodes[1]);
nodes[1].neighbors.push(nodes[0],nodes[2]);
nodes[2].neighbors.push(nodes[1]);
var finder = new PF.AStarFinder();
var path = finder.findPath(nodes[0], nodes[2], nodes);
The problem is, if I want to create a large 3d mesh of node, to create a path I need to push neighbour in each node to create a path.
Is there another way to do this? Can I create path from one point to another distant just by adding the origin node and destination node? Such as createPath(node(1,2,3), node(4,5,6) and the path between them create the path.
Or is there another solution more fitting than this?
I've managed to find a solution. First, I create three function to help me create layout, make all node connected, and, then, make only the necessary node connected using the pathfinding3d.js to calculate which node it need to connect based on proposed connected nodes. Here are the function:
function create3DLayout(x, y, z) {
let layout = new Array(x);
for (let i = 0; i < x; i++) {
layout[i] = new Array(y);
for (let j = 0; j < y; j++) {
layout[i][j] = new Array(z);
for (let k = 0; k < z; k++) {
layout[i][j][k] = new PF.Node(i, j, k);
}
}
}
return layout;
}
function createAllWalkable(layout) {
for (let i = 0; i < layout.length; i++) {
for (let j = 0; j < layout[i].length; j++) {
for (let k = 0; k < layout[i][j].length; k++) {
let mInit = (i + -1 >= 0) ? -1 : 0;
let mEnd = (i + 1 < layout.length) ? 1 : 0;
for (let m = mInit; m <= mEnd; m++) {
let nInit = (j + -1 >= 0) ? -1 : 0;
let nEnd = (j + 1 < layout[i].length) ? 1 : 0;
for (let n = nInit; n <= nEnd; n++) {
let oInit = (k + -1 >= 0) ? -1 : 0;
let oEnd = (k + 1 < layout[i][j].length) ? 1 : 0;
for (let o = oInit; o <= oEnd; o++) {
let xt = m + i;
let yt = n + j;
let zt = o + k;
if (layout[xt][yt][zt] != layout[i][j][k]) {
layout[i][j][k].neighbors.push(layout[xt][yt][zt]);
}
}
}
}
}
}
}
}
function createWalkablePath(layout, nodeStart, nodeEnd) {
// Create building
let walkablelayout = create3DLayout(layout.length, layout[0].length, layout[0][0].length);
// Create path to every corner of building
createAllWalkable(walkablelayout);
let startPath = walkablelayout[nodeStart.x][nodeStart.y][nodeStart.z];
let endPath = walkablelayout[nodeEnd.x][nodeEnd.y][nodeEnd.z];
let explorer = new PF.AStarFinder();
let exploredPath = explorer.findPath(startPath, endPath, walkablelayout);
for (let i = 0; i < exploredPath.length - 1; i++) {
layout[exploredPath[i][0]][exploredPath[i][1]][exploredPath[i][2]].neighbors.push(layout[exploredPath[i + 1][0]][exploredPath[i + 1][1]][exploredPath[i + 1][2]]);
layout[exploredPath[i + 1][0]][exploredPath[i + 1][1]][exploredPath[i + 1][2]].neighbors.push(layout[exploredPath[i][0]][exploredPath[i][1]][exploredPath[i][2]]);
}
}
Then, I'll do the calculation:
var nodes = create3DLayout(26, 26, 3);
createWalkablePath(nodes, nodes[7][14][0], nodes[9][17][0]);
createWalkablePath(nodes, nodes[0][0][0], nodes[25][25][2]);
createWalkablePath(nodes, nodes[0][25][0], nodes[9][17][0]);
createWalkablePath(nodes, nodes[1][15][1], nodes[9][17][0]);
createWalkablePath(nodes, nodes[20][25][1], nodes[9][17][0]);
// Create finder
var finder = new PF.AStarFinder();
// origin
var startNode = nodes[14][14][2];
console.log(startNode);
// Destination
var endNode = nodes[17][17][2];
console.log(endNode);
var path;
// Find path
path = finder.findPath(startNode, endNode, nodes);
console.log(path);
Hope this helps anyone who face same problem.
The problems asks "given a string, find the longest non-repeating sub-string without repeating characters". I am a little stumped why returning my code is not working for the string "dvdf" for example. Here is my code :
function lengthOfLongestSubstring(check) {
var letters = check.split("");
var max = 0;
var result = [];
for (var i = 0; i < letters.length; i++) {
var start = i
if (result.indexOf(letters[i]) === -1) {
result.push(letters[i])
} else {
i = i - 1
result = []
}
if (max === 0 || max < result.length) {
max = result.length
}
}
return max
}
This implementation gives the correct result for "dvdf".
It adds characters to current_string while there is no duplicate. When you find a duplicate cut current_string to the point of the duplicate. max is the max length current_string had at any time. This logic seems correct to me so I think it's correct.
function lengthOfLongestSubstring(string) {
var max = 0, current_string = "", i, char, pos;
for (i = 0; i < string.length; i += 1) {
char = string.charAt(i);
pos = current_string.indexOf(char);
if (pos !== -1) {
// cut "dv" to "v" when you see another "d"
current_string = current_string.substr(pos + 1);
}
current_string += char;
max = Math.max(max, current_string.length);
}
return max;
}
lengthOfLongestSubstring("dvdf"); // 3
The value of current_string in each round is "", "d", "dv", "vd", "vdf".
By replacing the result array with a map storing the last index for each encountered character, you can modify the loop body to jump back to one after the last index of an identical character and continue your search from there instead of just restarting from the current position via currently i = i - 1 which fails in cases such as 'dvdf':
Below is your code with changes to accommodate a map in place of an array:
function lengthOfLongestSubstring(check) {
var letters = check.split("");
var max = 0;
var result = new Map();
var start = 0;
for (var i = 0; i < letters.length; i++) {
if (!result.has(letters[i])) {
result.set(letters[i], i);
} else {
i = result.get(letters[i]);
result.clear();
}
if (max < result.size) {
max = result.size;
}
}
return max;
}
// Example:
console.log(lengthOfLongestSubstring("dvdf")); // 3
Here's a solution using Sliding window and HashMap.
var lengthOfLongestSubstring = function(str) {
if (!!!str.length || typeof str !== 'string') return 0;
if (str.length == 1) return 1;
let hashTable = {};
let longestSubstringLength = 0;
let start = 0;
for (let i = 0; i < str.length; i++) {
if (hashTable[str[i]] !== undefined && hashTable[str[i]] >= start) {
start = hashTable[str[i]] + 1;
}
hashTable[str[i]] = i;
longestSubstringLength = Math.max(longestSubstringLength, (i - start + 1))
}
return longestSubstringLength;
}
I figured out an easier solution:
function longestSubstring(str) {
let left = 0;
let max = 0;
let result = new Set();
for (let r = 0; r < str.length; r++) {
//The code will check for an existing item on the set
// If found, all the previously saved items will be deleted
// the set will return to being empty
while (result.has(str[r])) {
result.delete(str[left]);
left += 1;
}
result.add(str[r]);
max = Math.max(max, r - left + 1);
}
console.log(result);
return max;
}
console.log(longestSubstring('abcabccbc')); //3
Today (January 7th, 2021) this was the Leetcode question of the day. I initially used a solution very similar to the selected answer. Performance was okay but after reviewing the answer solution documentation I rewrote my answer using the sliding window technique (examples were only in Java and Python) since I was curious about how much of a performance improvement this would result in. It is slightly more performant (144ms versus 160ms) and has a lower memory footprint (42mb versus 44.9mb):
function lengthOfLongestSubstring(s: string): number {
let stringLength = s.length;
let maxLength = 0;
const charMap = new Map();
let pos = 0;
for (let i = 0; i < stringLength; i++) {
if (charMap.has(s[i])) {
pos = Math.max(charMap.get(s[i]), pos);
}
maxLength = Math.max(maxLength, i - pos + 1);
charMap.set(s[i], i + 1);
}
return maxLength;
}
console.log(lengthOfLongestSubstring("dvdf"));
Try this:
function lengthOfLongestSubstring (str) {
const map = new Map();
let max = 0;
let left = 0;
for (let right = 0; right < str.length; right++) {
const char = str[right];
if (map.get(char) >= left) left = map.get(char) + 1;
else max = Math.max(max, right - left + 1);
map.set(char, right);
}
return max;
}
You can try this:
function lengthOfLongestSubstring(str) {
let longest = "";
for (let i = 0; i < str.length; i++) {
if (longest.includes(str[i])) {
return longest.length
} else {
longest += str[i];
}
}
return longest.length;
}
console.log(lengthOfLongestSubstring("abcabcbb"));
console.log(lengthOfLongestSubstring("bbbbb"));
console.log(lengthOfLongestSubstring("abcdef"));
console.log(lengthOfLongestSubstring(""));
reset i to i -1 is incorrect. you need another loop inside the for loop. you try something like this (i didn't check the index carefully).
function lengthOfLongestSubstring(check){
var letters = check.split("");
var max = 0;
for (var i = 0; i < letters.length; i++) {
var result = [];
var j = i;
for(;j < letters.length; j++) {
if (result.indexOf(letters[j]) === -1) {
result.push(letters[j]);
} else {
break;
}
}
if(j - i > max) {
max = j - i;
}
}
return max;
}
You can try sliding window pattern to solve this problem.
function lengthOfLongestSubstring(str) {
let longest = 0;
let longestStr = "";
let seen = {};
let start = 0;
let next = 0;
while (next < str.length) {
// Take current character from string
let char = str[next];
// If current character is already present in map
if (seen[char]) {
// Check if start index is greater than current character's last index
start = Math.max(start, seen[char]);
}
// If new substring is longer than older
if (longest < next - start + 1) {
longest = next - start + 1;
// Take slice of longer substring
longestStr = str.slice(start, next + 1);
}
// Update current characters index
seen[char] = next + 1;
// Move to next character
next++;
}
console.log(str, "->", longestStr, "->", longest);
return longest;
}
lengthOfLongestSubstring("dvdfvev");
lengthOfLongestSubstring("hello");
lengthOfLongestSubstring("1212312344");
Find Longest Unique Substring using Map Method
var str = "aaabcbdeaf";
var start = 0;
var map = new Map();
var maxLength = 0;
var longStr = '';
for(next =0; next< str.length ; next++){
if(map.has(str[next])){
map.set(str[next],map.get(str[next])+1);
start = Math.max(start,map.get(str[next]));
}
if(maxLength < next-start+1){
maxLength = next-start+1;
longStr = str.slice(start,next+1);
}
map.set(str[next],next);
}
console.log(longStr);
You can try something like that:
function maxSubstring(s) {
const array = []
const lengthS = s.length
const pusher = (value) => {
if (value !== '') {
if (array.length > 0) {
if (array.indexOf(value) === -1) {
array.push(value)
}
} else {
array.push(value)
}
}
}
pusher(s)
for (const [index, value] of s.split('').entries()) {
let length = lengthS
let string = s
const indexO = s.indexOf(value)
pusher(value)
while (length > indexO) {
pusher(string.slice(index-1, length + 1))
length = --length
}
string = s.slice(index, lengthS)
}
array.sort()
return array.pop()
}
console.log(maxSubstring('banana'))
console.log(maxSubstring('fgjashore'))
console.log(maxSubstring('xyzabcd'))
Find Longest unique substring without using MAP(). Just simple slice().
The same can be used to return longest unique string.
Just replace "return max => return str"
const string = "dvdf";
var lengthOfLongestSubstring = function() {
if(string.length == 1) return 1;
if(string.length == 0) return 0;
let max = 0,i = 0, str = "";
while(i < string.length){
const index = str.indexOf(string.charAt(i));
if(index > -1) {
// s = "fiterm".slice(1,4) => ite
str = str.slice(index + 1, string.length);
}
str += string.charAt(i);
max = Math.max(str.length, max);
i++;
}
return max;
};
Logest unqiue substring:
function lengthOfLongestSubstring(s) {
if(s.length < 2) {
return s.length;
}
let longestLength = 1;
let currentStr = '';
for(let i=0 ; i < s.length ; i++){
if(currentStr.includes(s.charAt(i))){
let firstSeen = currentStr.indexOf(s.charAt(i));
currentStr = currentStr.substring(firstSeen+1,currentStr.length);
}
currentStr += s.charAt(i);
longestLength = Math.max(currentStr.length,longestLength);
}
return longestLength;
};
One liner with reduce method.
const subStrOfUniqueChar = str => [...str].reduce((p,c) => ( p.includes(c) ? (p += c, p.substr(p.indexOf(c)+1)) : p += c),'');
console.log(subStrOfUniqueChar('dvdf').length);
function lengthOfLongestSubstring(s: string): number {
const arr = s.split("");
let longest = 0;
const set: Set<string> = new Set();
for (let i = 0; i < arr.length; i++) {
set.add(arr[i]);
let tryIndex = i + 1;
while (arr[tryIndex] && !set.has(arr[tryIndex])) {
set.add(arr[tryIndex]);
tryIndex++;
}
if (set.size > longest) {
longest = set.size;
}
set.clear();
}
return longest;
}
I wanted to toss my hat in this ring because I feel like I've found a pretty creative solution to this. No if/else blocks are needed as the substring.indexOf() will attempt to find the matching string character in the array and delete the indexes of the array up to, and including, the match (+1). If an indexOf() call finds no match it will return a -1, which added to +1 becomes a .splice(0,0) which will remove nothing. The final Math check factors in the last character addition in the loop to determine which outcome is higher.
const findSubstring = string => {
let substring = [];
let maxCount = 0;
for (let i = 0; i < string.length; i++) {
maxCount = Math.max(substring.length, maxCount);
substring.splice(0, substring.indexOf(string[i]) + 1);
substring.push(string[i]);
}
maxCount = Math.max(substring.length, maxCount);
return maxCount;
}
uses sliding window concept
function lengthOfLongestSubstring(s) {
var letters = s.split("");
var subStr = "";
var result = [];
var len = 0;
let maxLen = 0;
for (var i = 0; i < letters.length; i++) {
const position = result.indexOf(letters[i]);
if (position === -1) {
result.push(letters[i]);
len += 1;
} else if (letters[i]) {
result = result.splice(position + 1);
len = result.length + 1;
result.push(letters[i]);
}
maxLen = len > maxLen ? len : maxLen;
}
return maxLen;
}
console.log(lengthOfLongestSubstring(" "));
Sliding Window Technique O(n)
you can use hash or Map in
loop through string char
Maintain dictionary of unique char
if char exist in memory take clear hash update the count in longest variable and clear count
start from first repeated char + 1 again.
var lengthOfLongestSubstring = function(s) {
if(s.length<2) return s.length;
let longest = 0;
let count=0;
let hash={}
for (let i = 0; i < s.length; i++) {
//If char exist in hash
if(hash[s[i]]!=undefined){
i=hash[s[i]];
hash={}
longest = Math.max(longest, count);
count = 0;
}else{
hash[s[i]]=i
count = count+1;
}
}
return Math.max(longest, count);
};
console.log(lengthOfLongestSubstring("abcabcbb"))
console.log(lengthOfLongestSubstring("au"))
I have quite complicated array which I need to transform to specific format. The array looks like this:
arr = [["name1",51,1,"code1",3],["name2",52,0,"code2",4,"code3",6],["name3",51,2,"code4",3,"code5",6,"code6",1],["name4",55,5,"code7",7,"code8",1],["name5",54,2,"code9",5,"code10",8]];
Each array in my output need contains only 5 values - 3 first values always will be the same like in input. The next 2 values should contain code and the lowest value from the rest of the array. So this case output will look like this:
output = [["name1",51,1,"code1",3],["name2",52,0,"code2",4],["name3",51,2,"code6",1],["name4",55,5,"code8",1],["name5",54,2,"code9",5]];
For start I think the best is use loop for and if instruction, but I don't know how to cope with this later on.
for (i=0; i<arr.length; i++) {
if (arr[i]>5) {
//dont know what to put here
}
}
My solution:
arr = [
["name1",51,1,"code1",3],
["name2",52,0,"code2",4,"code3",6],
["name3",51,2,"code4",3,"code5",6,"code6",1],
["name4",55,5,"code7",7,"code8",1],
["name5",54,2,"code9",5,"code10",8]
];
function process_array(in_array) {
var output = [];
/* check each element in array */
in_array.forEach(function(sub_array){
/* store new sub array here*/
var last_sub_out = [];
var code;
var lowest_num = Number.MAX_VALUE;
/* check sub array
#value is value of sub_array
#index is index of that value.
*/
sub_array.forEach(function(value, index){
/* add first 3 values */
if(index < 3) {
last_sub_out.push( value );
return;
}
/* checking only numbers(even index: 4,6,8, ...) */
if(index % 2 == 0) {
if(value < lowest_num) {
code = sub_array[index - 1];
lowest_num = value;
}
}
});
/* add found code with lowest number */
last_sub_out.push(code, lowest_num);
output.push( last_sub_out );
/* LOG */
document.write(last_sub_out.join(', ') + "</br>");
});
return output;
}
var out = process_array(arr);
var arr = [["name1",51,1,"code1",3],["name2",52,0,"code2",4,"code3",6],["name3",51,2,"code4",3,"code5",6,"code6",1],["name4",55,5,"code7",7,"code8",1],["name5",54,2,"code9",5,"code10",8]];
var out=[];
for (i=0; i < arr.length; i++) {
if (arr[i].length>5) {
out[i] = [arr[i][0], arr[i][1], arr[i][2]];
c = [arr[i][3], arr[i][4]];
for (j=0; j < (arr[i].length - 5)/2; j++){
if (c[1] > arr[i][6+2*j]){
c = [arr[i][5+2*j], arr[i][6+2*j]];
}
}
out[i][3] = c[0]; out[i][4] = c[1];
} else {
out[i] = arr[i]
}
}
Try:
var arr = [["name1",51,1,"code1",3],["name2",52,0,"code2",4,"code3",6],["name3",51,2,"code4",3,"code5",6,"code6",1],["name4",55,5,"code7",7,"code8",1],["name5",54,2,"code9",5,"code10",8]];
var output = [], startIndex = 3, i = 0;
while(i < arr.length){
var item = arr[i++], j = startIndex, count = 0, min = Infinity, code;
while(j < item.length){
count++ % 2 && item[j] < min && (min = item[j], code = item[j-1]);
j++
}
item.splice(startIndex, item.length, code, min);
output.push(item)
}
document.write("<pre>" + JSON.stringify(output, null, 4) + "<pre>");
I need help fixing my existing code to accomplish what I am trying to do.
with the following sample data:
var SAMPLE_DATA = [{start: 30, end: 150}, {start: 540, end: 600}, {start: 560, end: 620}, {start: 610, end: 670}];
I need to do the following:
iterate through each sample object
determine if the current objects range (obj.start:obj.end) overlaps with any other object ranges.
record the total number of overlaps for that object into totalSlots property
determine the "index" of the object (used for it's left-to-right positioning)
mockup of what I am trying to accomplish:
As you can see in the mockup, slotIndex is used to determine the left-to-right ordering of the display. totalSlots is how many objects it shares space with (1 meaning it is the only object). 100 / totalSlots tells me how wide the square can be (i.e. totalSlots=2, means it is 100 / 2, or 50% container width).
Current Output from my code
Obj[0] slotIndex=0, totalSlots=0
Obj[1] slotIndex=1, totalSlots=1
Obj[2] slotIndex=1, totalSlots=2
Obj[3] slotIndex=0, totalSlots=1
expected/desired output from my code:
Obj[0] slotIndex=0, totalSlots=0
Obj[1] slotIndex=0, totalSlots=1
Obj[2] slotIndex=1, totalSlots=2
Obj[3] slotIndex=0, totalSlots=1
the code:
detectSlots: function(oldEventArr) {
oldEventArr.sort(this.eventSorter);
var newEventArr = [],
n = oldEventArr.length;
for (var i = 0; i < n; i++) {
var currObj = oldEventArr[i];
if ('undefined' == typeof currObj.totalSlots) {
currObj.slotIndex = 0;
currObj.totalSlots = 0;
}
for (var x = 0; x < n; x++) {
if (i == x) {
continue;
}
var nextObj = oldEventArr[x];
if (currObj.start <= nextObj.end && nextObj.start <= currObj.end) {
currObj.totalSlots++;
nextObj.slotIndex++;
}
}
newEventArr.push(currObj);
}
return newEventArr;
}
Please help me figure out what is going wrong in my code. I'm about 90% sure the problem lies in the if(currObj.start <= nextObj.end && nextObj.start <= currObj.end) statement where I am assigning/incrementing the values but I could use an extra set of eyes on this.
The slotIndex value can be calculated by using graph colouring algorithm. Note that brute force algorithm is exponential in time and will only be a viable solution for a small set of overlapping slots. Other algorithms are heuristics and you won't be guaranteed the least slot possible.
Here is an example of heuristic for your problem:
...
// init
var newEventArr = [], n = oldEventArr.length;
for (var i = 0; i < n; i+=1) {
var currObj = oldEventArr[i];
newEventArr.push({"start":currObj.start,"end":currObj.end,"slotIndex":undefined,"totalSlots":0});
}
var link = {};
// create link lists and totals
for (var i = 0; i < n; i+=1) {
var currObj = newEventArr[i];
if (!link.hasOwnProperty(""+i))
link[""+i] = {};
for (var j = i+1; j < n; j+=1) {
var nextObj = newEventArr[j];
var not_overlap = (currObj.end <= nextObj.start || nextObj.end <= currObj.start);
if (!not_overlap) {
currObj.totalSlots+=1;
nextObj.totalSlots+=1;
link[""+i][""+j] = 1;
if (!link.hasOwnProperty(""+j))
link[""+j] = {};
link[""+j][""+i] = 1;
}
}
}
var arrities = [];
for (var i = 0; i < n; i+=1) {
arrities.push( {"arrity":newEventArr[i].totalSlots, "indx":i} );
}
// sort by arrities [a better solution is using a priority queue]
for (var i = 0; i < n-1; i+=1) {
var current_arrity = -1, indx = -1;
for (var j = i; j < n; j+=1) {
if (arrities[j].arrity > current_arrity) {
indx = j;
current_arrity = arrities[j].arrity;
}
}
var temp = arrities[i];
arrities[i] = arrities[indx];
arrities[indx] = temp;
}
for (var i = 0; i < n; i+=1) {
var nodeIndex = arrities[i].indx;
// init used colors
var colors = [];
for (var j = 0; j < n; j+=1) {
colors.push(0);
}
//find used colors on links
for (var k in link[""+nodeIndex]) {
var color = newEventArr[k].slotIndex;
if (color || color === 0)
colors[color] += 1;
}
//find the first unused color
for (var j = 0; j < n; j+=1) {
if (colors[j] <= 0) {
// color the node
newEventArr[nodeIndex].slotIndex = j;
break;
}
}
}
return newEventArr;
...
like this
var not_overlap = (currObj.end <= nextObj.start || nextObj.end <= currObj.start);
if (!not_overlap) { ...
or
var overlap = (currObj.end > nextObj.start && nextObj.end < currObj.start);
if (overlap) { ...