I want to write a function that accepts str1 and str2 and checks if str1 digits can be rearranged into str2.
Currently stuck at this:
My code works fine until str2 won't have any double digits.
How can I fix this?
function scramble(str1, str2) {
str1 = str1.split('');
str2 = str2.split('');
let result = [];
for (let i = 0; i < str2.length; i++) {
for (let j = 0; j < str1.length; j++) {
if (str2[i] === str1[j]) {
result.push(str1[j]);
}
}
}
for (let i = 0; i < result.length; i++) {
if (result[i] === result[i + 1]) {
result.splice(i, 1);
--i;
}
}
return result.join('') === str2.join('')
}
console.log(scramble('rkqodlw','world'));
console.log(scramble('aabbcamaomsccdd','commas')); //heres the problem
You want a count of the various characters in each and use that as comparison.
Following uses Map objects then iterates the str2 counts to make sure the test string (str1) contains equal or greater count for each character in str2
// helper function to map character counts
const charCount = (str) =>{
return [...str].reduce((a,c)=> a.set(c, (a.get(c)||0)+1), new Map)
}
function scramble(str1, str2) {
const s2Counts = charCount(str2),
s1Counts = charCount(str1);
return [...s2Counts.entries()].every(([char,count]) => s1Counts.get(char) >= count)
}
console.log(scramble('rkqodlw','world')); // expect true
console.log(scramble('aabbcamaomsccdd','commas')); // expect true
console.log(scramble('fobar','foobar')); // expect false
A simple method is to check, whether all characters from the second string are contained in the the first one. To deal with double characters in the second string, remove each found character from the first string.
This of course only returns the correct result if the extra characters in the first string don't matter ...
function checkstrings(string1, string2) {
let s1 = [...string1] //convert string1 and
, s2 = [...string2]; //string2 into arrays of char
for (let c of s2) {
let i = s1.indexOf(c); //check if c from s2 is contained in s1
if (i == -1) //if not found result can' be true
return false;
s1.splice(i, 1); //remove c from s1
}
return true;
}
console.log(checkstrings("rkqodlw", "world"));
console.log(checkstrings("aabbcamaomsccdd", "commas"));
console.log(checkstrings("aabbcamaomsccdd", "commmas"));
Related
function palindrome(str) {
const forward = str.replace(/[^a-zA-Z ]/g, "").toUpperCase()
const reversed = str.replace(/[^a-zA-Z ]/g, "").toUpperCase()
for (let i = 0; i < forward.length; i++) {
for (let k = reversed.length - 1; k >= 0; k--) {
if (forward[i] === reversed[k]) {
return true
} else {
return false
}
}
}
}
console.log(palindrome("almostomla"));
Why is this not working??
does my loop just creates a new "s"?
You don't need nested loops, that will compare every character with every other character. You just want to compare the first character with the last character, 2nd character with 2nd-to-last character, and so on. So there should just be a single loop that increments i and decrements k in lock step.
You shouldn't return true when you find a match, because there could be later characters that don't match. Return false when you find a mismatch, and return true if you make it through the loop without returning.
You don't need both forward and reversed variables, since they're the same. Just convert the input string to uppercase once, and use that for both.
You don't need to iterate through the whole string, you can stop when you get to the middle.
function palindrome(str) {
const upper = str.replace(/[^a-zA-Z ]/g, "").toUpperCase()
for (let i = 0, k = upper.length - 1; i < upper.length/2; i++, k--) {
if (upper[i] !== upper[k]) {
return false
}
}
return true;
}
console.log(palindrome("almostomla"));
console.log(palindrome("almotomla"));
console.log(palindrome("almottomla"));
You might want this:
function palindrome(str) {
const forward = str.replace(/[^a-zA-Z ]/g, "").toUpperCase()
var n = forward.length
for (let i = 0; i < n; i++) {
if (forward[i] !== forward[n-i-1]) {
return false;
}
}
return true;
}
The task was to write a function subLength() that takes 2 parameters, a string and a single character. The function should search the string for the two occurrences of the character and return the length between them including the 2 characters. If there are less than 2 or more than 2 occurrences of the character the function should return 0.
const subLength = (str, char) => {
let charCount = 0;
let len = -1;
for (let i=0; i<str.length; i++) {
if (str[i] == char) {
charCount++;
if (charCount > 2) {
return 0;
}
// could somebody explain why -1 is equal to len and then len is reassigned to i???
if (len == -1) {
len = i;
} else {
len = i - len + 1
}
}
}
if (charCount < 2) {
return 0;
}
return len;
};
dude there are other ways to do this.
see if my code helps you to understand any better :)
const subLength = (str, char) => {
let charCount = 0;
let letterFound = [];
let arr = str.split('');
for (let i = 0; i < arr.length; i++) {
if (arr[i] === char) {
letterFound.push(i);
charCount++;
}
}
let result = arr.slice(letterFound[0], letterFound[1]).length + 1;
if (charCount > 2 || charCount < 2) return 0;
return result;
}
console.log(subLength('saturday', 'a'));
in the first occurrence len= -1 so:
(len ==-1) turned to true;
and len is changed to i
so len=i;
in the second occurance len is not -1 so:
len = i - len -1;
in essence, in the above expression, len keeps the index of the first occurrence, and i has the index of second occurrence, so the difference will be, the difference between two occurrences, 'qweraq' : first occurrance: 0, second: 6. 6-0-1= 5 is difference;
This is how I manage to rewrite your code.
Hope this helps.
const subLength = (str, char) => {
const arr = str.split('');
let count = 0;
arr.forEach(letter => letter === char ? count++ : '')
const result = arr.some(letter => {
if (arr.indexOf(char) !== arr.lastIndexOf(char) && count == 2) {
return true
}
return false
})
return result ? Math.abs(arr.indexOf(char) - arr.lastIndexOf(char)) + 1 : 0
}
Whilst its possible to calculate the indexes and the count within a single loop, given the triviality I'd favor standard API methods for scanning. one could always optimize later if the application actually called for it.
First we convert the string to an array so that we have the ability to filter for matches to the input character, and derive the length.
Only if there are 2 occurrences do we calculate the distance between using the indexOf and lastIndexOf methods on string (note that these will only require a second full scan of the string if the two occurrences are consecutive).
Otherwise, the result should be 0.
const subLength = (str, chr) => {
const count = str.split('').filter(ltr => ltr === chr).length
if (count === 2) {
return (str.lastIndexOf(chr) - str.indexOf(chr)) + 1
}
return 0
}
console.log(subLength('asddfghvcba', 'a'))
console.log(subLength('asddfghvcba', 'x'))
console.log(subLength('aaaaaaaaaaa', 'a'))
I am trying to solve a palindrome using a for loop in JavaScript (my code is below).
I cannot figure out what I am doing wrong. If someone can please correct and explain, it will be much appreciated. I am fairly new to coding.
var word = window.prompt("Enter a word");
function palindrome(a) {
var reversed = '';
for (i = 0; i <= a.length; i++) {
reversed = reversed + a[a.length - 1 - i];
}
if (a == reversed) {
return "true";
} else {
return "false";
}
}
document.write(palindrome(word));
On for loop inside palindrome, you have looped from 0 ~ a.length and the item on length index in a string is undefined so reversed will always be undefined.
You need to loop from 0 ~ a.length - 1 as follows.
var word = window.prompt("Enter a word");
function palindrome(a) {
var reversed = '';
for (i = 0; i < a.length; i++) {
reversed = reversed + a[a.length - 1 - i];
}
console.log(reversed);
if (a == reversed) {
return "true";
} else {
return "false";
}
}
document.write(palindrome(word));
You can reverse string simply as follows.
var word = window.prompt("Enter a word");
function palindrome(a) {
const reversed = a.split('').reverse().join('');
if (a == reversed) {
return "true";
} else {
return "false";
}
}
document.write(palindrome(word));
your loop:
for (i = 0; i <= a.length; i++) {
reversed = reversed + a[a.length - 1 - i];
}
you just need remove -1 and start the loop with 1 because when you reached the end of the iteration you will have the length of the word -1 and this will try to access a negative position.
after changing:
for (let i = 1; i <= a.length; i++) {
// you can use reversed += a[a.length - i] instead of;
reversed = reversed + a[a.length - i];
}
You can also reverse a string using the reverse method like this:
reversed = a.split('').reverse().join('');
Finally if you want to validata sentences you need to remove blank spaces and convert it in lower or upper case(usually converted in lowercase) because compare is case sensitive ("Party trap" != "part ytraP").
This code compares the first character to the last character, then advances to compare the second character to the next to last character until it runs out of characters.
As soon as it finds an inequality, it returns false because there is no reason to continue comparing.
let word = window.prompt("Enter a word");
const palindrome = a => {
let last = a.length - 1;
// loop, comparing the values until you find something that doesn't match
for (let first = 0; first <= last; first++, last--) {
if (a[first] !== a[last]) {
return "false";
}
}
// everything matched
return "true";
}
document.getElementById("output").textContent = palindrome(word);
<output id="output"></output>
I'm trying to solve the problem of: Given an array of strings with only lower case letters, make a function that returns an array of those same strings, but each string has its letters rearranged such that it becomes a palindrome (if not possible then return -1). I'm a bit stuck on how I should be rearranging the letters.
let arr = ["hello", "racecra"];
I created a function to first check if a word is a palindrome :
function isPalindrome(arr) {
let obj = {};
for (var x = 0; x < str.length; x++) {
if (obj[arr[x]]) {
obj[arr[x]] += 1;
} else {
obj[arr[x]] = 1;
}
}
let countOdd = 0;
let countEven = 0;
for (let x of Object.values(obj)) {
if (x % 2 == 0) {
countEven += 1;
} else {
countOdd += 1;
}
}
return countOdd == 1 ? true : false
}
then I plan to loop through the words
let emptyArr = [];
for (var x = 0; x < arr.length; x++) {
if (isPalindrome(arr[x]) {
// not sure what to do here. I know the word is a palindrome but not sure how to sort the order of the word in the palindrome form.
} else {
emptyArr.push(-1);
}
}
return emptyArr;
Look closely: you don't need your words to be palindromes, you need them to be rearrangeable as palindromes ("palindrome-candidates"). Now, a word is a palindrome-candidate if all of its letters but one can be counted by an even number (2, 4, 6 etc.)
For example, this...
hollo
... is NOT a palindrome, but can become one, as there's 2 'o', 2 'l' and just one 'h' in it. To rearrange, you just move 'h' in the middle, then just place 'o' and 'l' before and after it:
l -> o -> h <- o <- l
So start with splitting each of your words by characters, then either count those characters or just sort them (as #Barmar suggested). If they satisfy the condition, rearrange the letters following the approach given; if not, return null (or any other special value clearly distinguishable from the rest) immediately.
Here's one way to do it:
function rearrangeAsPalindrome(word) {
if (word.length === 1) return word; // easy win first
const charCounter = word.split('').reduce((counter, ch) => ({
...counter,
[ch]: (counter[ch] || 0) + 1
}), {});
const parts = ['', '', '']; // left, middle, right
const entries = Object.entries(charCounter);
for (let i = 0; i < entries.length; ++i) {
const [char, counter] = entries[i];
if (counter % 2) { // odd
if (parts[1] !== '') return null;
// one odd is already here, eject! eject!
parts[1] = char.repeat(counter);
}
else { // even
const half = counter / 2;
parts[0] = char.repeat(half) + parts[0];
parts[2] += char.repeat(half);
}
}
return parts.join('');
}
console.log(rearrangeAsPalindrome('racarrrac')); // crraaarrc
console.log(rearrangeAsPalindrome('aabbcc')); // cbaabc
console.log(rearrangeAsPalindrome('hollo')); // lohol
console.log(rearrangeAsPalindrome('hello')); // null
This function returns null (and does it early) when it realizes the word given cannot be rearranged as a palindrome - or an actual palindrome if it is possible.
This can help
"How to generate distinct palindromes from a string in JavaScript"
https://medium.com/#bibinjaimon/how-to-generate-distinct-palindromes-from-a-string-in-javascript-6763940f5138
I am trying to replace all the letters of a string by the next letter in the alphabet.
For example: a --> b or i --> j.
My program is ignoring the if statement that checks a letter against the alphabet array. When I try running the code it replaces all letters by "A", the last element in the alphabet array.
Although inefficent, I cannot find any errors with this algorithm. So why is the program ignoring the if statement?
function LetterChanges(str){
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","a"];
str = str.toLowerCase();
var ans = str.split("");
for(i = 0; i < ans.length; i ++)//Running through for each letter of the input string
{
for(a = 0; a < 26; a++)//Checking each letter against the alphabet array
{
if(alphabet[a] == ans[i])
{
ans[i] = alphabet[a+1];
}
}
}
return ans;
}
LetterChanges("Argument goes here");
The reason why it is not working, is because the ans array is modified, whilst you are still checking it.
In this loop:
for(a = 0; a < 26; a++)//Checking each letter against the alphabet array
{
if(alphabet[a] == ans[i])
{
ans[i] = alphabet[a+1];
}
}
If the if statement is found to be true, ans[i] will be updated, but then on the next loop of the iteration, it will likely be true again, as you are checking against the updated ans[i] variable.
As #xianshenglu suggested, you can fix this issue by adding a break to escape from the inner loop once a correct match is found.
for(a = 0; a < 26; a++) {
if(alphabet[a] == ans[i]) {
ans[i] = alphabet[a+1]
// escape from the inner loop once a match has been found
break
}
}
For an alternative way to do this, you could do the following:
var result = str.toLowerCase().split('').map(ch => {
var pos = alphabet.indexOf(ch)
return pos >= 0 ? alphabet[pos + 1] : ch
}).join('')
And if you want to get rid of the alphabet array, you can use char codes. For example:
var result = str.toLowerCase().split('').map(ch => {
var code = ch.charCodeAt(0)
if(code < 96 || code > 122){ return ch }
return String.fromCharCode((code - 96) % 26 + 97)
}).join('')
you lost break when if executed
function LetterChanges(str){
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","a"];
str = str.toLowerCase();
var ans = str.split("");
for(i = 0; i < ans.length; i ++)//Running through for each letter of the input string
{
for(a = 0; a < 26; a++)//Checking each letter against the alphabet array
{
if(alphabet[a] == ans[i])
{
ans[i] = alphabet[a+1];
break;
}
}
}
return ans;
}
console.log(LetterChanges("Argument goes here"));