Finding a valid substring - javascript

I am a bit puzzled by one exercise I recently came across with.
It seems like an easy task and I've put my solution but it turned out it didn't pass all the tests :D
In the example, I've found two example substrings:
Input: S = "(()("
Output: 2
Explanation: The longest valid
substring is "()". Length = 2.
and
Input: S = "()(())("
Output: 6
Explanation: The longest valid
substring is "()(())". Length = 6.
at the first glance, everything is clear.
I came up with my solution:
class Solution {
findMaxLen(s) {
if (!s || !s.length) throw new Error('Invalid input value provided')
let openIndex = null
let closingIndex = null
for (let i = 0; i < s.length; i++) {
if (s[i] == '(' && !openIndex) openIndex = i + 1
if (s[i] == ')') closingIndex = i + 1
}
if(!closingIndex || !openIndex) throw new Error('Invalid substring')
return closingIndex - openIndex + 1
}
}
So, my solution should solve the issue of trying to find The longest substring with the opening and closing parentheses.
But it failed the test with an input value: (((()
Where the correct answer is 2 and my output is 5
Is this (((() different from ()(())( one provided in the example?
I suppose I do not wholly understand the idea of what the substring is or something...

This pseudocode should work. Some bugs or edge cases might have loose ends as I just wrote this here on the fly. Feel free to test it and point out the misses.
helper_stack = null
max_valid_len = 0
running_len = 0
for i=0 to input_s.length:
if helper_stack.length == 0:
if input_s[i] == ')':
running_len = 0
continue
else:
helper_stack.push('(')
else:
if input_s[i] == '(':
helper_stack.push('(')
else:
helper_stack.pop()
running_len += 2
if running_len > max_valid_len:
max_valid_len = running_len
EDIT: Explanation
With your logic, you are not keeping track of order of opening and closing of brackets, which is important. If a closing bracket precedes open, string becomes invaid by default. Hence, using stack makes sense here.
If ever we encounter a closing bracket before open, we restart from that point. Hence, we set the running_len = 0. For every encounter of closing bracket, if an open bracket is there to balance it, we just pop it off, and since its a pair (of chars, when we consider length of string), running_len += 2 is done.
With little modification, we can even reproduce max_valid_substring if needed. However, in our case, we could even use just an integer instead of helper_stack. For every push('(') operation, just do var += 1, and var -= 1 for pop and that should also do the trick. Note that here, we are not explicitly using stack, but this is still conceptually LIFO = last in first out which is basically, stack.

Related

Why is my script saying '(' === ')' is true?

I was doing this kata on codewars. The question wants the function to return true if the first argument (string) passed in ends with the 2nd argument (also a string). So I wrote my function and everything worked just fine until it compares ':-)' with ':-(' and returns true.
What is wrong? I'm so confident that my code should work that I don't even know what to search for.
function solution(str, ending){
if (!ending) return true; // if ending is a empty string return true (the question wants that)
let ok;
const strArr = str.split(''), endingArr = ending.split('');
for (let i = 0; i < endingArr.length; i++) strArr.reverse()[i] === endingArr.reverse()[i] ? ok = true : ok = false;
return ok;
}
console.log(solution(":-)",":-("));
Your problem is a misunderstanding of what reverse() does. It does not return a reversed copy of the old array, it reverses the existing array and returns that same array. As a result, you keep reversing the arrays back and forth every iteration of the loop, causing some elements to be skipped and some to be checked twice.
Array.prototype.reverse() on MDN
Edit:
As pointed out by others in the comments, both to the question and this answer, there are in fact multiple problems.
reverse() aside, the loop always sets ok to the result of the last comparison, making the function ignore all previous results.
The easier way to implement this is to remove ok altogether. Instead, return false as soon as a mismatch is detected. If the function runs long enough to exit the loop, it means no mismatch was detected and true can be returned.
Edit 2:
Just as a friendly suggestion:
While both reverse() and ok are real issues with the code, I only noticed the first one the first time around due to the formatting of the code. The ok problem was off-screen due to the line being too long. As such, once I spotted the reverse() issue, I assumed that was it and didn't bother scrolling sideways to see the rest of the code.
I am not going to demand that you write your own code in a certain way, but if you format it properly, it allows others to read it more easily. In essence, you help us to more easily help you.
For instance, this line:
for (let i = 0; i < endingArr.length; i++) strArr.reverse()[i] === endingArr.reverse()[i] ? ok = true : ok = false;
...would have been significantly easier to read as...
for (let i = 0; i < endingArr.length; i++) {
if(strArr.reverse()[i] === endingArr.reverse()[i])
ok = true;
else
ok = false;
}
...or some variation thereof. Here, the problem is significantly more visible and obvious.
The other answer explains many of the mistakes you've made. I wanted to point out just how much you've over-thought your solution.
function solution(str, ending){
if (ending === "") return true; // if ending is a empty string return true (the question wants that)
return str.endsWith(ending);
}
console.log(solution(":-)",":-("));
console.log(solution("foo",""));
console.log(solution("foo","bar"));
console.log(solution("foobar","bar"));
Even my solution above is overengineered, str.endsWith("") always returns true. So this can be simplified further.
function solution(str, ending){
return str.endsWith(ending);
}
console.log(solution(":-)",":-("));
console.log(solution("foo",""));
console.log(solution("foo","bar"));
console.log(solution("foobar","bar"));

JSLint confusion in Javascript alerts are not declared

Hey so I'm using JSLint under the assumption I'm using a browser and tolerating multiple vars and whitespace mess.
The whole program works, but I have a few problems, according to JSLint. First off, I'm trying to use alert(string) to make pop-up error messages, but JSLint is telling me the alerts are undeclared, I haven't found a resource on the internet that's explained how to make this not happen yet.
Secondly, I have loops that look like this:
function setMixedList() {
"use strict";
clearResults();
var n = "0";
var l = "0";
var text = "";
while (n < numList.length && l < letList.length) {
document.getElementById("listInput").value =
text += numList[n] + letList[l];
n ++;
l ++;
}
This loop in particular takes two separate arrays and mixes them together in order; one containing numbers (1-7) and the other containing letters (a-g) in a way so they appear in a text box like this:
1 a 2 b 3 c 4 d 5 e 6 f 7 g
JSLint doesn't like two things about this. The first is that in the
document.getElementById("listInput").value =
text += numList[n] + letList[l];
section of the loop, JSLint tells me the "+=" is unexpected. When I edit that to:
text = text + numList[n] + letList[l];
JSLint tells me the "=" is unexpected and I'm not sure how to take these things out without making my program unable to work.
The other important part of this is the
n ++;
l ++;
section of code. I know JSLint doesn't like ++, but if I make the code
n+= 1;
l+= 1;
The string doesn't come out right, with some characters undefined because I'm not just dealing with numbers. Anybody know how to fix these problems?
To answer the first part
JSLint is telling me the alert
This can be resolved by following one of the way . In jslint options set
"devel:true" which will enables things like Alert, console,prompt.Check this link to know more about it.
Secondly set browser option set to true in your .jshintrc and use window.alert instead of alert

Add indexes of all occurrences of character in a string to array

I'm trying to add all of the indexes of a specific character to an array from a string.
I've got the following code, but I've had to restart my browser about 10 times because it doesn't work.
var xPositions = new Array();
var startPos = 0;
var string = "abcdexabcdexabcdexabcdexabcdexabcdexabcdex";
while (true) {
var currentIndex = string.indexOf("x", startPos);
if (currentIndex == -1) {
break;
}
xPositions.push(currentIndex);
startPos = currentIndex;
}
I thought about iterating forever until there are no more occurrences of the character, and then break.
Any help/suggestions appreciated.
Try
var currentIndex = string.indexOf("x", startPos+1);
I think you're getting the same current index over and over. "indexOf" begins its search at the index you specify, so you must increment it relative to the last find.
For future reference, you may consider trying to use a debugger with breakpoints, problems like this become relatively easy to spot (even just doing a few console.log's of relevant data can make mincemeat out of this type of bug - it's hard to always perfectly understand how a function you've never used before will work, there's no shame in seeing if it's behavior matches your expectations).

Simple Confusing Loops and Variable working

In this question,I'm asking how the following snippets work, as it involves weird use of variable:
while (+(+i--)!=0)
{
i-=i++;
}
console.log(i);
Interesting problem... you've tagged it Java, JavaScript and C -- note that while these languages have the same syntax, this question involves very subtle semantics that may (I'm not sure) differ across languages.
Let's break it down:
+(+i--)
The -- postfix decrement operator is most tightly bound. So this is equivalent to +(+(i--)). That is therefore equivalent to the value of +(+i) (that is, i), but it also decrements i after taking the value. It compares the value with 0 to see if the loop should continue. Thus, while (+(+i--)!=0) is equivalent to the following:
while (i-- != 0)
Note that it also performs i-- at the end of the loop.
Inside the loop, I believe you have some undefined behaviour, at least in C, because you are referencing i on the right, and also updating i on the left -- I believe that C doesn't define which order to do that in. So your results will probably vary from compiler to compiler. Java, at least, is consistent, so I'll give the Java answer. i-=i++ is equivalent i = i - i++, which is equivalent to to reading all the values out of the expression, computing the result of the expression, applying the post-increment, and then assigning the result back. That is:
int t = i - i; // Calculate the result of the expression "i - i++"
i++; // Post-increment i
i = t; // Store the result back
Clearly, this is the same as writing i = 0. So the body of the loop sets i to 0.
Thus, the loop executes just one time, setting i to 0. Then, it decrements i one more time on the next while loop, but fails the check because i (before decrementing) == 0.
Hence, the final answer is -1, no matter what the initial value for i is.
To put this all together and write an equivalent program:
while (i-- != 0)
{
int t = i - i;
i++;
i = t;
}
console.log(i);
When I tried it in Java and JavaScript, that's what I got. For GCC (C compiler), it gives -1 only when i starts out as 0. If i starts out as anything else, it goes into an infinite loop.
That's because in GCC (not necessarily all C compilers), i-=i++ has a different meaning: it does the store back to i first, then does the post-increment. Therefore, it is equivalent to this:
int t = i - i; // Calculate the result of the expression "i - i++"
i = t; // Store the result back
i++; // Post-increment i
That's equivalent to writing i = 1. Therefore, on the first iteration, it sets i to 1, and then on the loop, it checks whether i == 0, and it isn't, so it goes around again, always setting i to 1. This will never terminate, but for the special case where i starts out as 0; then it will always terminate the loop and decrement i (so you get -1).
Another C compiler may choose to act like Java instead. This shows that you should never write code which both assigns and postincrements the same variable: you never know what will happen!
Edit: I tried to be too clever using that for loop; that wasn't equivalent. Turned back into a while loop.
That's soooo wierd! (I love it)
first, you can forget about the +(+...) part, it's just like saying 1 + (+1) = 2.
i-- means i = i - 1. In your while condition, you test if i-- is different from 0. Note: the test is made on i != 0 and then i's value is changed. If you wanted to change its value before the test, you should have used --i instead.
As for the i -= i++, it's a very dumb way to say i = 0. You must read it from right to left: i = i + 1 and then i = i - i1 (whatever value of i you have, you'll end up with 0.
Simplier quivalent snippet:
while (i-- != 0) {
i = 0;
}
console.log(i);
1 a -= b means a = a - b.
i -= i++ would mean a similar thing to i = i-i; i++ (if you make the -= explicit).
In a similar fashion, you can pull the side effect of i-- out of the loop condition by
transforming while (foo(i--)) { ... } to while (foo(i)) { i--; ...} i--; (you need to put it both in the loop body and after the loop because, at the end, the condition will be false and the loop body will not be executed but execution continues after the while loop).
The while condition evaluation happens based on operator precedence. I have used explicit braces to help understand the evaluation:
(+(+(i--)) != 0) which is equivalent to using (i-- != 0) as the '+' are just unary operators.
The expression i -=i++; is equivalent to i = i - i++; where the LHS expression gets evaluated from left to right.
i = 4;
while (+(+i--)!=0) //here i would be decremented once to 3.
{
i-=i++; // here i = 3 - 3 = 0; even though i has been incremented by 1 its value is set to 0 with this assignment
}
This is very simple. And I think the only reason to code like this is a concept called "code obfucasion" or "code confusing". This way makes the code harder to read and debug, so that can prevent from reverse engineer your code :-)

Weird JavaScript Code

for (var i=a.length-1;i>0;i--) {
if (i!=a.indexOf(a.charAt(i))) {
a=a.substring(0,i)+a.substring(i+1);
}
}
I found this in a web app I'm auditing, it just baffles me why it's there.
I can't seem to see a case where i!=a.indexOf(a.charAt(i)) would be false.
The value the pass to it is:
a = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
There is no comment either //sigh
This would be true for repeated characters, since indexOf finds the first index of a string, and you're searching from the end. Example:
var a = "xyzxyz";
On first iteration, i === 4, a.charAt(4) === "x", and a.indexOf("x") === 0. So 4 !== 0.
It then sets a = a.substring(0, 4) + a.substring(5). Recalling at substring is inclusive in the first index but exclusive in the last index, that means in this case a = "xyz" + "yz", so we have removed the duplicate "x" from the string.
Since the loop traverses backward, this will continue to work even for characters repeated more than once; you can see that the portion a.substring(i + 1) will always have been covered by the algorithm already, i.e. not contain any duplicates.
As always when encountering this type of thing, applying the extract method refactoring would be a great way to make the code clearer. (Even better than commenting it!) So if you just pulled this out into a method, the code could become a = removeDuplicateChars(a), and everyone is much happier.

Categories

Resources