understanding solution of Valid Anagram in javascript - javascript

This is from LeetCode - Valid Anagram
Given two strings s and t , write a function to determine if t is an anagram of s.
Example 1:
Input: s = "anagram", t = "nagaram"
Output: true
Example 2:
You may assume the string contains only lowercase alphabets.
Follow up:
What if the inputs contain unicode characters? How would you adapt your solution to such case?
I don't understand these code below
result1[s.charCodeAt(i) - 97]++; --> what does ++ mean?
result2.length = 26; --> what does 26 stand for?
result2.fill(0); --> why does fill it with 0?
Please advise!
var isAnagram = function(s,t) {
if (s.length !== t.length)
result false;
const result1 = [];
result1.length = 26;
result1.fill(0);
const result2 = [];
result2.length = 26;
result2.fill(0);
for (let i = 0; i < s.length; i++) {
result1[s.charCodeAt(i) - 97]++;
result2[t.charCodeAt(i) - 97]++;
}
for (let i = 0; i < result1.length; i++) {
if (result1[i] !== result2[i]) {
return false;
}
}
return true;
};

This is my version of solution. You can even skip join() at the end of, since you still can compare two arrays.
const isAnagram = function(s, t) {
if (s.length !== t.length ) {
return false;
}
if (s.split('').sort().join('') === t.split('').sort().join('')) {
return true;
} else {
return false;
}
};

That's somewhat poorly written code, let's improve it a bit so that your question are automatically gone:
var isAnagram = function(string1, string2) {
if (string1.length !== string2.length)
return false; // here was a typo: result false
const alphabetLength = 26;
// returns an array of zeros (empty counters), each one per alphabet letter
const getAlphabetCounters = function() {
const counters = [];
counters.length = alphabetLength;
counters.fill(0);
return counters;
}
const countCharacter = function(c, counters) {
// zero for a, 25 for z
const position = c.charCodeAt(0) - 97;
counters[position]++;
}
const counters1 = getAlphabetCounters();
const counters2 = getAlphabetCounters();
for (let i = 0; i < string1.length; i++) {
countCharacter(string1[i], counters1);
countCharacter(string2[i], counters2);
}
for (let i = 0; i < counters1.length; i++) {
if (counters1[i] !== counters2[i]) {
return false;
}
}
return true;
};
But it would be probably a better idea to use a "decremental" approach like this:
var isAnagram = function(string1, string2) {
if (string1.length !== string2.length)
return false;
let letters1 = string1.split('');
let letters2 = string2.split('');
for (let letter of letters1) {
let position = letters2.indexOf(letter);
if(position == -1)
return false;
letters2.splice(position, 1);
}
return true;
};
or if one cares about performance for long strings, sorting letters in those and direct comparison would be the way to go.

++ is the increment operator. It can be pre-fixed (++i) or post-fixed (i++). In this case it is post-fixed: result1[s.charCodeAt(i) - 97]++, so it will increment the value of result1[s.charCodeAt(i) - 97].
26 is simply the number of letters in the alphabet (from a to z).
The code is initializing the two arrays and filling them with 0s so that it can use the array elements as counters. Each index in the array represents a letter in the alphabet, and stores the occurrences of that letter in the string.

With minimum array functions and single for loop
function anagram(str1, str2){
var isAnagram = true;
if(str1.length != str2.length){
isAnagram = false;
}else{
for(var i=0; i<str1.length;i++) {
if(!str2.includes(str1[i])){
isAnagram = false;
}
}
}
if(isAnagram){
console.log('string is anagram');
}else{
console.log('string is not anagram');
}
}
anagram('READ', 'DEAR');

var isAnagram = function(s, t) {
let sArr = s.split('');
let tArr = t.split('');
sArr.sort();
let newS = sArr.join('');
tArr.sort();
let newT = tArr.join('');
return newS === newT;
};

