Reputation: 1163
I'm attempting the Codility 'Nested' test in Javascript.
The test is as below:
A string S consisting of N characters is called properly nested if:
S is empty;
S has the form "(U)" where U is a properly nested string;
S has the form "VW" where V and W are properly nested strings.
For example, string "(()(())())" is properly nested but string "())" isn't.
Write a function:
function solution(S);
that, given a string S consisting of N characters, returns 1 if string S is properly nested and 0 otherwise.
For example, given S = "(()(())())", the function should return 1 and given S = "())", the function should return 0, as explained above.
Write an efficient algorithm for the following assumptions:
N is an integer within the range [0..1,000,000];
string S consists only of the characters "(" and/or ")".
My solution is the following:
function solution(S) {
const elements = S.split('')
const stack = []
if (elements.length > 1000000) return 0
if (elements[0] == ')') return 0
if (elements[0] == '(') stack.push('(')
for (i=0; i < elements.length; i++){
const currentElement = elements[i]
if (currentElement !== '(' && currentElement !== ')') return 0
if (i>0){
if (stack[stack.length-1] == '(' && currentElement == ')') stack.pop()
else stack.push(currentElement)
}
}
if (stack.length) return 0
else return 1
}
This is correct but returns only 75% on performance, i can't see how to further improve the efficiency, does anyone have any suggestions?
Upvotes: 0
Views: 1736
Reputation: 977
Swift 100% solution:
public func solution(_ S : inout String) -> Int {
guard !S.isEmpty else { return 1 }
var stack = [Character]()
for character in S {
if stack.isEmpty && character == ")" {
return 0
}
guard !stack.isEmpty, (stack.last! == "(" && character == ")") else {
stack.append(character)
continue
}
stack.popLast()
}
return stack.isEmpty ? 1 : 0
}
Upvotes: 0
Reputation: 1
100% on Codility
const nesting = (s) => {
if (!s.length) {
return 1;
}
if (s.indexOf('(') === -1 && s.indexOf(')') === -1) {
return 1;
}
const arr = [];
const map = {
'(': ')'
};
for (let i = 0; i < s.length; i++) {
if (s[i] === '(' || s[i] === ')') {
if (!arr.length || map[arr[arr.length - 1]] !== s[i]) {
arr.push(s[i]);
continue;
}
if (map[arr[arr.length - 1]] === s[i]) arr.pop();
}
}
return arr.length > 0 ? 0 : 1;
}
Upvotes: 0
Reputation: 11
function solution(S) {
let stack=[];
if(!S){
return 1;
}
for(let i=0;i<S.length;i++){
if(S[i]==='('){
stack.push(S[i]);
}else if(stack.length){
stack.pop();
}else{
return 0;
}
}
return stack.length ? 0: 1;
}
Upvotes: 0
Reputation: 149
There are too many "if"s in your solution. Try to understand maraca's answer. Or, check my solution below (99% same)
function solution(S) {
let stack = 0;
for (let i=0; i<S.length; i++) {
S[i] === '(' ? stack++ : stack--;
if (S[i] === '(') {
stack++
} else {
stack--;
if (stack < 0) return 0;
}
}
return stack === 0 ? 1 : 0;
}
Upvotes: 0
Reputation: 8743
I think you are doing this way too complicated. Split isn't necessairy. Also the problem statement says the string only contains (
and )
. So the solution can be as simple as this (passes all tests):
function solution(S) {
let count = 0
for (const c of S) {
if (c == '(')
count++
else if (--count < 0)
return 0
}
return count == 0 ? 1 : 0
}
Btw. this statement in your code is wrong:
if (currentElement == ')' && openCount > 0) openCount = openCount - 1
else openCount = openCount + 1
If the count would become negative because there are too many )
you will increase the counter. So maybe it isn't a performance problem after all. Same for the solution with the stack: if the stack is empty you look for stack[-1] and this is undefined so you push the next element (although there it doesn't fail because you will push )
and this will never be consumed). Also it would make more sense to push the index of the opening braces on the stack so that you could (if you wanted to) show the pairings of the braces, which (
belongs to which )
. If you just push (
on the stack you can as well use a counter.
Upvotes: 3
Reputation: 1163
Following suggestions in the comments, i tried using a counter.
This still fails on efficiency though, being penalised on broad tree with deep paths.
function solution(S) {
// write your code in JavaScript (Node.js 8.9.4)
const elements = S.split('')
let openCount = 0
if (elements.length > 1000000) return 0
if (elements[0] == ')') return 0
if (elements[0] == '(') openCount = 1
for (i=0; i < elements.length; i++){
const currentElement = elements[i]
if (currentElement !== '(' && currentElement !== ')') return 0
if (i>0){
if (currentElement == ')' && openCount > 0) openCount = openCount - 1
else openCount = openCount + 1
}
}
if (openCount !== 0) return 0
else return 1
}
Upvotes: 0