Comparing Letters in a Palindrome (JavaScript) [duplicate] - javascript

This question already has answers here:
Palindrome check in Javascript
(45 answers)
Closed 7 years ago.
My objective is to test if a word (under 10 letters) that a user enters is a palindrome. I want to do this my comparing the first letter to the last, 2nd letter to the 2nd to last, 3rd letter to the 3rd to last...
I am using a for loop and an array to do this. I cannot use the reverse() method. My main issue is formatting the comparison equation that I have:
(lettersArray[i] + 1) == (lettersArray[i].length - 1)
This is supposed to compare the first to last, 2nd and 2nd to last, and so on. Is this the right format? Am I right in my method of accessing the last index in the array and counting it down? Please let me kow what I am doing wrong since it's not running. Here is my code:
var usersWord = prompt("Enter a Palindrome");
var lettersArray =usersWord.split(""); // this is the array
for(var i=0; lettersArray.length < 11; i++) {
if((letters[i] + 1) == (lettersArray.length[i]-1)) {
alert("is palindrome");
} //end if statement
else{
alert("is not palindrome");
} // end else statement
} // end for statement

The issue with your code is that you are reporting results after checking each character; however, we can't tell whether a word is a palindrome or not without checking every character. A function such as the following might better suit your requirements.
function checkPalindrome(word) {
var len = word.length;
for (var i = 0; i < (len / 2); i++) {
if (word.charAt(i) !== word.charAt(len - 1 - i))
return false;
}
return true;
}
Another important point to note is that you should be checking until word.length / 2, not an arbitrary number 11 that may change depending on the word used as an input. Note also that word.length / 2 is an optimized case. The loop could also have been run till the word length but there is no need to check again that last char == first char when already first char == last char

Related

Is there a more efficient algorithm to find this kind of substrings? [duplicate]

This question already has answers here:
How to determine if one string starts with what another ends with
(3 answers)
Closed 3 years ago.
I am writing a function that takes two strings as input parameters: text and pattern.
If text ends with a substring starting at index index and this substring is a start of pattern, then return index.
If there is no such substring, return -1.
I've come up with the following function, but I wonder if there is more efficient solution.
So the question is: is there more efficient algorithm to find such substrings?
function findSubstring(text, pattern) {
let index = -1;
for (let i = 1; i <= text.length; i++) {
const tail = text.substr(-i);
if (pattern.indexOf(tail) === 0) {
index = text.length - i;
}
}
return index;
}
const exampleText = 'const result = items.m';
const examplePattern = '.map((item) => {})';
console.log(findSubstring(exampleText, examplePattern)); // -> 20
I'd check either for a partial match at the end or a full match before that:
const last = text.lastIndexOf(pattern[0]);
if(text.substr(last, last + pattern.length) === pattern.substr(0, text.length - last))
return last;
return text.lastIndexOf(pattern, last);
Although the underlying algorithm is probably less eficcient, this may still run faster due to engine optimizations, wether it is faster in your case needs to be tested.

Counter variable in for/loop. Why does one program work and the other fails? [duplicate]

This question already has answers here:
How to get numeric value from a prompt box? [duplicate]
(6 answers)
Closed 7 years ago.
So, in writing a program - in javascript - that sums numbers from 1 to N (number given by user), I have written a working program, but I am still confused as to why one proposed solution that I wrote works, and the other doesn't.
This version works:
function spitback(){
var theNum = prompt("Give me a number");
var onwards = 0;
for(i = 0; i <= theNum; i++){
onwards += i;
}
console.log(onwards);
}
spitback();
This one does not:
function spitback(){
var theNum = prompt("Give me a number");
var onwards = theNum;
for(i = 0; i <= theNum; i++){
onwards += i;
}
console.log(onwards);
}
spitback();
Why doesn't the second one work? If I initially set var onwards as theNum (inputted by a user) and then have the function add onwards to the iterations of 'i' up until the counter reaches theNum, I will see a concatenation between theNum and all the iterations of i next to it, like it is a string. In my mind, setting a variable to the same value and then having that value change to add the counter's iteration should work! Why doesn't it work? Please share.
This is because prompt returns a string, not a number. And when you use "+" operation on a string, you get concatenation, not integer increment. Javascript will not magically convert your string into integer even if it looks like it.

How to find total possible values from length and characters?