this can be done with only one line of code
const isAnagram = (s,t) => ( [...s].sort().join('') === [...t].sort().join(''))
console.log( isAnagram('anagram', 'nagaram') ) // true
console.log( isAnagram('anagram', 'xxx') ) // false
But your question also asks to manage all the utf8 characters, which I interpret as having to eliminate the diacritic, for which there is an answer here.
that I changed a little to keep only the letters (which excludes spaces and other punctuation), to be able to process anagrams of several words too :
const letters = str => str.toLowerCase().normalize("NFD").replace(/[^a-z]/g, '')
which has for final solution:
const letters = str => str.toLowerCase().normalize("NFD").replace(/[^a-z]/g, '')
, isAnagram = (s,t) => ( [...letters(s)].sort().join('') === [...letters(t)].sort().join(''))
;
const anagrams = // from wikipedia
[ { s: "evil"
, t: "vile" }
, { s: "New York Times"
, t: "monkeys write" }
, { s: "William Shakespeare"
, t: "I am a weakish speller" }
, { s: "Le commandant Cousteau"
, t: "Tout commença dans l'eau" } // with diacritic ( French )
, { s: "La crise économique"
, t: "Le scénario comique" }
, { s: "Question sans réponse"
, t: "Enquêtons sans espoir" }
, { s: "Chauve-souris"
, t: "Souche à virus" }
]
for (let {s,t} of anagrams )
console.log(`_${s}_, _${t}_ -> `, isAnagram(s,t))
.as-console-wrapper { max-height: 100% !important; top: 0; }

Related

check if text is a subset of a serie

I want to check a string against a serie (with respect to order)
-- see bellow for another approach (string solution)
Regex solution (potential)
r = /[(qw|az)ert(y|z)uiop(é|å|ü)]{5}/g
str = "ertyu"
str2 = "rtrrr"
r.test(str) // true
r.test(str2) // true
The str2 should return false as it does not respect the order, but since the regex is wrapped in array I assume this approach is wrong from the start.
String solution
arr = [
"qwertyuiopé",
"qwertyuiopå",
"qwertyuiopü",
"qwertzuiopé",
"qwertzuiopå",
"qwertzuiopü",
"azertyuiopé",
"azertyuiopå",
"azertyuiopü",
"azertzuiopé",
"azertzuiopå",
"azertzuiopü",
]
str = "ertyu"
str2 = "yrwqp"
function test(s) {
for (const a of arr) {
if (a.indexOf(str) >= 0) return true
}
return false
}
test(str) // true
test(str2) // false
The string version works but its ugly and big
Is there a way with regex to get this working?
In the end I don't think what I want to achieve would be possible,
I ended up with an array of different series (keyboard trivial series)
and a function that checks if a password is a sequence of the series
const trivialseries = [
// swedish, german, french, english, spanish, italian - keyboard
"1234567890",
"qwertyuiopå", // se|en
"asdfghjklöä",
"zxcvbnm",
"qwertzuiopü", // de
"yxcvbnm",
"azertyuiop", // fe
"qsdfghjklmù",
"wxcvbn",
"asdfghjklñ", // sp
"qwertyuiopé", // it
"asdfghjklòàù",
];
const MAX = 5;
function subsequence(serie, str) {
for (let i = 0; i < str.length - MAX + 1; i++) {
const index = serie.indexOf(str[i]);
if (index >= 0) {
let found = 1;
for (let j = i + 1; j < str.length; j++) {
if (serie[index + found] === str[j]) found++;
else break;
if (found === MAX) return true;
}
}
}
return false;
}
function isTrivial(password) {
for (let ts of trivialseries) {
if (subsequence(ts, password)) return true;
const reverse = ts.split("").reverse().join("");
if (subsequence(reverse, password)) return true;
}
return false;
}
console.log(isTrivial("e927ncsmnbvcdkeloD€%s567jhdoewpm")); // true "mnbvc" is reverse form of "cvbnm"

binary Pattern Matching in ES6 with (pattern, s) as strings

