Project Euler -- Largest palindrome product - javascript

There seems to be a problem with this code as in it doesn't check for the largest palindrome. I mixed it with the example they showed of largest palindrome from two digit numbers (The largest palindrome made from the product of two 2-digit numbers is 9009 = 91 × 99) and it worked. I've looked around, but I still don't understand exactly why my code doesn't show the final product. If someone is willing to explain instead of just giving the answer, that would be quite helpful
for(var i = 100; i < 1000; i++) {
for(var j = 100; j < 1000; j++) {
var total = String(i*j);
var regularI = total.substring(0, Math.floor(total.length/2));
var regularJ = total.substring(total.length/2,total.length);
var reversedJ = regularJ.split("").reverse().join("");
if(regularI === reversedJ) {
console.log("SUCCESS\nTotal: " + (i*j) + "\nI: " + i + "\nJ: " + j);
}
}
}

993 * 913 = 906609
995 * 583 = 580085
Suppose the first number in the multiplication corresponds to i, and the second to j. In your nested for-loop with i and j, the result of the former multiplication will be output before the latter. You can see this if you look at the end of your code's output. Therefore, the final success that is output is not guaranteed to be the largest palindrome. It's possible that the largest palindrome appears earlier in your output.
One straightforward method of fixing this problem is to keep a list of palindromes you've found in an array. After the nested for-loop completes, you can sort the array by number value and get the largest number by looking at the last position:
var palindromes = [];
for(var i = 100; i < 1000; i++) {
for(var j = 100; j < 1000; j++) {
var total = String(i*j);
var regularI = total.substring(0, Math.floor(total.length/2));
var regularJ = total.substring(total.length/2,total.length);
var reversedJ = regularJ.split("").reverse().join("");
if(regularI === reversedJ) {
palindromes.push(Number(total));
}
}
}
// sorts the array in-place
// "default sort order is according to string Unicode code points" - Mozilla docs
// so we'll need to pass in a comparison function.
palindromes.sort(function(a, b) {
return a - b;
});
console.log(palindromes[palindromes.length-1]);
If you do this, you'll see that the largest palindrome is indeed 906609, a number that appeared third-to-last (and once more, earlier) in your nested for-loop.
Another way of solving this would be to dedicate a variable, say maxSoFar, to keeping track of the highest palindrome value you've seen.
There are other ways of solving this problem, but I'll leave that up to you to discover.

Related

Where have I mixed up my math logic for this Javascript problem?

I was doing this challenge on HackerRank and I got it right with one small mistake. Using the test example, you have an array of 5 numbers and you must find the largest and lowest sum using 4 of the 5 numbers. You must then print the two numbers with the smaller number first and larger one second. To achieve this, I made this:
function miniMaxSum(arr) {
var smallestNumber = arr[0];
var biggestNumber = arr[0];
var large = 0;
var small = 0;
for(var i = 0; i < arr.length; i++){
if(smallestNumber < arr[i]){
smallestNumber = arr[i];
}
large += arr[i];
}
large = large - smallestNumber;
for(var j = 0; j < arr.length; j++){
if(biggestNumber > arr[j]){
biggestNumber = arr[j];
}
small += arr[j];
}
small = small - biggestNumber;
console.log(small,large);
}
Now technically I have the right answer, but I have them reversed. When running the code my small variable is actually the larger number and the large variable is the smaller number. All I have to do is swap the variables in the console.log and the challenge is completed, but I'm going through the code and I'm not sure where I mixed them up. As far as I'm aware, the first loop finds the smallest number in the array and then after adding all the numbers in the array, subtracks the smallest number from the total. And the second loop adds all the numbers in the array and then subtracts the largest number from the total. And yet apparently what I have is the other way around. What am I missing here?

Javascript Random Name Guesser: Unresponsive Script Issues

