Hackerrank: Frequency Queries Timeout - javascript

I know that there are plenty of similar questions on SO on this specific thing, but I have a solution that works for all test cases EXCEPT for one (it gets timed out). Is there anyway I can make my code run faster or more efficiently... or do I need to start all over?
My logic:
I create three arrays.
Whenever there is a new value, I add it to my data array. At the same time, I add a "1" to my frequency array. The positions should be the same.
Whenever it is the same value, I simply increase the frequency value for the corresponding value by 1.
Whenever I need to return a value to say whether or not my array has a value with frequency "_", I just indexOf my frequency and tada if it's there I return 0, else I return 1.
function freqQuery(queries) {
var answer = new Array(),
data = new Array(),
frequency = new Array();
for (var i = 0; i < queries.length; i++){
var test = queries[i][0];
if (test == 1) { // first test
var place = data.indexOf(queries[i][1]);
if (place == -1){
data.push(queries[i][1]);
frequency.push(1);
} else {
frequency[place]++;
}
} else if (test == 2) { // second test
var place = data.indexOf(queries[i][1]);
if ((place != -1) && (frequency[place] > 0)) {
frequency[place]--;
}
} else if (test == 3) { // third test
if (frequency.indexOf(queries[i][1]) == -1) {
answer.push(0);
} else {
answer.push(1);
}
}
}
return answer;
}
Link: Hackerrank

Task is in category "Dictionaries and Hashmaps". Instead of data and frequency arrays create object with keys being data values and keys being frequencies. Instead of using indexOf which is O(n) you would be doing frequenciesMap[queries[i][1]] which is O(1).

Related

Arrays in arrays, length always is 0, json not working

I try to create arrays in arrays and then forward it to JSON.
First problem, when i try to use a lista.length or something, console always return 0. I tried to overpass this problem and create another array, but now I have problem with JSON - always return [] - empty lista array.
var lista = [];
var licz = [];
function ListujBledy(value, where) {
var checked = document.getElementById(value).checked;
var desc;
if (value == "blad-tab") {
desc = "Nieprzeźroczysta lista graczy.";
} else if (value == "blad-tab1") {
desc = "Brak listy graczy na początkowym zrzucie ekranu.";
} else if (value == "blad-tab2") {
desc = "Brak listy graczy na końcowym zrzucie ekranu.";
}
if (checked == true) {
if (lista[where] == undefined) {
var temp = [];
temp[value] = desc;
lista[where] = temp;
licz[where] = 1;
} else if (licz[where] == 1) {
var temp = lista[where];
temp[value] = desc;
lista[where] = temp;
licz[where] = 2;
} else if (licz[where] == 2) {
var temp = lista[where];
temp[value] = desc;
lista[where] = temp;
licz[where] = 3;
}
} else {
if (licz[where] == 1) {
delete lista[where];
licz[where] = 0;
} else if (licz[where] == 2) {
delete lista[where][value];
licz[where] = 1;
} else if (licz[where] == 3) {
delete lista[where][value];
licz[where] = 2;
}
}
console.log(lista.length);
console.log(lista);
console.log(JSON.stringify(lista));
console.log("---------------------------------------------------------");
}
Console log from browser:
I don't have more ideas, I can't use lista[0], lista[1] etc. everything must be functional. Eveyrthing is taken from variables but everywhere I was looking for information about it, everybody using numbers in key or permanent keys.
Editied version of code:
I know that checked could have been better done, so I corrected it here.
https://jsfiddle.net/5vdgLtue/1/
The main problem is that even if I do this https://jsfiddle.net/5vdgLtue/0/ the array returns this element, but the length function says it is 0.
It looks like you might be starting out with javascript. Keep in mind that you haven't actually called the function at any point in your code. Is that the case or are you not sharing the full code you have run?
There is only one condition in which the array 'lista' could gain value: if 'check'== true and 'where' == undefined.
In that scenario, you declare the array 'temp' and declare temp[value]= desc. However, if 'value' contains a value different than "blad-tab", "blad-tab1" or "blad-tab2", 'desc' remains empty therefore temp[value] has a name but no value. You are then assigning a named valueless item to lista[where] which would explain why your console displays content but no length. btw, this would be easier if you named your variable something other than 'value' .
Problem is your selector points to the parent element. In jquery you could do this less code but assuming you're not using jQuery. Try something like:
function getDesc(chkboxName) {
var checkboxes = document.getElementsByName(chkboxName);
//or use getElementsbyClassName...
var checkboxesChecked = [];
// loop over them all
for (var i=0; i<checkboxes.length; i++) {
// And stick the checked ones onto an array...
if (checkboxes[i].checked) {
checkboxesChecked.push(checkboxes[i]);
}
}
for (var i=0; i<checkboxesChecked.length; i++) {
if (checkboxesChecked[i].value === "blad-tab") {
desc = "Nieprzeźroczysta lista graczy.";
} else if (checkboxesChecked[i].value === "blad-tab1") {
desc = "Brak listy graczy na początkowym zrzucie ekranu.";
} else if (checkboxesChecked[i].value === "blad-tab2") {
desc = "Brak listy graczy na końcowym zrzucie ekranu.";
}
}
return desc;
}
This should answer most of your questions.
In summary:
In javascript there are 2 types of arrays: standard arrays and associative arrays
[ ] - standard array - 0 based integer indexes only
{ } - associative array - javascript objects where keys can be any strings
What you are doing is using array in an associative manner. Basically, you are adding properties to your array objects, unlike a standard array where you would only assign values by zero-indexed numbers like temp[0]='something', lista[1]='some other thing' etc.
If you want the length of the key set of the array, then you can use Object.keys(lista).length. This should solve your problem.