Given two strings pattern and s. The first string pattern contains only the
symbols 0 and 1, and the second string s contains only lowercase English
letters.
Let's say that pattern matches a substring s[l..r] of s if the following 3
conditions are met:
they have equal length;
for each 0 in pattern the corresponding letter in the substring is a vowel;
for each 1 in pattern the corresponding letter is a consonant.
the task is to calculate the number of substrings of s that match pattern.
Note: In this we define the vowels as a,e,i,o,u, and y. All other
letters are consonants.
I am not challenging anyone here, I have tried different ways but could not achieve. This question was asked in codesignal test assessment recently.
Here is my approach to tackle the problem.
replacing all 0 to a regex matching vowels and 1 to non-vowels from the pattern (after checking the inputs) and using that as regex (with overlapping) on s can help us with the requirements set.
function matchOverlap(input, re) {
var r = [],
m;
// prevent infinite loops
if (!re.global) re = new RegExp(
re.source, (re + '').split('/').pop() + 'g'
);
while (m = re.exec(input)) {
re.lastIndex -= m[0].length - 1;
r.push(m[0]);
}
return r;
}
function algorithm(pattern, s) {
const VOWELS = 'aeiouy'
if (pattern.match('[^01]'))
throw new Error('only 0 and 1 allowed in pattern')
else if (s.match('[^a-z]'))
throw new Error('only a-z allowed in s')
const generatedRegex = new RegExp(
pattern
.replace(/0/g, `[${VOWELS}]`)
.replace(/1/g, `[^${VOWELS}]`),
'g')
console.log("GENERATED REGEX:", generatedRegex)
const matches = matchOverlap(s, generatedRegex)
console.log("MATCHES:", matches)
return matches.length
}
console.log("FINAL RESULT: " + algorithm('101', 'wasistdas'))
// the following throws error as per the requirement
// console.log(algorithm('234234', 'sdfsdf'))
// console.log(algorithm('10101', 'ASDFDSFSD'))
The matchOverlap function used was taken from this answer
You could take check for length first and then check the test with a regular expression for consonants against the pattern and count.
function getCount(pattern, s) {
if (pattern.length !== s.length) return false;
const regExp = /^[^aeiouy]$/;
let count = 0;
for (let i = 0; i < pattern.length; i++) {
if (+regExp.test(s[i]) === +pattern[i]) count++;
}
return count;
}
console.log(getCount('010', 'ama'));
you should convert the input string to binary format.
function convertToBinary(source) {
var vowels = 'aeiouy'
var len = source.length
var binaryStr = ''
for (i = 0; i < len; i++) {
binaryStr += vowels.includes(source[i]) ? '0' : '1'
}
return binaryStr
}
function isMatch(txt, pattern) {
return txt === pattern
}
function findMatches(source, pattern) {
var binaryString = convertToBinary(source)
var result = []
var patternLen = pattern.length
for (var i = 0; i < binaryString.length - patternLen; i++) {
if (isMatch(binaryString.substr(i, patternLen), pattern)) {
result.push(source.substr(i, patternLen))
}
}
return result
}
var text = 'thisisaresultoffunction'
var pattern = '1011'
console.log(findMatches(text, pattern))
its result
[ "sult", "toff", "func" ]
This is a brute force C# version
int binaryPatternMatching(string pattern, string s) {
int count = 0;
char[] vowel = {'a', 'e', 'i', 'o', 'u', 'y'};
for(int i=0; i<=(s.Length - pattern.Length); i++){
int k=i;
bool match = true;
bool cTM = true;
int j=0;
while(match == true && j < pattern.Length){
if(pattern[j] == '0')
{
if(vowel.Contains(s[k])){
cTM = true;
}
else{
cTM = false;
}
}
else
{
if(!vowel.Contains(s[k])){
cTM = true;
}
else{
cTM = false;
}
}
k += 1;
j += 1;
match = (match && cTM);
}
if(match){
count += 1;
}
}
return count;
}
can be optimized
got it! also look at this question
the regex lib is more powerful than re
import regex as re
def pattern_finder(pattern,source):
vowels = ['aeouiy']
# using list comprehension to build the regular expression
reg_ex = "".join(['[aeiouy]' if num=='0' else '[^aeiouy]' for num in pattern ])
#finding overlapped patterns
matches = re.findall(reg_ex, source, overlapped=True)
return len(matches)