This is my first post here and I am having trouble wording a question, so please bear with me as I have been on this issue for hours.
My friend and I have thought of a fun little function that is supposed to guess the user's name (through an <input> tag) in a certain amount of trials using the random number function to access string letters from an alphabet array numbered 0-25. The function is also supposed to give the user the number of trials it took to guess their name.
I keep getting a non-responsive script, (line 33 - The line containing the second "for loop").
var goal = document.getElementById("your_Name").value;
var alphabet = ["a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"];
var goalArray = goal.split("");
var trials = 0;
var guessArray = new Array();
var i;
var n;
for (i = 0; i < goalArray.length; i++){
guessArray.push(alphabet[Math.floor(Math.random()*26)]);
}
while (goalArray != guessArray){
trials++;
guessArray = [];
for (n = 0; n < goalArray.length; n++){
guessArray.push(alphabet[Math.floor(Math.random()*26)]);
}
}
document.getElementById("appendomatic").innerHTML = "It took " + guessArray + " trials to guess correctly";
Any help or attempt to help would be immensely appreciated!
In case anyone was wondering: This little idea of ours was to test the randomness of Javascript's random function through trials (he made the same program in MatLab, so we are going to compare results of the random functions from both languages).
goalArray != guessArray is always true since they are two separate arrays; even if they contain the same elements.
Since they appear to just be arrays of individual letters in a-z you could compare them with something like goalArray + '' != guessArray, because the toString() of the arrays will compare correctly.
This is how I eventually got it to work (by nesting the while loop and second for loop in another for loop):
var goal = document.getElementById("your_Name").value;
var goalArray = goal.split("");
var alphabet = ["a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"];
var trials = 0;
var guessArray = [];
for (i = 0; i < goalArray.length; i++){
guessArray.push(alphabet[Math.floor(Math.random()*26)]);
}
for (x = 0; x < goalArray.length; x++){
while (goalArray[x] != guessArray[x]){
trials++;
guessArray = [];
for (n = 0; n < goalArray.length; n++){
guessArray.push(alphabet[Math.floor(Math.random()*26)]);
}
}
document.getElementById("appendomatic").innerHTML = "It took " + trials + " trials to guess correctly";
}
}

How do I grab the two largest integers from a Javascript Array and return the value to the DOM?

