This question already has an answer here:
Javascript unknown error
(1 answer)
Closed 8 years ago.
I am having a problem with my code, I have not been able to figure it out for the past 2 days.
/**
*
*///function 7
/**
* returns the number of times that pattern occurs in string
*/
function score(string,pattern) {
var v = string.toUpperCase();
var s = pattern.toUpperCase();
var result = [];
for (var i = 0; i < string.length; i++) {
var index = v.indexOf(s, i);
if (index != -1) {
result[result.length]=index;
i = index;
}
}
return result.length;
}
/**
* returns an array of records of the form {trackTitle: ..., trackLyrics: ..., trackScore: ...} derived from web.
* Each record contains the track title, track lyrics and pattern score of its corresponding content.
*
*
*
*/
//FUNCTION 9
function urlScores(music, pattern) {
var scoresArray = [];
for(var i = 0; i < music.length; i++) {
for(var j = 0; j < music[i].tracks.length; j++){
var itemScore = score(music[i].tracks[j].title, pattern) + score(music[i].tracks[j].lyrics, pattern);
if (itemScore > 0) {
scoresArray[scoresArray.length] = ({indexOfTrack: j, trackTitle: music[i].tracks[j].title, trackLyrics: music[i].tracks[j].lyrics, trackScore: itemScore, album: music[i]});
}
itemScore = 0;
}
}
return scoresArray;
}
/**
* Sorts the result of urlScores() into descending order.
* Records with a score of zero are omitted.
*/
//FUNCTION 10
function rankedScores(music, pattern) {
var scoresArray = urlScores(music, pattern);
function swap(a, b) {
var temp = scoresArray[a];
scoresArray[a] = scoresArray[b];
scoresArray[b] = temp;
}
for(var i = 0; i < scoresArray.length; i++) {
for(var x = 0; x < scoresArray.length - 1; x++) {
if (scoresArray[x].score > scoresArray[x + 1].score) {
swap(x, x + 1);
}
}
}
alert(scoresArray);
}
When I run it with the following:
rankedScores(albums, "sparrow");
The albums variable is - http://pastebin.com/G25SxrwY
The error is the following -
[object Object],[object Object]
Thank you very much!
This line:
alert(scoresArray);
No good. You are telling the alert() to output a whole array, but it doesn't know how to output a whole array.
Create a loop to loop through scoresArray and output it that way.
Related
I am working with this problem: https://www.hackerrank.com/challenges/fraudulent-activity-notifications/
My code works almost fine, but for some test cases it fails, because of the large array (over 200000 items). I am spending hours trying to understand what I can do to improve the speed, but I cannot come out with a working solution, so 2 of my tests always fail for timeout and I am frustrated trying to pass this test.
I think I cannot avoid the first loop and also the loop in sort, but cannot think of a faster way.
The problem described in the website is is this:
HackerLand National Bank has a simple policy for warning clients about possible fraudulent account activity. If the amount spent by a client on a particular day is greater than or equal to the client's median spending for a trailing number of days, they send the client a notification about potential fraud. The bank doesn't send the client any notifications until they have at least that trailing number of prior days' transaction data.
I solved it with this code
function getMedianNumber(arr) {
arr.sort((a, b) => a - b);
let medianNumber = 0;
const middle = Math.floor(arr.length / 2);
if (arr.length % 2 === 0) {
// Is even we get the median number
medianNumber = (arr[middle] + arr[middle - 1]) / 2;
} else {
const index = Math.floor(middle);
medianNumber = arr[index];
}
return medianNumber;
}
function activityNotifications(expenditure, d) {
let notifications = 0;
let len = expenditure.length - 1;
for (let i = len; i > d - 1; i--) {
let trailingDays = expenditure.slice(i - d, i);
let dayExpense = expenditure[i];
let median = getMedianNumber(trailingDays);
if (expenditure[i] >= median * 2) {
notifications++;
}
}
return notifications;
}
It only fails in 2 test cases because the passed array is huge and I get a timeout error.
expenditure.slice(i - d, i); is too expensive, you are making it O(n^2) by copying the array elements over each iteration. Use indexes over the original array to calculate median: getMedianNumber(arr, startIndex, endIndex).
function copy(a, ind) {
b = [];
for(var i = ind; i < a.length; ++i) {
b.push(a[i]);
}
return b;
}
function processData(input) {
//Enter your code here
var inputArr = input.split("\n");
var d = parseInt(inputArr[0].split(" ")[1]);
var arr = inputArr[1].split(" ").map(Number);
var countArray = [], sortedArray = [], tempArray = [], notifications = 0, median, count, middle;
for(var i = 0; i <= 200; ++i) {
countArray.push(0);
}
for(i = 0; i < d; ++i) {
countArray[arr[i]]++;
}
for(var j = 0; i < arr.length; ++i, ++j) {
tempArray = [], count = 0;
for(var k = 0; k <= 200; ++k) {
if(countArray[k] > 0) {
count += countArray[k];
tempArray.push({
no: k,
count: count
});
}
}
middle = {};
if((d&1) === 0) {
middle.index = count / 2;
} else {
middle.index = Math.ceil(count / 2);
}
var tempCount = 0;
for(k = 0; k < tempArray.length; ++k) {
if(tempArray[k].count === middle.index) {
if((d&1) === 0) {
median = (tempArray[k].no + tempArray[k + 1].no) / 2;
break;
} else {
median = tempArray[k].no;
break;
}
} else if(tempArray[k].count > middle.index) {
median = tempArray[k].no;
break;
}
}
//console.log(tempArray, median, arr[i]);
if(arr[i] >= (2 * median)) {
notifications++;
}
countArray[arr[i]]++;
countArray[arr[j]]--;
}
console.log(notifications);
}
process.stdin.resume();
process.stdin.setEncoding("ascii");
_input = "";
process.stdin.on("data", function (input) {
_input += input;
});
process.stdin.on("end", function () {
processData(_input);
});
I'm working on a script that creates random mathematical problems (simple questions). The problem is that there seems to be an infinite loop, and I can't figure out where or how my script can run without this part of the code.
https://codepen.io/abooo/pen/GyJKwP?editors=1010
var arr = [];
var lastArr = [];
while(lastArr.length<122){
arr.push('<br>'+Math.round(Math.random() * 10)+'+'+Math.round(Math.random() * 10)+'=');
lastArr=removeDuplicates(arr);
}
document.write(lastArr.join(' '));
alert(arr.length);
function removeDuplicates(arr){
let unique_array = []
for(let i = 0;i < arr.length; i++){
if(unique_array.indexOf(arr[i]) == -1){
unique_array.push(arr[i])
}
}
return unique_array
}
This is the working snippet without any infinity loop.
var arr = [];
while(arr.length < 121){
var randValue = '<br>'+Math.round(Math.random() * 10)+'+'+Math.round(Math.random() * 10)+'='
arr.push();
// Check duplicate elements before push
if ( arr.indexOf(randValue) == -1 ) arr.push(randValue);
}
document.write(arr.join(' '));
alert(arr.length);
It looks like you are trying to shuffle every possible outcome of adding two numbers from 0 to 10. Why not do that, rather than your attempt of "throw missiles into pidgeonholes and hope for the best"?
function generateArray(maxA, maxB) {
var arr = [],
a, b;
for (a = 0; a <= maxA; a++) {
for (b = 0; b <= maxB; b++) {
arr.push([a, b]);
}
}
return arr;
}
function shuffleArray(arr) {
// simple Fisher-Yates shuffle, modifies original array
var l = arr.length,
i, j, t;
for (i = l - 1; i > 0; i--) {
j = Math.floor(Math.random() * (i + 1));
t = arr[i];
arr[i] = arr[j];
arr[j] = t;
}
}
function outputArray(arr) {
var i, l = arr.length;
for (i = 0; i < l; i++) {
document.write("<br />" + arr[i][0] + " + " + arr[i][1] + " = ");
}
}
var arr = generateArray(10, 10);
shuffleArray(arr);
outputArray(arr);
The line Math.round(Math.random() * 10) will give you 11 possible outcomes (from 0 to 10). That means there are 11*11 non-duplicates lastArr can hold.
As mentioned in the comments, it does not only take a long time for every possibility to occur, it is also impossible for lastArr to be longer than 121 (11*11), which means your loop cannot end, due to the condition while(lastArr.length<122).
Besides that there are better ways to achieve the desired result, changing your code to this will make it work:
var arr = [];
var lastArr = [];
while(lastArr.length<121){ // Here I change 122 to 121
arr.push('<br>'+Math.round(Math.random() * 10)+'+'+Math.round(Math.random() * 10)+'=');
lastArr=removeDuplicates(arr);
}
document.write(lastArr.join(' '));
alert(arr.length);
function removeDuplicates(arr){
let unique_array = []
for(let i = 0;i < arr.length; i++){
if(unique_array.indexOf(arr[i]) == -1){
unique_array.push(arr[i])
}
}
return unique_array
}
I have written a function and called another function inside but my tests show that it is not time optimized. How can I make the following code faster?
function maxSum(arr, range) {
function sumAll(array1, myrange) {
var total = 0;
if (Array.isArray(myrange)) {
for (var i = myrange[0]; i <= myrange[1]; i++) {
total += array1[i];
}
return total;
} else return array1[myrange];
}
var mylist = [];
var l = range.length;
for (var n = 0; n < l; n++) {
mylist.push(sumAll(arr, range[n]));
}
return Math.max.apply(null, mylist);
}
Algorithmic optimization: create new array with cumulative sums from index 0 to every index
cumsum[0] = 0;
for (var i = 1; i <= arr.Length; i++) {
cumsum[i] = cumsum[i-1] + arr[i-1]
Now you don't need to calculate sums for every range - just get difference
sum for range (i..j) = cumsum[j+1] - cumsum[i];
in your terms:
function sumAll(array1, myrange) {
return cumsum[myrange[1]+1] - cumsum[myrange[0]];
}
example:
arr = [1,2,3,4]
cumsum = [0,1,3,6,10]
sum for range 1..2 = 6 - 1 = 5
P.S. If your array might be updated, consider Fenwick tree data structure
1) You can define the function sumAll outside of the function maxSum because every time you call maxSum the javascript engine is recreating a fresh new function sumAll.
2) You can define myrange[1] as a variable in the initialiser part to avoid javascript to look for myrange[1] at each iteration.
for (var i = myrange[0]; i <= myrange[1]; i++) {
total += array1[i];
}
become this:
for (var i = myrange[0], len = myrange[1]; i <= len; i++) {
total += array1[i];
}
Full working code based on #MBo's excellent optimization. This passes all the tests at https://www.codewars.com/kata/the-maximum-sum-value-of-ranges-challenge-version/train/javascript, which I gather is where this problem comes from.
function maxSum(arr, ranges) {
var max = null;
var sums = [];
var sofar = 0;
for (var i = 0; i <= arr.length; i++) {
sums[i] = sofar;
sofar += arr[i];
}
for (var i = 0; i < ranges.length; i++) {
var sum = sums[ranges[i][1]+1] - sums[ranges[i][0]];
if (max === null || sum > max) {
max = sum;
}
}
return max;
}
I am trying to count the number of permutations that do not contain consecutive letters. My code passes tests like 'aabb' (answer:8) and 'aab' (answer:2), but does not pass cases like 'abcdefa'(my answer: 2520; correct answer: 3600). Here's my code:
function permAlone(str) {
var totalPerm = 1;
var result = [];
//assign the first letter
for (var i = 0; i < str.length; i++) {
var firstNum = str[i];
var perm = firstNum;
//create an array from the remaining letters in the string
for (var k = 0; k < str.length; k++) {
if (k !== i) {
perm += str[k];
}
}
//Permutations: get the last letter and change its position by -1;
//Keep changing that letters's position by -1 until its index is 1;
//Then, take the last letter again and do the same thing;
//Keep doing the same thing until the total num of permutations of the number of items in the string -1 is reached (factorial of the number of items in the string -1 because we already established what the very first letter must be).
var permArr = perm.split("");
var j = permArr.length - 1;
var patternsLeft = totalNumPatterns(perm.length - 1);
while (patternsLeft > 0) {
var to = j - 1;
var subRes = permArr.move(j, to);
console.log(subRes);
if (noDoubleLettersPresent(subRes)) {
result.push([subRes]);
}
j -= 1;
if (j == 1) {
j = perm.length - 1;
}
patternsLeft--;
}
}
return result.length;
}
Array.prototype.move = function(from, to) {
this.splice(to, 0, (this.splice(from, 1))[0]);
return this.join("");
};
function totalNumPatterns(numOfRotatingItems) {
var iter = 1;
for (var q = numOfRotatingItems; q > 1; q--) {
iter *= q;
}
return iter;
}
function noDoubleLettersPresent(str) {
if (str.match(/(.)\1/g)) {
return false;
} else {
return true;
}
}
permAlone('abcdefa');
I think the problem was your permutation algorithm; where did you get that from? I tried it with a different one (after Filip Nguyen, adapted from his answer to this question) and it returns 3600 as expected.
function permAlone(str) {
var result = 0;
var fact = [1];
for (var i = 1; i <= str.length; i++) {
fact[i] = i * fact[i - 1];
}
for (var i = 0; i < fact[str.length]; i++) {
var perm = "";
var temp = str;
var code = i;
for (var pos = str.length; pos > 0; pos--) {
var sel = code / fact[pos - 1];
perm += temp.charAt(sel);
code = code % fact[pos - 1];
temp = temp.substring(0, sel) + temp.substring(sel + 1);
}
console.log(perm);
if (! perm.match(/(.)\1/g)) result++;
}
return result;
}
alert(permAlone('abcdefa'));
UPDATE: In response to a related question, I wrote an algorithm which doesn't just brute force all the permutations and then skips the ones with adjacent doubles, but uses a logical way to only generate the correct permutations. It's explained here: Permutations excluding repeated characters and expanded to include any number of repeats per character here: Generate all permutations of a list without adjacent equal elements
I agree with m69, the bug seems to be in how you are generating permutations. I got 3600 for 'abcdefa' by implementing a different algorithm for generating permutations. My solution is below. Since it uses recursion to generate the permutations the solution is not fast, however you may find the code easier to follow, if speed is not important.
The reason for having a separate function to generate the array index values in the permutations was to verify that the permutation code was working properly. Since there are duplicate values in the input strings it's harder to debug issues in the permutation algorithm.
// Simple helper function to compute all permutations of string indices
function permute_indices_helper(input) {
var result = [];
if (input.length == 0) {
return [[]];
}
for(var i = 0; i < input.length; i++) {
var head = input.splice(i, 1)[0];
var tails = permute_indices_helper(input);
for (var j = 0; j < tails.length; j++) {
tails[j].splice(0, 0, head);
result.push(tails[j]);
}
input.splice(i, 0, head); // check
}
return result;
};
// Given an array length, generate all permutations of possible indices
// for array of that length.
// Example: permute_indices(2) generates:
// [[0,1,2], [0,2,1], [1,0,2], ... , [2, 0, 1]]
function permute_indices(array_length) {
var result = [];
for (var i = 0; i < array_length; i++) {
result.push(i);
}
return permute_indices_helper(result);
}
// Rearrange letters of input string according to indices.
// Example: "car", [2, 1, 0]
// returns: "rac"
function rearrange_string(str, indices) {
var result = "";
for (var i = 0; i < indices.length; i++) {
var string_index = indices[i];
result += str[string_index];
}
return result;
}
function permAlone(str) {
var result = 0;
var permutation_indices = permute_indices(str.length);
for (var i = 0; i < permutation_indices.length; i++) {
var permuted_string = rearrange_string(str, permutation_indices[i]);
if (! permuted_string.match(/(.)\1/g)) result++;
}
return result;
}
You can see a working example on JSFiddle.
As an exercise, I'm trying to create a function that returns the palindromic numbers resulting from multiplying three-digit numbers. As far as I can tell, the function is running through numbers correctly, however, the resulting array is incorrect. I don't need the solution to the palindrome problem...just an idea of what I might be missing. Have I run into some limitation?
var palindromic = function() {
var a = [];
var res = [];
for (var i = 100; i < 1000; i++) {
a.push(i);
}
var ar = a.slice(0);
a.map(function(x) {
for (var j = 0; j < ar.length; j++) {
var result = x * ar[j];
if (result.toString() === result.toString().split("").reverse().join("")) {
res.push(result);
}
}
})
return res;
};
Pretty sure it's just trying to call console.log() 810,000 times. If you comment the console.log line, it works just fine.
var palindromic = function() {
var a = [];
var res = [];
for (var i = 100; i < 1000; i++) {
a.push(i);
}
var ar = a.slice(0);
a.map(function(x) {
for (var j = 0; j < ar.length; j++) {
var result = x * ar[j];
//console.log(x + " : " + ar[j] + ' = ' + result);
if (result.toString() === result.toString().split("").reverse().join("")) {
res.push(result);
}
}
});
return res;
};
console.log(palindromic());