I'm totally not a Math whiz kid here, but have put together a function with the great help of StackOverflow (and a lot of trial and error) that generates a random serial number from a Formula, group of Letters/Numbers, and array (so as to not duplicate values).
So, my current formula is as follows:
$.extend({
generateSerial: function(formula, chrs, checks) {
var formula = formula && formula != "" ? formula : 'XXX-XXX-XXX-XXX-XXX', // Default Formula to use, should change to what's most commonly used!
chrs = chrs && chrs != "" ? chrs : "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", // Default characters to randomize, if not defined!
len = (formula.match(/X/g) || []).length,
indices = [],
rand;
// Get all "-" char indexes
for(var i=0; i < formula.length; i++) {
if (formula[i] === "-") indices.push(i);
}
do {
rand = Array(len).join().split(',').map(function() {
return chrs.charAt(Math.floor(Math.random() * chrs.length));
}).join('');
// Rebuild string!
if (indices && indices.length > 0)
{
for(var x=0; x < indices.length; x++)
rand = rand.insert(indices[x], '-');
}
} while (checks && $.inArray(rand, checks) !== -1);
return rand;
}
});
Ok, so, what I need to be able to do is to find total possible values and make sure that it is possible to generate a unique serial number before actually doing so.
For example:
var num = $.generateSerial('XX', 'AB', new Array('AB', 'BA', 'AA', 'BB'));
This will cause the code to do an infinite loop, since there are no more possibilties here, other than the ones being excluded from the extension. So this will cause browser to crash. What I need to be able to do here is to be able to get the number of possible unique values here and if it is greater than 0, continue, otherwise, don't continue, maybe an alert for an error would be fine.
Also, keep in mind, could also do this in a loop so as to not repeat serials already generated:
var currSerials = [];
for (var x = 0; x < 5; x++)
{
var output = $.generateSerial('XXX-XXX-XXX', '0123456789', currSerials);
currSerials.push(output);
}
But the important thing here, is how to get total possible unique values from within the generateSerial function itself? We have the length, characters, and exclusions array also in here (checks). This would seem more like a math question, and I'm not expert in Math. Could use some help here.
Thanks guys :)
Here is a jsFiddle of it working nicely because there are more possible choices than 16: http://jsfiddle.net/qpw66bwb/1/
And here is a jsFiddle of the problem I am facing: Just click the "Generate Serials" button to see the problem (it continuously loops, never finishes), it wants to create 16 serials, but 16 possible choices are not even possible with 2 characters and only using A and B characters: http://jsfiddle.net/qpw66bwb/2/
I need to catch the loop here and exit out of it, if it is not able to generate a random number somehow. But how?
The number of possible serials is len * chrs.length, assuming all the characters in chrs are different. The serial contains len characters to fill in randomly, and chrs.length is the number of possible characters in each position of that.

Recursion and Loops - Maximum Call Stack Exceeded