print like this * "a" -> "a1" * "aabbbaa" -> "a2b3a2"

I am new to js.
can you tell me how to print like this * "a" -> "a1" * "aabbbaa" -> "a2b3a2"
i tried with hash map but test cases failing.
providing my code below.
i am not good in hash map.
can you tell me how to solve with hash map so that in future I can fix it my self.
not sure what data structure to use for this one.
providing my code below.
const _ = require("underscore");
const rle = ( input ) => {
console.log("input--->" + input);
//var someString ="aaa";
var someString = input;
var arr = someString.split("");
var numberCount = {};
for(var i=0; i< arr.length; i++) {
var alphabet = arr[i];
if(numberCount[alphabet]){
numberCount[alphabet] = numberCount[alphabet] + 1;
}
else{
numberCount[alphabet] = 1;
}
}
console.log("a:" + numberCount['a'], "b:" + numberCount['b']);
}
/**
* boolean doTestsPass()
* Returns true if all the tests pass. Otherwise returns false.
*/
/**
* Returns true if all tests pass; otherwise, returns false.
*/
const doTestsPass = () => {
const VALID_COMBOS = {"aaa": "a3", "aaabbc":"a3b2c1"};
let testPassed = true;
_.forEach(VALID_COMBOS, function(value, key) {
console.log(key, rle(key));
if (value !== rle(key)) {
testPassed = false;
}
});
return testPassed;
}
/**
* Main execution entry.
*/
if(doTestsPass())
{
console.log("All tests pass!");
}
else
{
console.log("There are test failures.");
}
You could
match groups of characters,
get the character and the count and
join it to a string.
function runLengthEncoding(string) {
return string
.match(/(.)\1*/g) // keep same characters in a single string
.map(s => s[0] + s.length) // take first character of string and length
.join(''); // create string of array
}
console.log(['a', 'aaa', 'aaabbc'].map(runLengthEncoding));
This is a bit more understandable version which iterates the given string and count the characters. If a different character is found, the last character and count is added to the result string.
At the end, a check is made, to prevent counting of empty strings and the last character cound is added to the result.
function runLengthEncoding(string) {
var result = '',
i,
count = 0,
character = string[0];
for (i = 0; i < string.length; i++) {
if (character === string[i]) {
count++;
continue;
}
result += character + count;
character = string[i];
count = 1;
}
if (count) {
result += character + count;
}
return result;
}
console.log(['', 'a', 'aaa', 'aaabbc'].map(runLengthEncoding));
You can reduce the array into a multidimensional array. map and join the array to convert to string.
const rle = (input) => {
return input.split("").reduce((c, v) => {
if (c[c.length - 1] && c[c.length - 1][0] === v) c[c.length - 1][1]++;
else c.push([v, 1]);
return c;
}, []).map(o => o.join('')).join('');
}
console.log(rle("a"));
console.log(rle("aabbbaa"));
console.log(rle("aaaaaa"));
Your function rle doesn't return a result.
Also note, this implementation may pass the test cases you wrote, but not the examples you mentioned in your question: for the string "aabbaa" this will produce "a4b2", not " a2b2a2" .
A simpler solution:
function runLengthEncoding(str) {
let out = "";
for (let i = 0; i < str.length; ++i) {
let temp = str[i];
let count = 1;
while (i < str.length && str[i+1] == temp) {
++count;
++i;
}
out += temp + count;
} // end-for
return out;
}
console.log(runLengthEncoding("a"));
console.log(runLengthEncoding("aabbbaa"));
console.log(runLengthEncoding("aaaaaa"));

Find the longest occurrence of the "aeiou" in a string