I've written a solution to take a list of integers entered through a form. It works. It gives you the sum of the two largest integers and posts it in the DOM.
However, it's not very efficient for large arrays of say 1 million integers.
How can I improve this solution to be more efficient.
App.js
// This function reverses the order of the array and places the biggest numbers first
function sortNumber(a, b) {
return b - a;
}
// this function is used to ensure the user didn't enter any letters
function getArray() {
var alphaExp = /^[a-zA-Z]+$/;
// This function takes the array, orders it, adds the sum of the two largest numbers and returns the value
function sumOf(x) {
// Sort the ary with the sortNumber function
array.sort(sortNumber);
// Then we add the two biggest numbers of the array and save it to the result variable.
var result = array[0] + array[1];
// Then we share the result with the user by updating the browser
var myHeading = document.querySelector('h2');
myHeading.textContent = "The sum of your two biggest numbers is: " + result;
// Like a good student, it's important to show your work
var showYourWork = document.querySelector('h3');
showYourWork.textContent = array[0] + " + " + array[1] + " = " + result;
}
// This grabs the value of the input
var arrayField = document.getElementById('arrayField').value;
if (arrayField.match(alphaExp)) {
// Fail if user enters letters
var raiseError = document.querySelector('h5');
raiseError.textContent = 'No not letters! We want numbers!!';
} else {
var array = JSON.parse("[" + arrayField + "]");
if (arrayField.length < 2) {
// If the user enters only 1 number, tell them to enter more!
var raiseError = document.querySelector('h5');
raiseError.textContent = 'Please enter atleast two numbers seperated by commas for us to add!'
} else {
// When the user enters a list of numbers, run the sumOf function.
sumOf(arrayField);
//Make the error go away
var raiseError = document.querySelector('h5');
raiseError.textContent = '';
}
}
};
// use an eventlistener for the event (This is where the magic happens)
var subButton = document.getElementById('subButton');
subButton.addEventListener('click', getArray, false);
You don't have to sort it, just search linearly for the two biggest ones:
EDIT: the code below should work now and is asymptotically faster than the OP's code. The OP does sorting first which can be done in O(n log n), assuming a random list. My code does a linear search through the list in O(cn) with c = 2 (the two loops are not necessary but simple). The solution for ceil(n log n) = 2n with n a positive integer is 14, that is for every list longer than 14 entries the code below is faster. E.g.: for one million entries the relation is 13,815,511 to 2,000,000, more than six times faster. You can do the same thing in a single loop which halves the runtime (theoretically, but it is also a tiny bit faster because of the better locality).
function maxtwo_wrong(a){
var b1 = -Infinity;
var b2 = -Infinity;
for (var i=0; i < a.length; i++) {
if (a[i] > b1) {
b1 = a[i];
}
}
for (var i=0; i < a.length; i++) {
if (a[i] > b2 && a[i] < b1) {
b2 = a[i];
}
}
return [b1,b2];
}
EDIT-2: The code above maxtwo_wrong seems not to fit the requirements, so I wrote another one maxtwo_rightand put it below. Please, OP, tell me which one fulfills your requirements such that I can delete the wrong one.
EDIT-3: made it simpler and correct.
function maxtwo_right(a){
var b1 = -Infinity;
var b2 = -Infinity;
for (var i=0; i < a.length; i++) {
// If the current entry is bigger than variable b1
// keep the old value in the variable b2 and set b1 to the
// value of the current entry
if (a[i] > b1) {
b2 = b1;
b1 = a[i];
}
// if the current entry equals b1 set the variable b2 to
// the value of the current entry
else if(a[i] === b1){
b2 = a[i];
}
}
// return the sum of the two variables as requested
return b1 + b2;
}
I finally found some time to sit down and work this one out.
I was looking at the problem all wrong.
Here is my new solution
// This function adds the sum of the two largest integers of an array and returns the value
function topTwoInt(theArray) {
var intArray = theArray;
var highestInt = -Infinity;
var secondHighestInt = -Infinity;
var answer = 0;
//Loop through the array
for (var i=0; i < intArray.length; i++) {
//grab the biggest int and assign it to the highestInt variable;
if (intArray[i] > highestInt) {
secondHighestInt = highestInt;
highestInt = intArray[i];
}
//If the next number is equal too highestInt or greater than secondHighestInt
//Make that number become the new secondHighestInt
else if(intArray[i] === highestInt || intArray[i] > secondHighestInt) {
secondHighestInt = intArray[i];
}
}
answer = highestInt + secondHighestInt;
return answer;
};
This solution is largely inspired by #deamentiaemundi
Thanks man.

Comparing 2 arrays to output total integer