I'm trying to build a function that adds up all the numbers within a string... for example, 'dlsjf3diw62' would end up being 65.
I tried to be clever and put together a recursive function:
function NumberAddition(str) {
var numbers='1234567890';
var check=[];
str=str.split[''];
function recursive(str,check) {
if (str.length==0)
return check;
else if (numbers.indexOf(str[0])>=0)
{
for (i=0;i<str.length;i++){
if (numbers.indexOf(str[i])<0)
check.push(str.slice(0,i));
str=str.slice(i);
return recursive(str,check);
}
}
else
str.shift();
return recursive(str,check);
}
You'll see that I'm trying to get my numbers returned as an array in the array named check. Unfortunately, I have a maximum call stack size exceeded, and I'm not sure why! The recursion does have a base case!! It ends once str no longer has any contents. Why wouldn't this work? Is there something I'm missing?
-Will
You can achieve the same thing with a far easier solution, using regular expressions, as follows:
var str = 'dlsjf3diw62';
var check = str.match(/\d+/g); // this pattern matches all instances of 1 or more digits
Then, to sum the numbers, you can do this:
var checkSum = 0;
for (var i = 0; i < check.length; i++) {
checkSum += parseInt(check[i]);
}
Or, slightly more compact:
var checkSum = check.reduce(function(sum, num){ return sum + parseInt(num) }, 0);
The reason your recursion doesn't work is the case where you do enter the for loop, because you've found a digit, but the digits continue to the end of the string. If that happens, the return inside the for loop never happens, and the loop ends. After that, the .shift() does not happen, because it's in that else branch, so you return re-process the same string.
You shouldn't solve this particular problem that way, but the code makes a good example of the anti-pattern of having return statements inside if bodies followed by else. Your code would be clearer (and would work) if it looked like this:
function recursive(str, check) {
if (str.length == 0)
return check;
if (numbers.indexOf(str[0]) >= 0) {
// Find the end of the string of digits, or
// the end of the whole thing
for (var i = 0; i < str.length && numbers.indexOf(str[i]) >= 0; i++);
check.push(str.slice(0, i));
str = str.slice(i);
return recursive(str, check);
}
// A non-digit character
str.shift();
return recursive(str, check);
}
In that version, there are no else clauses, because the two if clauses always involve a return. The for loop is changed to simply find the right value of "i" for the subsequent slicing.
edit — one thing this doesn't fix is the fact that you're pushing arrays into your "check" list. That is, the substring "62" would be pushed as the array ["6", "2"]. That's not a huge problem; it's solved with the addition of a .join() in the right place.

checking if digit exists on particular place in string

I have a string that starts with "TT" and ends with six digits(ex. "TT012345", "TT012000, TT329001). The string is always formatted like this and I need to check if the last digit in this string is of a certain value.
Say I have the string "TT032970". In this case I'd like to get a match on this string since the last digit is zero and the digit before that is a seven(I'm looking for 7).
The string "TT037000" should also be a match but "TT0329701" shouldn't(since it isn't all zeroes to the right of the seven(the "last" 7 in the string)).
I was thinking of using a set of nested if's using substr() to check all places of the string for zeroes and if it isn't a zero in position n, then I check if the digit I'm looking for exists in position n.
My code is repetitive and I'm all for being efficient.
This is what I got so far(that works but only checks the last place of the string and the second last place):
var lastDigit = [3, 7, 8], tda = document.querySelectorAll('td a'), i, j;
function checkArray(num) {
"use strict";
for (j = 0; j < lastDigit.length; j++) {
if (num === lastDigit[j]) {
return true;
}
}
}
for (i = 0; i < tda.length; i++) {
if ((parseInt(tda[i].textContent.substr(8, 1), 10) === 0 && checkArray(parseInt(tda[i].textContent.substr(7, 1), 10))) || checkArray(parseInt(tda[i].textContent.substr(8, 1), 10))) {
tda[i].style.background = "rgb(255, 144, 255)";
amountOfTickets.push(tda[i]);
}
}
I'm positive there's a great way of checking the string for trailing zeroes and check the first non-zero digit before the zeroes. However, I'm really bad with loops and I just can't figure out how.
I'm very keen on figuring it out myself but I need a head start. I'd rather take a detailed explanation on how to do it than just the "answer".
If anything else seem off I'd gladly listen to improvements.
Thanks in advance!
To get the first digit before the zeros at the end of a string, you may use a regular expression :
+string.match(/(\d)0*$/)[1]
Example 1 :
var string = "TT032970";
var digit = +string.match(/(\d)0*$/)[1];
console.log(digit); // logs 7
Example 2 :
console.log(["TT012345","TT012000","TT329001","TT032970"].map(function(string){
return +string.match(/(\d)0*$/)[1]
})); // logs [5, 2, 1, 7]
Demonstration
Obviously, from the other answers, a regular expression will be much simpler than your loops. Moreover, any nested loop solution will be difficult to work, as you don't know how many levels deep you have to look. (Is there one zero? Two? Five?)
This regex is quite simple:
/(\d)0+$/
If you do a match on that with your string, you should get either null if it doesn't match (e.g. "TT0329701") or a two-element array if it does (e.g. "TT037000" will return ["7000", "7"].)
That should be enough for your to build your own solution upon.
Best of luck.
The first thing I though about is something like this (depends on whether I understood your problem correctly):
function lookFor(str, digit) {
//validate input...
if (str.length != 8) return false;
if (str[0] != "T" && str[1] != "T") return false;
//start at the end and move to the left as long as there are zeros
//the first non-zero element must be our digit, else return false
for (var i = str.length-1; i>0; --i) {
if (str[i] !== "0") {
return str[i] === digit;
}
}
}
lookFor("TT012000", "2") --> true
lookFor("TT012000", "3") --> false
But I guess the regex solution is probably more compact than this one.

Categories