I was recently doing an interview and was asked multiple questions, one of the questions was this and I had a bit of trouble trying to answer it.
Given a string, find the longest occurrence of vowels "aeiou" that appear.
The substring of vowels do not have to be consecutive, and there can be repeats.
The goal is the find the max occurrence of each vowel and join them, but it must be in the order of "a","e","i","o","u".
Edit: In addition, each individual vowel character must be chained as well. In the example below, there is "aaa" and "aa" , since 3 is longer, our result must contain the longer chain.
For example:
Input: "aaagtaayuhiejjhgiiiouaae"
Result: aaaeiiiou
The code that I have tried is below:
EDIT: Following the solution, I have written this below but I am still running into issues with strings such as "aeiouaaaeeeiiiooouuu". The correct result for that would be 15 but I am getting 5.
var findLongestVowels = function(s){
var count = 1;
var i = 0;
var j = 0;
var vowels = ['a','e','i','o','u'];
var total = 0;
var array = [];
while (i < s.length){
if (s.charAt(i) == vowels[j] && s.charAt(i) == s.charAt(i+1) ){
count++;
}
else if (s.charAt(i) == vowels[j] && s.charAt(i) != s.charAt(i+1)){
if (j === 0 && !array[vowels[j]]){
array[vowels[j]] = count;
}
else if (j === 0 && array[vowels[j]]){
array[vowels[j]] = Math.max(array[vowels[j]],count);
}
else if (j !== 0 && !array[vowels[j]] && array[vowels[j-1]]){
array[vowels[j]] = array[vowels[j-1]] + count;
}
else if (j !== 0 && array[vowels[j]] && array[vowels[j-1]]){
array[vowels[j]] = Math.max(array[vowels[j]],array[vowels[j-1]] + count);
}
count = 1;
}
else if (s.charAt(i) == vowels[j+1] && array[vowels[j]]){
j++;
i--;
}
i++;
}
console.log(array);
console.log('Answer: ' + array[vowels[j]]);
}
findLongestVowels("eeeeebbbagtaagaaajaaaaattyuhiejjhgiiiouaae");
Am I at least going in the right direction?
Thanks in advance.
We can solve this in O(n) time. Consider that for each block, if its vowel is at index v in the list of vowels, we are only interested in the best solution for the block with a vowel at index v-1 in the order of vowels. We save the last best solution for each block type (each vowel) as we go along:
|aaa|g|t|aa|y|u|h|i|e|jj|h|g|iii|o|u|aa|e
b: 1 2 3 4 5 6 7 8 9 10
b 1: v[a] = 3
b 2: v[a] = max(2,3)
b 3: v[u] = None recorded for v-1
b 4: v[i] = None recorded for v-1
b 5: v[e] = 1 + 3
b 6: v[i] = 3 + 4
b 7: v[o] = 1 + 7
b 8: v[u] = 1 + 8 // answer
b 9: v[a] = max(2,3)
b 10: v[e] = 1 + 3
JavaScript code:
function f(str){
console.log(`String: ${ str }\n`);
var vowels = {
a: {best: 0, prev: null},
e: {best: 0, prev: 'a'},
i: {best: 0, prev: 'e'},
o: {best: 0, prev: 'i'},
u: {best: 0, prev: 'o'}
};
function getBlock(i){
let length = 1;
while (str[i+1] && str[i] == str[i+1]){
length++;
i++;
}
return length;
}
for (let i=0; i<str.length;){
let length = getBlock(i);
console.log(`i: ${ i }; length: ${ length }`)
if (!vowels[str[i]]){
i = i + length;
continue;
}
if (!vowels[str[i]].prev){
vowels[str[i]].best = Math.max(
vowels[str[i]].best,
length
);
// make sure the previous vowel
// exists in the string before
// this vowel
} else if (vowels[ vowels[str[i]].prev ].best){
vowels[str[i]].best = Math.max(
vowels[str[i]].best,
length + vowels[ vowels[str[i]].prev ].best
);
}
i = i + length;
}
console.log(`\n${ JSON.stringify(vowels) }\n\n`);
return vowels['u'].best;
}
var s = 'eeeeebbbagtaagaaajaaaaattyuhiejjhgiiiouaae';
console.log(f(s) + '\n\n');
s = 'aaagtaayuhiejjhgiiiouaae';
console.log(f(s) + '\n\n');
s = 'aeiouaaaeeeiiiooouuu';
console.log(f(s));
This problem can be solved by using dynamic programming technique.
First, we have string x and we want to find the longest string for this string.
Traversing the string x from start to end, assuming at index i, we are trying to find vowel e, there are two possibilities:
Current character is e, so we take the whole block and move to next character
Or, we can try with the next character
So, we have our pseudocode:
int[][]dp;
int largestBlock (int index, int currentVowel, String x, String vowels){
if (currentVowel == 5) {
// We found all 5 vowel
return 0;
}
if visited this state (index, currentVowel) before {
return dp[index][currentVowel];
}
int result = largestBlock(index + 1, currentVowel, x, vowels) ;
if (x[index] == vowels[currentVowel]){
int nxt = nextIndexThatIsNotVowel(index, currentVowel, x, vowels);
result = max(result, nxt - index + largestBlock(nxt, currentVowel + 1, x , vowels));
}
return dp[index][currentVowel] = result;
}
Time complexity is O(n * m) with m is number of vowels which is 5 in this case.
You need to remember biggest combination of individual vowels.
Use reduce, map and Object.values
var vowels = "aeiou";
var input = "aaagtaayuhiejjhgiiiouaae";
var output = Object.values(
input.split( "" ).reduce( ( a, c, i, arr ) => {
var lastChar = arr[ i - 1 ];
if ( !vowels.includes( c ) ) return a; //if not vowel, return accumulator
if ( c != lastChar ) //if not same as last character then create a new array
{
a[ c ] = a[ c ] || [];
a[ c ].push( [ c ] );
}
else //else push to the last array;
{
var lastCombo = a[ c ].slice( -1 )[ 0 ];
lastCombo.push(c)
}
return a; //return accumulator
} , {}) ).map( s => {
var char = s[0][0]; //find the character to repeat
var maxLength = Math.max.apply( null, s.map( s => s.length ) ); //find how many times to repeat
return Array( maxLength + 1 ).join( char );
}).join( "" ); //join all the vowels
console.log( output );
It's just one of many possible solutions - feel free to try it out.
Store every vowel you're interested in, in vowels array.
Use map to loop over every vowel in array, create regex from vowel to split string into array of vowels. For example "aaabdmedaskaa" would be split into ["aaa", "a", "aa"].
Filter this array so it doesn't include empty strings.
Sort it by length, so accesing 0 element would give you longest occurance
After mapping over every vowel, return the result - filter out "undefined" in case some of your vowels don't occur at all and regex results in empty array (accesing empty array's 0th element would result in undefined), join array of occurances into a result string.
The regex created from "a" will be [^a]+ which means any character sequence that does not include "a".
function findLongestOccurance(str) {
const vowels = ["a", "e", "i", "o", "u"];
const result = vowels.map(vowel => {
const regex = new RegExp(`[^${vowel}]+`);
return str.split(regex)
.filter(r => r !== "")
.sort((a, b) => b.length - a.length)[0];
});
return result.filter(occ => typeof(occ) !== "undefined").join("");
}
console.log(findLongestOccurance("aaagtaayuhiejjhgiiiouaae"));
Why not regex?
var result = /(a+).*(e+).*(i+).*(o+).*(u+)/.exec("aaagtaayuhiejjhgiiiouaae");
console.log(result[1]+result[2]+result[3]+result[4]+result[5]);
First of all, from what I understand from the question the result for Input: "aaagtaayuhiejjhgiiiouaae" should be aaaaaeiiiou, like #PhamTrung asked in the comments but didn't get answered.
Because it a job interview I would start with the first thing that comes to mind, namely brute force the solution out of this
function a(string, prefix='') {
if(!string.length){
return prefix
}
if(!/[aeiou]/.test(string[0])){
return a(string.substr(1), prefix)
}
const option1 = a(string.substr(1), prefix)
const option2 = a(string.substr(1), prefix+string[0])
const validateRegex = /^a+e+i+o+u+$/
const isValidOption1 = validateRegex.test(option1)
const isValidOption2 = validateRegex.test(option2)
if(isValidOption1 && isValidOption2){
if(option1.length > option2.length) {
return option1
}
return option2
}
if(isValidOption1) {
return option1
}
if(isValidOption2) {
return option2
}
return null
}
const input = 'aaagtaayuhiejjhgiiiouaae'
console.log(a(input))
This has a terrible run time though, we are trying all possible substring that contains only vowels, than we are discarding those that aren't of the form required (a+e+i+o+u+) and than choosing only the biggest of them all. If I'm not mistake this has a worst case of ∑(n choose i) which is O(n^n) - well, the actual worst case here would be a stackOverflow exception for sufficiently large n in which case we'd have to reimplement this with a loop instead of recursing. In this case we could still get an out of memory exception in which case we'd be out of options but to improve our algorithm. It's fair to imagine that if the input were large enough that we got an out of memory exception than our code would also be slow enough to not be a reasonable solution to the problem. I'm just arguing all this because these are things that an interviewer would possibly like to see that you are aware of, meaning you know enough of CS 101.
Following that the interviewer would ask if I can improve the performance. This is a solution with running time of O(n).
const input = 'aeiouaaaeeeiiiooouuu'
let curr = { "1": {price: -1} }
const nodes = []
const voewels = '1aeiou'
const getPrevLetter = (node) => voewels[voewels.indexOf(node.letter) -1]
let resultNode
function setUpNodeByCurrent(node, letter){
node.price = curr[letter].price + 1
node.previous = curr[letter]
}
function setBestResultIfNeeded(node){
if(node.letter !== 'u') {
return
}
if(!resultNode || resultNode.price < node.price) {
resultNode = node
return
}
}
function setCurrent(letter){
const node = {
letter,
price: 0
}
const prevLetter = getPrevLetter(node)
if(!prevLetter || !curr[prevLetter]){
// either letter isn't on of aeiou or
// we got to an i without ever seeing an e, an o without ever seeing an i, ... this letter is irrelevant
return
}
if(curr[node.letter]) {
setUpNodeByCurrent(node, node.letter)
}
if(node.price < curr[prevLetter].price + 1) {
setUpNodeByCurrent(node, prevLetter)
}
curr[node.letter] = node
setBestResultIfNeeded(node)
}
function getStringResult(node){
let result = ''
while(node) {
result = node.letter + result
node = node.previous
}
return result
}
function getResult(){
const node = resultNode //getBestResultNode()
const result = getStringResult(node)
console.log(result)
console.log(result.length)
}
for(let l of input){
setCurrent(l)
}
getResult()
This can be seen as a simplification of the longest path problem over a DAG basically you'd run through the string and every a points to the next occurance of a and the next occurance of e. e points to the next e and to the next i and so on. You'd than have a start node pointing to every occurance of a and an end node pointed to by every occurance of u. Now what you want is the longest path from the start node to the end node which is an O(|V|+|E|), now |V|<=n and |E|<=2n since every node in your graph has at most 2 vertices going out of it so the total running time is O(n). I have simplified the code to build the result as it goes on building the graph, basically I already calculate the cost on the go so when I finished building a graph similar to what I described I already know what the result is.
Note that this solution is based on the assumption that the input string is one that necessarily has a solution embedded in it. If the input string is unsolvable (there isn't and aeiou sequence in it) than this case would need to be properly handled, it is actually trivial to add the code that handles that. The first solution will return null in such a case(if I'm not mistaken)
Hope this helps.
If you want to find a substring which contains the maximum number of vowels and you also want to give {specify} the length of the substring then you should use this program:
let newk = s;
const elementsArray = [];
const tempoArray = [];
const counting = [];
const maxPoint = [];
let count
for (var i = 0; i < newk.length; i++) {
while (tempoArray.length > 0) {
tempoArray.pop();
}
let fk = i + k;
if (fk <= newk.length) {
for (let j = i; j < fk; j++) {
tempoArray.push(newk[j]);
}
let makingArray = tempoArray.toString();
elementsArray.push(makingArray);
} else {
// console.log(" ");
}
}
for (let q = 0; q < elementsArray.length; q++) {
count = 0
let tempString = new String(elementsArray[q]).split(",")
for (let l = 0; l < tempString.length; l++) {
if (tempString[l] == "a" || tempString[l] == "e" || tempString[l] == "i" || tempString[l] == "o" || tempString[l] == "u") {
count ++;
}else{
}
}
// console.log(count);
counting.push(count)
}
let max = 0,Maximist
// for (let d = 0; d < counting.length; d++) {
// console.log(counting[d] , " this is the value of the counting array");
// }
for (let t = 0; t <= counting.length; t++) {
if (counting[t] != 0) {
if (max < counting[t]) {
max = counting[t]
Maximist = t
}
else if (max == counting[t]){
max = counting[t]
Maximist = t
}
else{
console.log("");
}
}
}
// console.log(Maximist);
// console.log(max);
// maxPoint.push(Maximist)
for (let t = 0; t <= counting.length; t++) {
if (counting[0] != 0) {
if (max == counting[t]) {
maxPoint.push(t)
}
}
}
for (let e = 0; e < maxPoint.length; e++) {
console.log("{", elementsArray[maxPoint[e]] ,"}")
}
}
findSubstring("captainamerica", 3);
The bigger your size of the substring will be the less chances that there will be less substring with same number of vowels in it