I have 2 arrays of numbers. I want to go through each array and find the number of times 1 number from each array adds up to the particular amount x.
If the particular amount x is reached as many times as another set number n then the function should print 'YES'. If x does not reach the set number of n then the function should print 'NO'.
The values of x , n and both arrays are in a string input. These values have been split into arrays as seen below in the code.
I have set up 2 for loops to run through each array and an if statement that checks for the condition of x meeting n.
The arrays I'm using in this code should print out the result of 'YES' however every time I run the code I'm getting 'NO' ? I've tried tinkering with the code but nothing has worked.
Any idea on where this code is broke and how to fix the problem?
Thanks :)
code:
var input = '2\n3 10\n2 1 3\n7 8 9';
function processData(input) {
var inputArray = input.split('\n');
var n = inputArray[1][0];
var x = inputArray[1].split(' ')[1];
var arrayA = inputArray[2].split(' ');
var arrayB = inputArray[3].split(' ');
var total = 0;
for(var i = 0; i < arrayA.length; i++) {
for(var j = 0; j < arrayB.length; j++) {
if(arrayA[i] + arrayB[j] == x) {
total = total + 1;
} if (total == n) {
return 'YES';
}
}
}
return 'NO';
}
console.log(processData(input));
arrayA[i] and arrayB[j] are strings, so arrayA[i] + arrayB[j] will be the concatenation of them (ex: '2' + '3' === '23').
If your logic is correct (i didn't quite understand what you are trying to do), it should be enough to convert them to numbers before adding them, using parseInt or some other method:
if(+arrayA[i] + (+arrayB[j]) == +x) { // used unary + to convert to number
total = total + 1;
} if (total == n) {
return 'YES';
}
PS: A cleaner version would be to convert each string in the array to number, but that involves more than adding 3 characters to your code.
PS2: You have a weird way of getting the input data. If you get it from another place in your JS code, you could simply pass it as an object with the relevant structure, otherwise you could pass it around in a more ... common format, like JSON.

Sorting function?

I need to organize an array of strings of random length into the least number of new strings with a max size. Is there a function or something in javascript, or something that can be translated to javascript, that will do this?
For example, the new strings might have max lengths of 1000 characters. The array might have strings of lengths 100, 48, 29, etc. I would want to combine those strings into as few new strings as possible.
edit: Sorry if this doesn't make sense, I tried my best.
No standard method in Javascript, but plenty of theoretical work has been done on this (i.e. the bin packing problem).
http://en.wikipedia.org/wiki/Bin_packing_problem
Some sample pseudo code in the link - should be trivial to translate to javascript.
The algorithm shown isn't going to be optimal in every case. To find the optimal solution to your example you'll just need to iterate over every possibility which might not be that bad depending on how many strings you have.
For my own entertainment, I wrote a simple bin packing algorithm. I picked a simple algorithm which is to sort the input strings by length. Create a new bin. Put the first (longest remaining) string into the bin and then keep filling it up with the longest strings that will fit until no more strings will fit. Create a new bin, repeat. To test it, I allocate an array of strings of random lengths and use that as input. You can see the output visually here: http://jsfiddle.net/jfriend00/FqPKe/.
Running it a bunch of times, it gets a fill percentage of between 91-98%, usually around 96%. Obviously the fill percentage is higher if there are more short strings to fill with.
Here's the code:
function generateRandomLengthStringArrays(num, maxLen) {
var sourceChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXY1234567890";
var sourceIndex = 0;
var result = [];
var len, temp, fill;
function getNextSourceChar() {
var ch = sourceChars.charAt(sourceIndex++);
if (sourceIndex >= sourceChars.length) {
sourceIndex = 0;
}
return(ch);
}
for (var i = 0; i < num; i++) {
len = Math.floor(Math.random() * maxLen);
temp = new String();
fill = getNextSourceChar();
// create string
for (var j = 0; j < len; j++) {
temp += fill;
}
result.push(temp);
}
return(result);
}
function packIntoFewestBins(input, maxLen) {
// we assume that none of the strings in input are longer than maxLen (they wouldn't fit in any bin)
var result = [];
// algorithm here is to put the longest string into a bin and
// then find the next longest one that will fit into that bin with it
// repeat until nothing more fits in the bin, put next longest into a new bin
// rinse, lather, repeat
var bin, i, tryAgain, binLen;
// sort the input strings by length (longest first)
input.sort(function(a, b) {return(b.length - a.length)});
while (input.length > 0) {
bin = new String(); // create new bin
bin += input.shift(); // put first one in (longest we have left) and remove it
tryAgain = true;
while (bin.length < maxLen && tryAgain) {
tryAgain = false; // if we don't find any more that fit, we'll stop after this iteration
binLen = bin.length; // save locally for speed/convenience
// find longest string left that will fit in the bin
for (i = 0; i < input.length; i++) {
if (input[i].length + binLen <= maxLen) {
bin += input[i];
input.splice(i, 1); // remove this item from the array
tryAgain = true; // try one more time
break; // break out of for loop
}
}
}
result.push(bin);
}
return(result);
}
var binLength = 60;
var numStrings = 100;
var list = generateRandomLengthStringArrays(numStrings, binLength);
var result = packIntoFewestBins(list, binLength);
var capacity = result.length * binLength;
var fillage = 0;
for (var i = 0; i < result.length; i++) {
fillage += result[i].length;
$("#result").append(result[i] + "<br>")
}
$("#summary").html(
"Fill percentage: " + ((fillage/capacity) * 100).toFixed(1) + "%<br>" +
"Number of Input Strings: " + numStrings + "<br>" +
"Number of Output Bins: " + result.length + "<br>" +
"Bin Legnth: " + binLength + "<br>"
);

Categories

Resources