need help understanding using an associative array to keep track of array value appearances

code:
method = function(a) {
//use associative array to keep track of the total number of appearances of a value
//in the array
var counts = [];
for(var i = 0; i <= a.length; i++) {
if(counts[a[i]] === undefined) {
//if the condition is looking for a[0],a[1],a[2],a[3],a[4],a[5] inside counts[] one value at a time and does not find them inside counts[] it will set each value to 1
counts[a[i]] = 1;
console.log(counts[a[i]]);
} else {
return true;
}
}
return false;
}
the js console logs 1x6
how can the condition see if a value inside counts[a[i]] has been repeated if all of the counts[a[i]] values are being set to 1 each iteration? wouldn't it always be comparing 1 to 1?
for example, if the a array is [1,2,3,4,5,2] and counts[a[1]](first int 2 in the array) is undefined and then set to 1, how would the condition know that counts[a[5]](second int 2 in the array) is the same value as counts[a[1]] and therefore it should return true?
perhaps I am misunderstanding whats going on.
I would appreciate any help. thanks
function counter(){
this.counts=[];
}
counter.prototype.add=function(a){
if(this.counts[a] === undefined) {
this.counts[a] = 1;
console.log(this.counts);
} else {
return true;
}
return false;
}
try this:
c= new counter();
c.counts;//[]
c.add(1);
c.counts;//[ ,1]
c.add(5);
c.counts;//[ ,1, , , ,1]
c.add(1);//true
...
may it helps you to understand whats going on

Javascript flood fill algorithm getting caught in an infinite loop

Hello I am trying to implement a simple flood fill type algorithm in javascript. Basically I have a 3x3 board which I represent as a 1 dimensional array. I want to append the index for every equal value that is "touching" to a separate array. So for instance this board:
[1][1][0]
[3][1][3]
[0][0][0]
Would be represented as a 1D array ie [1,1,0,3,1,3,0,0,0]. And after running the floodFill on one of the [1] it would result with an array that looks like this [4, 1, 0] because those are the indexes in the 1d array that are touching, which have the same value.
Here is the code:
var boardArray = new Array(1,1,0,3,1,3,0,0,0);
var comboArray = new Array();
function floodFill(n, diceVal) {
if(boardArray[n] != diceVal) {
return;
}
comboArray.push(n);
if (n >0 && n < 8) {
// right
if(!(n%3==2)) {
floodFill(n+1, diceVal);
}
// left
if(!(n%3==0)) {
floodFill(n-1, diceVal);
}
// up
if(n>2) {
floodFill(n-3, diceVal);
}
// down
if(n<5) {
floodFill(n+3, diceVal);
}
} else {
return;
}
}
floodFill(4,1);
Can anyone tell me why this is getting stuck in an infinite loop?
In your "up" case, the first time through, you'll call floodFill(1,1);. That call, in its "down" case, will call floodFill(4,1);, which will soon call floodFill(1,1)
You're already keeping track of the matching squares - the only ones that will really cause any trouble. Just confirm that you're not checking the same square again:
function floodFill(n, diceVal) {
if(boardArray[n] != diceVal) {
return;
}
// have we been here before?
if (comboArray.indexOf(n) >= 0)
return;
comboArray.push(n);
// ...
}

Javascript if value is in array else in next array