Javascript Cannot call method 'indexOf' of undefined at order

I need to make a function that will sort a string. Each word in the String will contain a single number. Numbers can be from 1 to 9(no 0).
For example an input: "is2 Thi1s T4est 3a" the function should return "Thi1s is2 3a T4est".
My code is :
function order(words)
{
// ...
if(words == '')
{
return words;
}
var all_words = words.split(" ");
var checked_words = new Array();
var joined_words = "";
for(i = 1; i <= 9; i++)
{
//console.log(checked_words);
//checked_words[i-1] = all_words;
for(j = 1;j <= all_words.length; j++)
{
if(all_words[i-1].indexOf(i) != -1)
{
checked_words.push(all_words[i-1]);
if(i == (all_words.length))
{
joined_words = checked_words.join(" ");
return joined_words;
}
}
}
}
}
The problem is it kept showing "TypeError: Cannot call method 'indexOf' of undefined at order". Please help thanks!
I've been trying to figure out what that first loop is doing and I finally realised it's checking for the numbers in the string. You shouldn't do it that way because it's 1) weird, 2) non-peformant if it worked.
Instead use one loop and a regex to find the number in the string.
for (var i = 0; i < all_words.length; i++) {
// take the first match and coerce it to an integer
var n = +all_words[i].match(/\d+/)[0];
checked_words[n] = all_words[i];
}
// checked_words has an undefined element at index 0;
// slice takes a copy of the array from index 1
return checked_words.slice(1).join(' ');
DEMO
Alternatively you could use reduce.
var joined_words = str.split(' ').reduce(function (p, c) {
var n = +c.match(/\d+/)[0];
p[n] = c;
return p;
}, []).slice(1).join(' ');
DEMO
You're not even tied to the numbers 0-9. As long as you filter out the undefined elements, you're golden...
var str = 'is2 Thi1s T4est 3a Ye12s!';
var out = str.split(' ').reduce(function (p, c) {
var n = +c.match(/\d+/)[0];
p[n] = c;
return p;
}, []).slice(1).filter(function (el) {
return el !== undefined;
}).join(' ');
DEMO

Categories

Resources