Rearranging a string to be a palindrome - javascript

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

Related

Java script flexible walk thru a string and return number of char

I have a task where I have to iterate thru a string and return a predefined number of chars in a row. So f.i. the string is "Thisisatest" and I have to start on the first position and return two characters. Have to proof them for som uniques (outside that scope) and if not proofed I have to shift the start be one and start on the second position and return two characters. Have to repeat this as long as I found a unique pair of chars or reached the end of the string.
So f.i. first loop: returns Th, then hi, is, si, is, sa, at...
Used this script:
function setInitials(Start,Num,Str){
var initials=""
if(Number(Start)+Number(Num)-1 < Str.length){
for (var i = Number(Start); i < Number(Num); i++) {
initials += Str[i];
}
}
return initials
}
where Start ist my Starting point, Num the Number of Chars to return ans Str the string.
But if I try setInitials("2","2","Thisiaatrest") I will get back nothing
after more search I found the problem- the start end endpoint were the same.
so the correct working function is:
function setInitials(Start,Num,Str){
var initials=""
var end = Number(Start)+Number(Num)-1
if(end-1 < Str.length){
for (var i = Number(Start)-1; i < end; i++) {
initials += Str[i];
}
}
return initials
}
You can check my solution.
function setInitials(start = 0, span = 0, str = '') {
const [obj, tmp] = [{}, []];
let [left, right, count] = [start, start, 0];
while (right < str.length) {
const char = str[right];
if (!obj[char]) {
obj[char] = 1;
count++;
} else {
obj[char]++;
}
tmp.push(char);
while (left < str.length && right - left + 1 === span) {
const _char = str[left];
if (count === span) return tmp.join('');
obj[_char] = Math.max(obj[_char] - 1, 0);
if (obj[_char] === 0) count--;
tmp.shift();
left++;
}
right++;
}
return 'Not Found';
}
console.log(setInitials(0, 2, 'Thisisatest'));
console.log(setInitials(2, 2, 'Thisiaatrest'));
console.log(setInitials(0, 3, 'aaaabcaa'));
console.log(setInitials(0, 3, 'aaaaaaaa'));

i need to find the distance between two characters in string js. i have a solution but i can't understand the snippet of code related to if statement

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'))

Assistance with javascript palindrome

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>

How find the length of the longest substring?

Need find the length of the longest substring that consists of the same letter. For example, line "aaabbcaaaa" contains four substrings with the same letters "aaa", "bb","c" and "aaaa".
i found two way to do that, but all not so good;
At first way i don't make check previos similar letters here sdsffffse;
Because i check only current element and second element if(line[i] === line[i+1]).
At second way i fail when i try to check how many aa i found in that string abababaab but in object i add all a letters and length = 5;
function longRepeat(line) {
let count = {};
let letter = [];
for (let i=0; i<line.length; i++) {
count[line[i]] = i;
if(line[i] === line[i+1]){
letter.push([line[i], line[i+1]])
}
}
/*
second way
for (let x of line) {
count[x] = ~~count[x] + 1;
} */
return letter;
}
console.log(longRepeat('sdsffffse')); f = 4
console.log(longRepeat('ddvvrwwwrggg')); = 3
console.log(longRepeat('abababaab')); // last two a = 2
Possible solution:
function longestSubstr(str) {
if (!str) return 0
let maxL = 1
let curL = 1
for (let i = 0; i < str.length - 1; i++) {
let cur = str[i]
let next = str[i + 1]
if (cur === next) {
curL++
} else {
if (maxL < curL) maxL = curL
curL = 1
}
}
if (maxL < curL) maxL = curL
return maxL
}
console.log(longestSubstr("abababaab")) // 2
If you don't mind using regular expressions.
function func(line) {
let reg = /(\w)\1+/g;
let longest = line.match(reg).sort((a, b) => {
a.length - b.length
}).pop();
console.log(line + ' : ' + longest);
}
func('ddvvrwwwrggg');
func('sdsffffse');
func('abababaab');
func('aaabbcaaaa');
func('aaaasdfbbbbyyyweryyyuurweuuuuuu');
/(\w)\1+/g will match a sequence of the same character, using the match() method we get all the sequences, sort them by length, and get the last item in the array, i didn't know what to do in case of equal length, so i'll leave that you, i'm merely presenting an idea, and it's for you to improve it :)
#python
def long_repeat(line):
line = line.lower()
max = 1
if len(line) == 0:
return 0
for i in range(0, len(line) - 1):
count = 1
while line[i] == line[i + 1]:
count += 1
if max < count:
max = count
if i < len(line) - 2:
i += 1
else:
break
return max

Comparison operator not working(Java Script)

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"));

Categories

Resources