I have written the logic to check for parenthesis for "(" and ")" but there seems to an issue when parenthesis gets mixed. This is because I'm just comparing the total parenthesis count.
This is what i wrote
function checkParanthesis(str){
var depth=0;
for(var i in str){
if(str[i] == "(" || str[i] == "{" || str[i] == "[")
depth++;
else if(str[i] == ")" || str[i] == "}" || str[i] == "]")
depth--;
}
if(depth !==0) return false;
return true;
}
console.log(checkParanthesis("() test"));
Question:
But how can I check for multiple parenthesis elements? (){}[]
For example,
Input:
"[(]) abcd" // should return false
"[{()}] test" // should return true
Should return false (Not true)
Use an array as a stack to keep track of unresolved opening braces:
function checkParanthesis(str){
var stack=[];
for(var i=0; i<str.length; i++){
if(str[i] == "(" || str[i] == "{" || str[i] == "[")
stack.push(str[i]);
else if(str[i] == ")") {
if(stack.pop() != "(") { return false; }
}
else if(str[i] == "}") {
if(stack.pop() != "{") { return false; }
}
else if(str[i] == "]") {
if(stack.pop() != "[") { return false; }
}
}
return !stack.length;
}
You can probably clean this up to be more readable, but basically:
Every time you find an opening brace, add it to the stack.
Every time you see a closing brace, pop the stack and see if the stack's top is a matching opening brace.
If it's not, you have a mismatch, so you can immediately return false.
If you make it to the end, you didn't spot any errors, return true if the stack is empty (i.e., stack.length is 0).
(Note I also changed your i in str loop since it will iterate over properties on String.prototype.)
One cleanup you could do (but I'm not sure if this makes the code more readable or not) would be to put the brace pairings in an object, with the closing character as the key and the corresponding opening character as the value. Then, see if the current character exists as a key in the object, and if so, pop the stack and see if the value for that key matches:
function checkParanthesis(str){
var stack=[];
var brace_pairings = { ")":"(", "}":"{", "]":"[" };
for(var i=0; i<str.length; i++){
if(str[i] == "(" || str[i] == "{" || str[i] == "[") {
stack.push(str[i]);
} else if(str[i] in brace_pairings) {
if(stack.pop() != brace_pairings[str[i]]) { return false; }
}
}
return !stack.length;
}
Rather than a counter, you could use a stack, pushing a token onto the stack when an opening bracket is seen, and popping from the stack when the correct closing bracket is seen. If a closing bracket is encountered when a different type of bracket is at the top of the stack, or when the stack is empty, the string is unbalances.
Something like this (not polished and tested):
function checkParanthesis(str){
var stack = [];
var open;
for(var i in str){
if(str[i] == "(" || str[i] == "{" || str[i] == "[") {
stack.push(str[i]);
}
else if(str[i] == ")" || str[i] == "}" || str[i] == "]") {
if ( stack.length == 0 ) {
return false;
}
open = stack.pop();
if (
( open == '(' && str[i] != ')' )
|| ( open == '[' && str[i] != ']' )
|| ( open == '{' && str[i] != '}' )
) {
return false;
}
}
}
if ( stack.length > 0 ) {
return false;
}
return true;
}
Use a regex to get all the braces in a match() array...then remove each end of array testing each set
function checkParanthesis(str) {
//hashmap to compare open/close braces
var closers = {'[': ']','(': ')','{': '}'};
// create braces array
var parStack = str.match(/\(|\{|\[|\)|\}|\]/g) || [];
if (parStack.length % 2 !== 0) {//must have even number
return false;
} else {
while (parStack.length) {
// check each end of array against each other.
if (closers[parStack.shift()] !== parStack.pop()) {
//mismatch , we're done
return false;
}
}
return true;
}
}
console.log('no braces ', checkParanthesis("test"));
console.log('matched ', checkParanthesis("() test"));
console.log('mis matched ',checkParanthesis("[(]) abcd")); // should return false
console.log('matched ',checkParanthesis("[{()}] test"));
The array/stack/counter approach reads the string from left to right. Another approach is to work from the inside out.
function checkParanthesis(str){
while ( str.indexOf('()')>=0 || str.indexOf('[]')>=0 || str.indexOf('{}')>=0 ) {
str = str.replace('()','').replace('[]','').replace('{}','');
}
return str.length===0;
}
You could use regular expressions for the replace part to do a global replace and loop fewer times. The downside is that you'd need to escape everything in sight: str.replace(/\(\)/g,'') et.c.
Since I was working on leetCode and find your question, I found this article was written pretty clear about the problem and I tested it and I quoted here:
Click here!
Parenthesis Matching Problem in JavaScript
let isMatchingBrackets = function (str) {
let stack = [];
let map = {
'(': ')',
'[': ']',
'{': '}'
}
for (let i = 0; i < str.length; i++) {
// If character is an opening brace add it to a stack
if (str[i] === '(' || str[i] === '{' || str[i] === '[' ) {
stack.push(str[i]);
}
// If that character is a closing brace, pop from the stack, which will also reduce the length of the stack each time a closing bracket is encountered.
else {
let last = stack.pop();
//If the popped element from the stack, which is the last opening brace doesn’t match the corresponding closing brace in the map, then return false
if (str[i] !== map[last]) {return false};
}
}
// By the completion of the for loop after checking all the brackets of the str, at the end, if the stack is not empty then fail
if (stack.length !== 0) {return false};
return true;
}
Related
Trying to solve a problem at LeetCode called "Valid Parentheses".
Conditions are:
Given a string s containing just the characters '(', ')', '{', '}',
'[' and ']', determine if the input string is valid.
An input string is valid if:
Open brackets must be closed by the same type of brackets. Open
brackets must be closed in the correct order.
I wrote a function and it's working in this snippet:
let arr = ['()']
var isValid = function (data) {
let stack = [];
const bracketsArray = {
'{':'}',
'[':']',
'(':')'
}
for (i=0; i < data[0].length; i++) {
if (data[0][i] == '{' || data[0][i] == '(' || data[0][i] == '[') {
stack.push(data[0][i]);
} else if (data[0][i] == '}' || data[0][i] == ']' || data[0][i] == ')') {
if (bracketsArray[stack[stack.length-1]] == data[0][i]) {
stack.pop()
}
}
}
if (stack.length == 0) {
return true
} else {
return false
}
}
console.log(isValid(arr))
Function gives a correct output (boolean)
But when I run this code at LeetCode for some reason the same code gives me a wrong boolean.
Don't understand what is wrong.
/**
* #param {string} s
* #return {boolean}
*/
var isValid = function(s) {
let stack = [];
const bracketsArray = {
'{':'}',
'[':']',
'(':')'
}
for (i=0; i < s[0].length; i++) {
if (s[0][i] == '{' || s[0][i] == '(' || s[0][i] == '[') {
stack.push(s[0][i]);
} else if (s[0][i] == '}' || s[0][i] == ']' || s[0][i] == ')') {
if (bracketsArray[stack[stack.length-1]] == s[0][i]) {
stack.pop()
}
}
}
if (stack.length == 0) {
return true;
} else {
return false;
}
};
Any advice?
On LeetCode the function parameter is a string, but in your tests you are passing an array, and also your function code expects an array, since it accesses the string with s[0], instead of s.
Unrelated, but:
Your code fails when the input is just a closing bracket. This is because your loop doesn't break with return false when a non-matching closing bracket is encountered. This should happen in the else part of if (bracketsArray[stack[stack.length-1]] == s[i]) {
Don't use an undeclared variable i, which will then implicitly become a global variable (if running in non-strict mode).
Don't name your variable bracketsArray since it is not an array.
Make more use of that object, instead of making three comparisons with opening brackets.
The final if...then is overkill for just returning the value of a boolean expression.
So:
var isValid = function(s) {
const stack = [];
const brackets = {
'{':'}',
'[':']',
'(':')'
}
const closing = Object.values(brackets);
for (let ch of s) {
if (brackets[ch]) {
stack.push(brackets[ch]);
} else if (ch == stack.at(-1)) {
stack.pop()
} else if (closing.includes(ch)) {
return false;
}
}
return !stack.length;
};
console.log(isValid("{([])}")); // true
console.log(isValid("]")); // false
The way you are accessing the current character of the iteration is wrong. Instead of doing s[0][i], simply do s[i].
s[0][i] accesses the first character, and then attempts to get the i-th entry from it (which is undefined).
var isValid = function(s) {
let stack = [];
const bracketsArray = {
'{':'}',
'[':']',
'(':')'
}
for (i=0; i < s.length; i++) {
if (s[i] == '{' || s[i] == '(' || s[i] == '[') {
stack.push(s[i]);
} else if (s[i] == '}' || s[i] == ']' || s[i] == ')') {
if (bracketsArray[stack[stack.length-1]] == s[i]) {
stack.pop()
}
}
}
if (stack.length == 0) {
return true;
} else {
return false;
}
};
isValid("{([])}") // true
isValid("{([)}") // false
Need to find open and closed bracket, if the sequence of opening and closing brackets is violated, then return false.
But if don't revert right array to compare with left array, i don't make check brackets here {[(3+1)+2]+}. And if reverse like now, then i fail to check here [1+1]+(2*2)-{3/3}
function brackets(expression){
let leftArr=[];
let rightArr = [];
for(let i=0; i<expression.length; i++){
if(expression[i] === '(' || expression[i] === '[' || expression[i] === "{"){
leftArr.push(expression[i]);
}
if(expression[i] === ')'){
rightArr.push("(");
}else if(expression[i] === '}'){
rightArr.push("{");
} else if(expression[i] === ']'){
rightArr.push("[");
}
}
rightArr.reverse();
if(leftArr.length<rightArr.length || leftArr.length>rightArr.length){
return false;
}
for(let k=0; k<leftArr.length; k++) {
if(leftArr[k] != rightArr[k]){
return false;
}
}
return true;
}
console.log(brackets('(3+{1-1)}')); // false
console.log(brackets('{[(3+1)+2]+}')); //true
console.log(brackets('[1+1]+(2*2)-{3/3}')); //true
console.log(brackets('(({[(((1)-2)+3)-3]/3}-3)')); //false
In the shortest possible, with comments for lines that are probably confusing for you.
function check(expr){
const holder = []
const openBrackets = ['(','{','[']
const closedBrackets = [')','}',']']
for (let letter of expr) { // loop trought all letters of expr
if(openBrackets.includes(letter)){ // if its oppening bracket
holder.push(letter)
}else if(closedBrackets.includes(letter)){ // if its closing
const openPair = openBrackets[closedBrackets.indexOf(letter)] // find its pair
if(holder[holder.length - 1] === openPair){ // check if that pair is the last element in the array
holder.splice(-1,1) // if so, remove it
}else{ // if its not
holder.push(letter)
break // exit loop
}
}
}
return (holder.length === 0) // return true if length is 0, otherwise false
}
check('[[{asd}]]') /// true
Right now you are getting every single open bracket into one array, then pushing an open bracket for every closing one into another array, then comparing them. That's a bit wasteful.
Instead, you can maintain a stack. Push an open tag onto the stack and if you find a close bracket - pop from the stack
if there is no match or nothing on the stack when you pop, terminate with a failure
if you finish with a stack size of zero, then you are successful
function brackets(expression) {
let stack = [];
let current;
const matchLookup = {
"(": ")",
"[": "]",
"{": "}",
};
for (let i = 0; i < expression.length; i++) {
current = expression[i]; //easier than writing it over and over
if (current === '(' || current === '[' || current === "{") {
stack.push(current);
} else if (current === ')' || current === ']' || current === "}") {
const lastBracket = stack.pop();
if (matchLookup[lastBracket] !== current) { //if the stack is empty, .pop() returns undefined, so this expression is still correct
return false; //terminate immediately - no need to continue scanning the string
}
}
}
return stack.length === 0; //any elements mean brackets left open
}
console.log(brackets('(3+{1-1)}')); // false
console.log(brackets('{[(3+1)+2]+}')); //true
console.log(brackets('[1+1]+(2*2)-{3/3}')); //true
console.log(brackets('(({[(((1)-2)+3)-3]/3}-3)')); //false
I have used an object to lookup the values but it need not be one. An alternative is to use two arrays that you have to keep in sync
opening = ["(", "[", "{"]
closing = [")", "]", "}"]
On the other hand, if you have those, you can shorten your if checks to if (open.includes(current)) and if (closing.includes(current)).
This can be an easier solution:
const checkBrackets = (expression) => {
const stack = [];
const bracketLookup = {
'{': '}',
'(': ')',
'[': ']',
};
for (const key of expression) {
if(Object.keys(bracketLookup).includes(key)) { // matches open brackets
stack.push(key);
} else if(Object.values(bracketLookup).includes(key)) { //matches closed brackets
const lastBracket = stack.pop();
if(bracketLookup[lastBracket] !== key) {
return false;
}
}
}
return stack.length === 0;
}
Results:
checkBrackets('a(fg(a)}'); // false
checkBrackets('[1+1)+(2*2]-{3/3}'); // false
checkBrackets('a(d-h)+y{hh}||[hh-a-]'); // true
You can use stack with switch statement with a single for loop for efficient time and space complexity
function checkParantesis(str) {
const stack = [];
for (let s of str) {
if (s == '(' || s == '[' || s == '{') {
stack.push(s);
continue;
}
if (stack.length === 0) {
return false
}
switch (s) {
case ')':
stack.pop();
if (s == '{' || s == '[') {
return false
}
break;
case '}':
stack.pop();
if (s == '(' || s == '[') {
return false
}
break;
case ']':
stack.pop();
if (s == '{' || s == '(') {
return false
}
break;
}
}
return stack.length ? false : true
}
const output = checkParantesis('{{}}'));
console.log(output)
You can use the function String.prototype.replace to gather the brackets and use a kind of stack to compare each char. The stack is useful in order to know what was the last pushed bracket.
let check = (e) => {
let brackets = [],
stack = [],
map = {'}': '{', ']': '[', ')': '('};
e.replace(/[\[\]\{\}\(\)]/g, (m) => m && brackets.push(m));
for (let i = 0, {length} = brackets; i < length; i++) {
if (['}', ']', ')'].includes(brackets[i])) {
if (stack.pop() !== map[brackets[i]]) return false;
} else stack.push(brackets[i]);
}
return !stack.length;
};
console.log(check('(3+{1-1)}')); // false
console.log(check('{[(3+1)+2]+}')); //true
console.log(check('[1+1]+(2*2)-{3/3}')); //true
console.log(check('(({[(((1)-2)+3)-3]/3}-3)')); //false
I hope this will solve your problem...
function brackets(expression) {
let leftArr=[];
for(let i=0; i<expression.length; i++) {
if(expression[i] === '(' || expression[i] === '[' || expression[i] === "{") {
leftArr.push(expression[i]);
}
let leftArrLength = leftArr.length;
if(expression[i] === ')' && leftArr[leftArrLength - 1] === '('){
leftArr.pop();
}else if(expression[i] === '}' && leftArr[leftArrLength - 1] === '{') {
leftArr.pop();
} else if(expression[i] === ']' && leftArr[leftArrLength - 1] === '[') {
leftArr.pop();
}
else if(expression[i] === ')' || expression[i] === '}' || expression[i] === ']'){
return false;
}
}
return leftArr.length === 0;
}
console.log(brackets('(3+{1-1)}')); // false
console.log(brackets('{[(3+1)+2]+}')); //true
console.log(brackets('[1+1]+(2*2)-{3/3}')); //true
console.log(brackets('(({[(((1)-2)+3)-3]/3}-3)')); //false
console.log(brackets('(((([[[[{{{3}}}]]]]))))')); //false
My approach will be a little different.
These bracket pairs lie in the ASCII pair right after there first occurence.
Means '(' is placed (at 41) after ')' (at 40).
So, if there is a string input {[()]} and are in order.
We can divide the string by length/2 and check for ASCII value + 1
I think this the best solution.
const checkBracketSequenceBalance = (exp) => {
const pairs = {
'(': ')',
'[': ']',
'{': '}'
},
open = []
for (let i = 0; i < exp.length; i++)
if (pairs[exp[i]])
open.push(exp[i])
else if (exp[i] === pairs[open[open.length - 1]])
open.pop()
return !open.length
}
var input = "[({([])})]";
console.log(checkPairs(input));
function checkPairs(input=null) {
var arr = input.split("");
var result = false;
var tmpArr = [];
if ((arr.length % 2) == 0) {
arr.forEach(element => {
if (tmpArr[element] == null) {
tmpArr[element] = 1;
} else {
tmpArr[element] += 1;
}
});
if (tmpArr['['] == tmpArr[']'] && tmpArr['('] == tmpArr[')'] && tmpArr['{'] == tmpArr['}']) {
result = true;
}
}
return result;
}
input
books.copies.[read_by.[p_id="65784"].page=5468].text.[paragraph="20"].letters
the idea is to split the string by dots but ignore those inside square brackets
so after splitting there should be an array
[
'books',
'copies',
'[read_by.[p_id="65784"].page=5468]',
'text',
'[paragraph="20"]',
'letters'
]
I already looked at this answer but it doesn't work with nested square brackets, which is what i need. Also I'm using javascript, so negative lookbehinds are not supported.
Help is much appreciated.
Edit 1: expand example
It isn't possible to do it with a regex in Javascript that isn't able to match nested structures. You need to use the good old method: a stack.
var text = 'books.copies.[read_by.[p_id="65784"].page=5468].text.[paragraph="20"].letters';
var item = '', result = [], stack = 0;
for (var i=0; i < text.length; i++) {
if ( text[i] == '.' && stack == 0 ) {
result.push(item);
item = '';
continue;
} else if ( text[i] == '[' ) {
stack++;
} else if ( text[i] == ']' ) {
stack--;
}
item += text[i];
}
result.push(item);
console.log(result);
You need to write a parser for this since a JavaScript regex does not support regex recursion, nor balanced constructs.
The point in these functions is that they keep a stack (level, openBrackets) of opening delimiters (in your case, it is [) and then check the stack state: if the stack is not emppty, the found . is considered inside the brackets, and is thus just appended to the current match. Else, when the stack is empty, the . found is considered outside of brackets, and is thus used to split on (the current value is appended to the output array (result, ret)).
function splitByDotsOutsideBrackets(string){
var openBrackets = 0, ret = [], i = 0;
while (i < string.length){
if (string.charAt(i) == '[')
openBrackets++;
else if (string.charAt(i) == ']')
openBrackets--;
else if (string.charAt(i) == "." && openBrackets == 0){
ret.push(string.substr(0, i));
string = string.substr(i + 1);
i = -1;
}
i++;
}
if (string != "") ret.push(string);
return ret;
}
var res = splitByDotsOutsideBrackets('books.copies.[read_by.[p_id="65784"].page=5468].text.[paragraph="20"].letters');
console.log(res);
Or another variation:
function splitOnDotsOutsideNestedBrackets(str) {
var result = [], start = 0, level = 0;
for (var i = 0; i < str.length; ++i) {
switch (str[i]) {
case '[':
++level;
break;
case ']':
if (level > 0)
--level;
break;
case '.':
if (level)
break;
if (start < i)
result.push(str.substr(start, i - start));
start = i + 1;
break;
}
}
if (start < i)
result.push(str.substr(start, i - start));
return result;
}
var s = 'books.copies.[read_by.[p_id="65784"].page=5468].text.[paragraph="20"].letters';
console.log(splitOnDotsOutsideNestedBrackets(s))
Adapted from one of my previous answers.
I'm taking freecodecamp challenge "Check for Palindromes". Write a function to check if a given string is palindrome. Here is my code:
function palindrome(str) {
str = str.toLowerCase();
for(var i=0; i<str.length; i++){
if((str[i] > 'z' || str[i] < 'a') && (str[i] < '0' || str[i] > '9')){
str = str.replace(str[i], '');
}
}
for(i=0; i<str.length/2; i++){
if(str[i] != str[str.length-1-i]){
return false;
}
}
return true;
}
But it not worked properly. When I use replace(/[\W_]/g, ''); :
function palindrome(str) {
str = str.toLowerCase().replace(/[\W_]/g, '');
// for(var i=0; i<str.length; i++){
// if((str[i] > 'z' || str[i] < 'a') && (str[i] < '0' || str[i] > '9')){
// str = str.replace(str[i], '');
// }
// }
for(i=0; i<str.length/2; i++){
if(str[i] != str[str.length-1-i]){
return false;
}
}
return true;
}
The function worked properly. Is my first method not correct?
Palindromes ignore capitalization, spaces, punctuation and newlines and so on.
So:
A man. A plan. A canal: Panama!
Is a valid palindrome.
As such, you need to strip all punctuation and whitespace out of your string before trying to evaluate it, such that the string you're actually evaluating is:
amanaplanacanalpanama
Then it's easy to do whatever comparator you'd like on the remaining characters.
I did one of these a while ago and included some tests, it might be worth looking at: https://github.com/pvencill/palindrome
The Function to check mathematical expression not working.
I debugged this on chrome, and i saw that when it gets to the first pop (stack.pop()!== chars[i]), it returns false, but it shouldn't.
var smarter_validate = function(str) {
var chars = str.split('');
var stack = [];
var lookup = {
'(': ')',
'[': ']',
'{': '}',
'<': '>'
};
var left = Object.keys(lookup);
var right = Object.keys(lookup).map(function(key) {
return lookup[key]
});
for (var i = 0; i < chars.length; i++) {
if (left.indexOf(chars[i]) !== (-1)) {
stack.push(chars[i]);
} else if (right.indexOf(chars[i]) !== (-1)) {
if ((stack.length === 0) || (stack.pop() !== chars[i])) {
return false;
}
}
}
return (stack.length === 0);
};
console.log("SMART VALIDATE" + smarter_validate('(3+4[*2{6+8}])'));
You actually have to compare the popped value's corresponding closing character with chars[i], not the popped value itself.
So you need to do
if (stack.length === 0 || lookup[stack.pop()] !== chars[i]) {
Now, when you { from the stack, you will look for the corresponding closing character from the lookup and compare it with the current closing character.
Alternatively you can simply push the expected closing character in the stack so that you don't have do the lookup during the comparison, like this
stack.push(lookup[chars[i]]);