How to validate brackets '((()))''? [closed] - javascript

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
I had a problem on my last interview with the next task:
Make the function that will validate the count of the brackets and if each opens bracket will have the close bracket (like () or (((())))) - the validation must be true, in other way (like (( or )( or ()()))) - must be false.
I mean that the count of open brackets must equal to the count of close brackets.
If some one can explain me how it must work I'll be happy. Thanks!
function validator(brackets) {
...// some code
}
const goodBrackets = '(((())))';
const badBrackets = '(()())))';
const veryBadBrackets = '(()())()))';
validator(goodBrackets);
validator(badBrackets);
validator(veryBadBrackets);

This can be done using stack, but this is not necessary (extra memory). To check the balance, you will need only a counter which will be incremented in case of ( and decremented if encounter any ). At any point if you encounter an ) and the counter is less than 1, that means you don't have any ( to match current right parenthesis. So its not valid. At the end, if counter is 0 meaning the expression is balanced.
I don't know javascript, this is some sort of pseudocode:
function validator(string expression) {
count := 0
for (int i = 0; i < expression.length; i++):
if (expression[i] == '('):
count++
else if (expression[i] == ')'):
if (count == 0):
return false
else:
count--
end //for
if (count == 0):
return true
return false
}

There are multiple ways you can check for valid braces.
validator=B=>(X=B.replace(/\(\)|\[]|{}|<>/,''))==B?!B:validator(X)
Recursive. (will provide an explanation in a bit). Checks for all brackets ()/[]/{}/<>
Explanation :
validator = Bracket => { // define the function and parameter Bracket
X = Bracket.replace(/\(\)|\[]|{}|<>/,'') // replace all of these with empty strings
return X == B ? !B : validator(X) // if empty string then !B is returned (guess what that is
// other wise repeat with X as input
Another one is far simpler :
Validator = (braces) => { // define function and parameter braces
while(/\(\)|\[\]|\{\}/g.test(braces)){ // while there are still any of these left
braces = braces.replace(/\(\)|\[\]|\{\}/g,"") // keep replacing with ''
}
return !braces.length; // return the opposite of brace.length after that
// 0 becomes 1 and 1 becomes 0
}
Another answer : (I think beats my first one for being overly weird)
Validator = (b, X) => {
for(; (X= b.replace(/\[\]|\{\}|\(\)/, '')) != b; b = X);
return!X
}
Lengthy explanation :
This is the lengthy explanation for the first method for validating brackets :
/**
define function brackets
#param {string} brackets to test
**/
const Validator = (brackets) => {
// create a variable check
let check = brackets.replace(
/ // start regexp
\(\) // Check for parenthesis ( and )
| // OR
\[] // Check for square brackets [ and ]
| // OR
{} // Check for brackets { and }
| // OR
<> // Check for < and >
/ // end regexp
, // replace all this with
'' // empty string
) // end replace
// check if check is equal to brackets
if (check === brackets) {
// if so then return the inverse of bracket
return !brackets
}
// otherwise
return Validator(check); // otherwise set the parameter equal to check and repeat

Create a status variable that is initially set to 0.
Create a loop that looks at the characters in the string from beginning to end.
Inside the loop, first check the character. If it is '(', increase the status variable. If it is ')', decrease the status variable.
If the status variable becomes negative, the expression is invalid and you may exit.
If the status variable is 0 again after the loop finishes, the expression is valid.
I leave the coding up to you. ;)
Edit: veryBadBrackets might be correct. Depends on the kind of expression, of course. ((A OR B) AND (C OR D)) OR (E AND (F OR G)) might be such an expression. Nothing wrong with it.
Edit 2: Ah. veryBadBrakets now has more closing brackets than opening brackets... Then it will correctly fail.

function validate(input) {
let tmp = 0;
for (c of input) {
if (c === '(') tmp++;
else if (c === ')' && --tmp < 0) return false; // Unexpected ')'
}
return tmp === 0; // False if unbalanced
}
const goodBrackets = '(((())))';
const badBrackets = '(()())))';
const veryBadBrackets = '(()())()))';
console.log(validate(goodBrackets));
console.log(validate(badBrackets));
console.log(validate(veryBadBrackets));

What I would do is test one item from each end of the string, looping till we get to the middle.
const goodBrackets = '(((())))';
const badBrackets = '(()())))';
const veryBadBrackets = '(()())()';
function validate(b) {
// make sure we have an even number of paren
if (b % 2 == 0) return false
// Split the items into an array
let items = b.split('')
// Test how many items to loop over
let t = b.length / 2
for (let i = 0; i < t; i++) {
// Get the item from the begining
let first = items[i]
// Get the item form the other side
let last = items[items.length - i - 1]
// Test the two, they should not match to be valid
// If they do match then return false
if (first == last) return false
}
return true
}
console.log(validate(goodBrackets))
console.log(validate(badBrackets))
console.log(validate(veryBadBrackets))

Related

Check length between two characters in a string

So I've been working on this coding challenge for about a day now and I still feel like I haven't scratched the surface even though it's suppose to be Easy. The problem asks us to take a string parameter and if there are exactly 3 characters (not including spaces) in between the letters 'a' and 'b', it should be true.
Example: Input: "maple bread"; Output: false // Because there are > 3 places
Input: "age bad"; Output: true // Exactly three places in between 'a' and 'b'
Here is what I've written, although it is unfinished and most likely in the wrong direction:
function challengeOne(str) {
let places = 0;
for (let i=0; i < str.length; i++) {
if (str[i] != 'a') {
places++
} else if (str[i] === 'b'){
}
}
console.log(places)
}
So my idea was to start counting places after the letter 'a' until it gets to 'b', then it would return the amount of places. I would then start another flow where if 'places' > 3, return false or if 'places' === 3, then return true.
However, attempting the first flow only returns the total count for places that aren't 'a'. I'm using console.log instead of return to test if it works or not.
I'm only looking for a push in the right direction and if there is a method I might be missing or if there are other examples similar to this. I feel like the solution is pretty simple yet I can't seem to grasp it.
Edit:
I took a break from this challenge just so I could look at it from fresh eyes and I was able to solve it quickly! I looked through everyone's suggestions and applied it until I found the solution. Here is the new code that worked:
function challengeOne(str) {
// code goes here
str = str.replace(/ /g, '')
let count = Math.abs(str.lastIndexOf('a')-str.lastIndexOf('b'));
if (count === 3) {
return true
} else return false
}
Thank you for all your input!
Here's a more efficient approach - simply find the indexes of the letter a and b and check whether the absolute value of subtracting the two is 4 (since indexes are 0 indexed):
function challengeOne(str) {
return Math.abs(str.indexOf("a") - str.indexOf("b")) == 4;
}
console.log(challengeOne("age bad"));
console.log(challengeOne("maple bread"));
if there are exactly 3 characters (not including spaces)
Simply remove all spaces via String#replace, then perform the check:
function challengeOne(str) {
return str = str.replace(/ /g, ''), Math.abs(str.indexOf("a") - str.indexOf("b")) == 4;
}
console.log(challengeOne("age bad"));
console.log(challengeOne("maple bread"));
References:
Math#abs
String#indexOf
Here is another approach: This one excludes spaces as in the OP, so the output reflects that. If it is to include spaces, that line could be removed.
function challengeOne(str) {
//strip spaces
str = str.replace(/\s/g, '');
//take just the in between chars
let extract = str.match(/a(.*)b/).pop();
return extract.length == 3
}
console.log(challengeOne('maple bread'));
console.log(challengeOne('age bad'));
You can go recursive:
Check if the string starts with 'a' and ends with 'b' and check the length
Continue by cutting the string either left or right (or both) until there are 3 characters in between or the string is empty.
Examples:
maple bread
aple brea
aple bre
aple br
aple b
ple
le
FALSE
age bad
age ba
age b
TRUE
const check = (x, y, z) => str => {
const exec = s => {
const xb = s.startsWith(x);
const yb = s.endsWith(y);
return ( !s ? false
: xb && yb && s.length === z + 2 ? true
: xb && yb ? exec(s.slice(1, -1))
: xb ? exec(s.slice(0, -1))
: exec(s.slice(1)));
};
return exec(str);
}
const challenge = check('a', 'b', 3);
console.log(`
challenge("maple bread"): ${challenge("maple bread")}
challenge("age bad"): ${challenge("age bad")}
challenge("aabab"): ${challenge("aabab")}
`)
I assume spaces are counted and your examples seem to indicate this, although your question says otherwise. If so, here's a push that should be helpful. You're right, there are JavaScript methods for strings, including one that should help you find the index (location) of the a and b within the given string.
Try here:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String#instance_methods

Javascript - Find opening and closing bracket positions on a string?

I'm making a calculator for a site project of mine where you can type your entire expression before resolving, for example: 2+3*4 would return 14, 22-4 would return 18, 20+5! would return 140, and so on.
And that works for simple expressions like the ones I showed, but when I add brackets the code breaks.
So a simple expression like (2+3)! that should return 120 actually returns 10 or 2+3!.
my original ideia to make even the basic 2+3! work was to separate the string in math simbols and the rest. so it would separate in this case it would separate it into 2, + and 3!; where it would find the symbol and resolve just that part. And that's why it solves 10 instead of not working.
But after trying to solve I couldn't make the code work except in a extremely specific situation, so I decided to redo the code and post this here in case someone could help me out.
This is the function that I'm currently using to prepare my string for evaluation:
function sepOperFat(){
//2+3! it's working
//1+(2-(2+2)+3)! want that to work in the end
var value = document.calculator.ans.value;
var operandoPos = ['0'];
var operandoInPos = [''];
var paraResolver = [];
for(i = 0; i <= value.length; i++){
//check if value[i] is equal to +, -, ×, ÷, * & /
if(value[i] == '+' || value[i] == '-' || value[i] == '×' || value[i] == '÷' || value[i] == '*' || value[i] == '/'){
operandoPos.push(i);
operandoInPos.push(value[i]);
}
}
paraResolver.push(value.slice(operandoPos[0], operandoPos[1]));
for(var total = 1; total <= operandoPos.length; total++){
paraResolver.push(value.slice(operandoPos[total] + 1, operandoPos[total + 1]));
}
document.calculator.ans.value = '';
for(var total = 0; total <= paraResolver.length - 2; total++){
if(paraResolver[total].includes('!')){
document.calculator.ans.value += "factorial(" + paraResolver[total] + ")";
}else{
document.calculator.ans.value += paraResolver[total];
}
document.calculator.ans.value += operandoInPos[total + 1];
}
}
document.calculator.ans.value is the name of the string where i have the expression.
operandoPos is the position on the string where a symbol is at.
operandoInPos is the symbol (I maybe could have used value.charAt(operandoPos) for that too).
paraResolver is the number that I will be solving (like 3).
factorial( is the name of my function responsible for making the number factorial.
the function doesn't have a return because I still want to solve inside the document.calculator.ans.value.
to resolve the equation I'm using document.calculator.ans.value = Function('"use strict"; return '+ document.calculator.ans.value)(); that activates when I press a button.
And yeah, that's it. I just want a function capable of knowing the difference between (2+3)! and 2+(3)! so it can return factorial(2+3) instead of (2+factorial(3)).
Thank you for your help.
Your biggest problem is going to be that order of operations says parentheses need to be evaluated first. This might mean your code has to change considerably to support whatever comes out of your parentheses parsing.
I don't think you want all of that handled for you, but an approach you can take to sorting out the parenthesis part is something like this:
function parseParentheses(input) {
let openParenCount = 0;
let myOpenParenIndex = 0;
let myEndParenIndex = 0;
const result = [];
for (let i = 0; i < input.length; i++) {
if (input[i] === '(') {
if (openParenCount === 0) {
myOpenParenIndex=i;
// checking if anything exists before this set of parentheses
if (i !== myEndParenIndex) {
result.push(input.substring(myEndParenIndex, i));
}
}
openParenCount++;
}
if (input[i] === ')') {
openParenCount--;
if (openParenCount === 0) {
myEndParenIndex=i+1;
// recurse the contents of the parentheses to search for nested ones
result.push(parseParentheses(input.substring(myOpenParenIndex+1, i)));
}
}
}
// capture anything after the last parentheses
if (input.length > myEndParenIndex) {
result.push(input.substring(myEndParenIndex, input.length));
}
return result;
}
// tests
console.log(JSON.stringify(parseParentheses('1!+20'))) // ["1!+20"]
console.log(JSON.stringify(parseParentheses('1-(2+2)!'))) // ["1-",["2+2"],"!"]
console.log(JSON.stringify(parseParentheses('(1-3)*(2+5)'))) // [["1-3"],"*",["2+5"]]
console.log(JSON.stringify(parseParentheses('1+(2-(3+4))'))) // ["1+",["2-",["3+4"]]]
this will wrap your input in an array, and essentially group anything wrapped in brackets into nested arrays.
I can further explain what's happening here, but you're not likely to want this specific code so much as the general idea of how you might approach unwrapping parenthesis.
It's worth noting, the code I've provided is barely functional and has no error handling, and will behave poorly if something like 1 - (2 + 3 or 1 - )2+3( is provided.

My code should be detecting if a string has currency symbols, but it will not detect £

My code is supposed to detect currency symbols, and execute code based on the result, but the code will not detect the '£' under any circumstances. Here is the relevant code:
let requirements = [ "£", "$" ];
let mcontent = "$£50";
let y = 0;
for (let p = 0; p < requirements.length; ++p) {
if (mcontent.includes(requirements[p])) {
++y;
}
}
if (y == 1) {
//this is considered success, only ONE currency symbol was detected. If mcontent = '$50' or '£50', we should be here.
} else {
//this is considered failure, TWO or ZERO currency symbols were detected. In this scenario, I want the code to fail.
}
I'm aware this may not be the best way to code a function to accomplish what I'm trying to accomplish, so I'm open for better ideas/fixes for what I already have.
The most concise way to do this is to check with RegExp like this:
if (mcontent.match(/£|\$/g)?.length == 1) { // the question mark is so we don't encounter an error if no matches were found
// success
} else {
// failure
}
Here's a live example:
const mcontent1 = '$£50';
const mcontent2 = '£50';
const mcontent3 = '$50';
const regex = /£|\$/g; // slash to escape $ because it has special meaning in regex
console.log(mcontent1.match(regex).length == 1); // false
console.log(mcontent2.match(regex).length == 1); // true
console.log(mcontent3.match(regex).length == 1); // true
If you don't want to use regex, just check if the string includes a symbol, increment a counter, and return whether or not there was exactly 1 match:
let testA = "$£50",
testB = "£50",
testC = "$50";
function checkString(str) {
const symbols = ["£", "$"];
let matches = 0;
for (const symbol of symbols)
if (str.includes(symbol)) matches++;
return matches == 1;
}
console.log(
checkString(testA),
checkString(testB),
checkString(testC)
);
Use RegExp it will return true or flase based on value entred
this example will give you an idea of how to use it
const elementTwo = document.getElementById('elementTwo');
elementTwo.addEventListener("input", function(event) {
pattern = /^[£|$]{1}(\d+)/
if (pattern.test(this.value)) {
console.log("found")
} else console.log("not found")
});
<p>Enter value</p>
<input id="elementTwo" type="text" />

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.

Count Vowels in String Using Recursion With JavaScript

Hello I'm trying to understand recursion in JavaScript.
So far I have:
function countVowels(string) {
let vowelCount = 0;
// if we're not at the end of the string,
// and if the character in the string is a vowel
if (string.length - 1 >= 0 && charAt(string.length -1) === "aeiouAEIOU") {
//increase vowel count every time we iterate
countVowels(vowelCount++);
}
return vowelCount;
}
First of all, this is giving me issues because charAt is not defined. How else can I say "the character at the current index" while iterating?
I can't use a for-loop - I have to use recursion.
Second of all, am I using recursion correctly here?
countVowels(vowelCount++);
I'm trying to increase the vowel count every time the function is called.
Thanks for your guidance.
If you're interested, here is a version that does not keep track of the index or count, which might illuminate more about how the recursion can be done.
function countVowels(string) {
if (!string.length) return 0;
return (
"aeiou".includes(string.charAt(0).toLowerCase()) +
countVowels(string.substr(1))
);
}
console.log(countVowels("")); // 0
console.log(countVowels("abcde")); // 2
console.log(countVowels("eee")); // 3
// Note that:
console.log('"hello".substr(1)', "hello".substr(1)) // ello
console.log('"hello".charAt(0)', "hello".charAt(0)) // h
console.log('"aeiou".includes("a")', "aeiou".includes("a")) // true
console.log('"a".includes("aeiou")', "a".includes("aeiou")) // false
Our base case is that the string is empty, so we return 0.
Otherwise, we check if the first character in the string is a vowel (true == 1 and false == 0 in javascript) and sum that with counting the next (smaller by one) string.
You are making two mistakes:
You should have three parameters string , count(count of vowels) and current index i.
You should use includes() instead of comparing character with "aeiouAEIOU"
function countVowels(string,count= 0,i=0) {
if(!string[i]) return count
if("aeiou".includes(string[i].toLowerCase())) count++;
return countVowels(string,count,i+1);
}
console.log(countVowels("abcde")) //2
As asked by OP in comments "Can you please explain why it'sif("aeiou".includes(string[i].toLowerCase())) instead of if(string[i].includes("aeiou".toLowerCase()))"
So first we should know what includes does. includes() checks for string if it includes a certain substring passed to it or not. The string on which the method will be used it will be larger string and the value passed to includes() be smaller one.
Wrong one.
"a".includes('aeiou') //checking if 'aeiou' is present in string "a" //false
Correct one.
"aeiou".includes('a') //checking if 'a' is present in string "aeiou" //true
One possible solution would be:
function countVowels(string, number) {
if (!string) return number;
return countVowels(string.slice(1), 'aeiouAEIOU'.includes(string[0])? number + 1 : number);
}
// tests
console.log('abc --> ' + countVowels('abc', 0));
console.log('noor --> ' + countVowels('noor', 0));
console.log('hi --> ' + countVowels('hi', 0));
console.log('xyz --> ' + countVowels('xyz', 0));
and you should call your function like: countVowels('abc', 0)
Notes about your solution:
you always reset vowelCount inside your function, this usually does not work with recursion.
you defined your function to accept a string, but recall it with an integer in countVowels(vowelCount++); this it will misbehave.
always remember that you have to define your base case first thing in your recursion function, to make sure that you will stop sometime and not generate an infinite loop.
Alternative ES6 solution using regex and slice() method. Regex test() method will return true for vowels and as stated in a previous answer JavaScript considers true + true === 2.
const countVowels = str => {
return !str.length ? 0 : /[aeiou]/i.test(str[0]) + countVowels(str.slice(1));
}

Categories