I have found a few posts on here with similar questions but not entirely the same as what I am trying. I am currently using a simple if statement that checks the data the user enters then checks to see if it starts with a number of different values. I am doing this with the following:
var value = string;
var value = value.toLowerCase();
country = "NONE";
county = "NONE";
if (value.indexOf('ba1 ') == 0 || value.indexOf('ba2 ') == 0 || value.indexOf('ba3 ') == 0) { //CHECK AVON (MAINLAND UK) UK.AVON
country = "UK";
county = "UK.AVON";
} else if(value.indexOf('lu') == 0){//CHECK BEDFORDSHIRE (MAINLAND UK) UK.BEDS
country = "UK";
county = "UK.BEDS";
}
I have about 20-30 different if, else statements that are basically checking the post code entered and finding the county associated. However some of these if statements are incredibly long so I would like to store the values inside an array and then in the if statement simply check value.indexOf() for each of the array values.
So in the above example I would have an array as follows for the statement:
var avon = new Array('ba1 ','ba 2','ba3 ');
then inside the indexOf() use each value
Would this be possible with minimal script or am I going to need to make a function for this to work? I am ideally wanting to keep the array inside the if statement instead of querying for each array value.
You can use the some Array method (though you might need to shim it for legacy environments):
var value = string.toLowerCase(),
country = "NONE",
county = "NONE";
if (['ba1 ','ba 2','ba3 '].some(function(str) {
return value.slice(0, str.length) === str;
})) {
country = "UK";
county = "UK.AVON";
}
(using a more performant How to check if a string "StartsWith" another string? implementation also)
For an even shorter condition, you might also resort to regex (anchor and alternation):
if (/^ba(1 | 2|3 )/i.test(string)) { … }
No, it doesn’t exist, but you can make a function to do just that:
function containsAny(string, substrings) {
for(var i = 0; i < substrings.length; i++) {
if(string.indexOf(substrings[i]) !== -1) {
return true;
}
}
return false;
}
Alternatively, there’s a regular expression:
/ba[123] /.test(value)
My recomendation is to rethink your approach and use regular expressions instead of indexOf.
But if you really need it, you can use the following method:
function checkStart(value, acceptableStarts){
for (var i=0; i<acceptableStarts.length; i++) {
if (value.indexOf(acceptableStarts[i]) == 0) {
return true;
}
}
return false;
}
Your previous usage turns into:
if (checkStart(value, ['ba1', ba2 ', 'ba3'])) {
country = 'UK';
}
Even better you can generalize stuff, like this:
var countryPrefixes = {
'UK' : ['ba1','ba2 ', 'ba3'],
'FR' : ['fa2','fa2']
}
for (var key in countryPrefixes) {
if (checkStart(value, countryPrefixes[key]) {
country = key;
}
}
I'd forget using hard-coded logic for this, and just use data:
var countyMapping = {
'BA1': 'UK.AVON',
'BA2': 'UK.AVON',
'BA3': 'UK.AVON',
'LU': 'UK.BEDS',
...
};
Take successive characters off the right hand side of the postcode and do a trivial lookup in the table until you get a match. Four or so lines of code ought to do it:
function getCounty(str) {
while (str.length) {
var res = countyMapping[str];
if (res !== undefined) return res;
str = str.slice(0, -1);
}
}
I'd suggest normalising your strings first to ensure that the space between the two halves of the postcode is present and in the right place.
For extra bonus points, get the table out of a database so you don't have to modify your code when Scotland gets thrown out of leaves the UK ;-)

Get a limit on arrays (Javascript)

I've a problem with set a limit into my own lightbox for a gallery
<script>
var imagenumber = 0;
function btnleft(){
load = imagenumber-=1;
document.getElementById('lightboxcontent').innerHTML=imagelist[load];
}
function btnright(){
load = imagenumber+=1;
if (load==undefined){load=imagenumber-=1}
document.getElementById('lightboxcontent').innerHTML=imagelist[load];
}
</script>
Then the array
var imagelist=new Array(); // regular array (add an optional integer
imagelist[0]="image1.jpg"; // argument to control array's size)
imagelist[1]="image2.jpg";
imagelist[2]="image3.jpg";
When I click more then 3 times on the next button I got the error-message "undefined".
How should I do to get a limit on my arrays?
Try it with
function btnleft(){
var load = imagelist[imagenumber-=1];
if (load) // imagenumber in array boundaries
document.getElementById('lightboxcontent').innerHTML = load;
else
imagenumber = 0;
}
function btnright(){
var load = imagelist[imagenumber+=1];
if (load) // imagenumber in array boundaries
document.getElementById('lightboxcontent').innerHTML = load;
else
imagenumber = imagelist.length-1;
}
Yet, Arrays in Javascript have no limited size, they are more like (infinite) lists. You can hardly set a limit on their length - espcially not with the constructor, whose number argument is just for initialisation purposes.
You can use the length property of an array to check whether your index is in the array boundaries: i >= 0 && i < arr.length. My code just checks whether there is an item at that index (as your second function seems to intend, too) and resets the index otherwise.
I assume that clicking on the "next button" calls the btnright() function.
If that is the case then you are testing the wrong value for undefined. You could rewrite your function as:
function btnright(){
load = imagenumber += 1;
// Test the value at the index of the array, not your index variable.
if (imagelist[load] === undefined) {
load = imagenumber-= 1;
}
document.getElementById('lightboxcontent').innerHTML = imagelist[load];
}
Stylistically this is still no the best. Your load variable is not required since its value always duplicates imagenumber. You could refactor the function such:
function btnright() {
// If we have a new array value do something.
if (imagelist[imagenumber + 1] !== undefined) {
// Increment the index and load the new image.
document.getElementById('lightboxcontent').innerHTML = imagelist[++imagenumber];
}
}
function btnleft() {
// If we're not on the first image do something.
if (imagenumber !== 0) {
// Decrement the index and load the new image.
document.getElementById('lightboxcontent').innerHTML = imagelist[--imagenumber];
}
}

Categories