I am currently studying another user’s code for a coding question from LeetCode. My question is about certain aspects of his code. Here’s a link to the question.
Question:
Why does this user use a # to mark the end of the array?
Under the second if case, the user writes:
ans.push(nums[t] + '->' + (nums[i-1]))
Now, I understand what this statement does. My question is: Why does this produce an output of ["0->2",...] instead of [0"->"2,...]?
var summaryRanges = function(nums) {
var t = 0
var ans = []
nums.push('#')
for(var i=1;i<nums.length;i++)
if(nums[i]-nums[t] !== i-t){
if(i-t>1)
ans.push(nums[t]+'->'+(nums[i-1]))
else
ans.push(nums[t].toString())
t = i
}
return ans
}
The algorithm depends on that the difference between nums[i] and nums[t] is not the same as the difference between i and t. When that happens, the algorithm adds more to the output. This creates a special case when the last range is just a single number, since this cannot trigger the condition.
Hence the hash character is padding to extend the array in order to make the algorithm work, so that the condition nums[i]-nums[t] !== i-t will trigger even for a finishing range of a single number. It could be any string really as long as it is not an integer number.
Related
This question already has answers here:
Find difference between two strings in JavaScript
(6 answers)
Closed last year.
I want to create a function to compare two strings and return changes in string (like Stack Overflow shows changes in answer which was edited).
Expected results should be.
console.log(detectChange("SHANTI DEVI","SHANT DEVI")); // SHANT_I_ DEVI
console.log(detectChange("MOHAN SINGH","MOHAN SINGH")); // MOHAN SINGH
console.log(detectChange("SURESH SINGH","MOHAN SINGH")); // -MOHAN-_SURESH_ SINGH
console.log(detectChange("SEETA DEVI","SITA SINGH")); // S-I-_EE_TA -SINGH-_DEVI_
First parameter is the new value and second parameter is the old value.
Bracket letter or word using "-" if that word or letter was removed
The word or letter that was added should be bracketed using "_"
The below code was unsuccessful for me.
function detectChange(name1, name2) {
name1 = name1.split("");
name2 = name2.split("");
var visit = 0;
var final_name = [];
if (name2.length > name1.length) {
nameTmp = name1;
name1 = name2;
name2 = nameTmp;
}
for (i = 0; i <= name1.length; i++) {
if (name1[i] == name2[visit]) {
final_name.push(name1[i]);
visit++;
} else if (name1[i] !== null) {
final_name.push("_" + name1[i] + "_");
visit++;
}
}
return final_name.join("");
}
// Getting unexpected results
console.log(detectChange("SHANTI DEVI", "SHANT DEVI")); // SHANT_I__ __D__E__V__I_
console.log(detectChange("MOHAN SINGH", "MOHAN SINGH")); // MOHAN SINGH
console.log(detectChange("SURESH SINGH", "MOHAN SINGH")); // _S__U__R__E__S__H__ __S__I__N__G__H_
console.log(detectChange("SEETA DEVI", "SITA SINGH")); // S_E__E__T__A__ __D__E__V__I_
Here every single output is invalid, please help me regarding this how can I handle this.
You probably want to read this paper, "An O(ND) Difference Algorithm and Its Variations". Here's the abstract:
Abstract
The problems of finding a longest common subsequence of two sequences A and B and a shortest edit script for transforming A into B have long been known to be dual problems. In this paper, they are shown to be equivalent to finding a shortest/longest path in an edit graph. Using this perspective, a simple O(ND) time and space algorithm is developed where N is the sum of the lengths of A and B and D is the size of the minimum edit script for A and B. The algorithm performs well when differences are small (sequences are similar) and is consequently fast in typical applications. The algorithm is shown to have O(N + D2) expected-time performance under a basic stochastic model. A refinement of the algorithm requires only O(N) space, and the use of suffix trees leads to an O(NlgN + D2) time variation.
And then implement the algorithm.
But no... you don't actually want to do that, because it's already been done for you: See the npm package diff.
This question already has answers here:
Length of a JavaScript object
(43 answers)
Closed 2 years ago.
Lately I have been trying to create a webpage with a search feature. My way of implementing this, while not the fastest or most elegant, should work in theory. All it does is split the search term into a list, the delimiter being a space, and then splits the keywords (in dictionary format, with the value being a download link, and with the key being the "keywords" I was referring to) and finally, it has an outer loop looping through the keys (being split each iteration into a list), and an inner loop looping through the words input through the input field. If a word in the search field matches one keyword of the key words list, then that key from the dictionary gets a score of +1.
This should sort the keys into order of best result to worst, and then the code can continue on to process all this information and display links to the downloadable files (the point of the webpage is to supply downloads to old software [of which I have collected over the years] etc.). However, when I run the program, whenever the alert(ranking.length) function is called, all I get is undefined in the output window.
Here is the code. (The search() function is called whenever the search button is pressed):
var kw_href = {
"windows":["windows3.1.7z"],
"ms dos 6.22":["ms-dos 6.22.7z"]
}
function search(){
var element = document.getElementById("search_area");
var search_term = element.value.toLowerCase();
var s_tags = search_term.split(" ");
var keys = Object.keys(kw_href);
ranking = {
"windows":0,
"ms dos 6.22":0
};
for (i = 0; i < keys.length; i++){
keywords_arr = keys[i].split(" ");
for (x = 0; x < s_tags.length; x++){
if (keywords_arr.includes(s_tags[x])){
ranking[keys[i]] = ranking[keys[i]] + 1;
}
}
}
// now we have a results list with the best results. Lets sort them into order.
alert(ranking.length);
}
Edit
alert(ranking.length) line is for debugging purposes only, and I was not specifically trying to find the length.
ranking is a generic object, not an array, so it won't have a computed length property.
If you want to count the number of properties in it, convert it to an array with Object.keys(ranking).
ranking should be array of object like ranking =[{"windows":0,"ms dos 6.22":0},{"windows":1,"ms dos 6.22":10}]
Then length ranking.length will work
As the title suggests, I was trying to recursively solve a JavaScript problem. An exercise for my internet programming class was to invert any string that was entered in the function, and I saw this as a good opportunity to solve this with recursion. My code:
function reverseStr(str){
str = Array.from(str);
let fliparray = new Array(str.length).fill(0);
let char = str.slice(-1);
fliparray.push(char);
str.pop();
str.join("");
return reverseStr(str);
}
writeln(reverseStr("hello"))
The biggest problem is that your function doesn't have an end (base) case. It needs to have some way to recognize when it's supposed to stop or it will recurse forever.
The second problem is that you don't really seem to be thinking recursively. You're making some modification to the string, but then you just call reverseStr() all over again on the modified string, which is just going to start the process all over again.
The following doesn't really resemble your attempt (I don't know how to salvage your attempt), but it is a simple way to implement the reverse string algorithm recursively.
function reverseStr(str) {
// string is 0 or 1 characters. nothing to reverse
if (str.length <= 1) {
return str;
}
// return the first character appended to the end of the reverse of
// the portion after the first character
return reverseStr(str.substring(1)) + str.charAt(0);
}
console.log(reverseStr("Hello Everybody!"));
I am writing a recursive algorithm to build a finite state automaton by parsing a regular expression. The automaton iterates through the expression, pushing characters to a stack and operators to an "operator stack." When I encounter "(" (indicating a grouping operation), I push a "sub automaton" to the stack and pass the rest of the pattern to the sub automaton to parse. When that automaton encounters ")", it passes the rest of the string up to the parent automaton to finish parsing. Here is the code:
var NFA = function(par) {
this.stack = [];
this.op_stack = [];
this.parent = par;
};
NFA.prototype.parse = function(pattern) {
var done = false;
for(var i in pattern) {
if (done === true) {
break;
}
switch(pattern.charAt(i)) {
case "(":
var sub_nfa = new NFA(this);
this.stack.push(sub_nfa);
sub_nfa.parse(pattern.substring(i+1, pattern.length));
done = true;
break;
case ")":
if (this.parent !== null) {
var len = pattern.length;
/*TROUBLE SPOT*/
this.parent.parse(pattern.substring(i, pattern.length));
done = true;
break;
}
case "*":
this.op_stack.push(operator.KLEENE);
break;
case "|":
this.op_stack.push(operator.UNION);
break;
default:
if(this.stack.length > 0) {
//only push concat after we see at least one symbol
this.op_stack.push(operator.CONCAT);
}
this.stack.push(pattern.charAt(i));
}
}
};
Note the area marked "TROUBLE SPOT". Given the regular expression "(a|b)a", the call this.parent.parse, is called exactly once: when the sub-automaton encounters ")". At this point, pattern.substring(i, pattern.length) = ")a". This "works", but it isn't correct because I need to consume the ")" input before I pass the string to the parent automaton. However, if I change the call to this.parent.parse(pattern.substring(i+1, pattern.length), parse gets handed the empty string! I have tried stepping through the code and I cannot explain this behavior. What am I missing?
At Juan's suggestion, I made a quick jsfiddle to show the problem when trying to parse "(a|b)a" with this algorithm. In the ")" case, it populates an empty div with the substring at the i index and the substring at the i+1 index. It shows that while there are 2 characters in the substring at i, the substring at i+1 is the empty string! Here's the link: http://jsfiddle.net/XC6QM/1/
EDIT: I edited this question to reflect the fact that using charAt(i) doesn't change the behavior of the algorithm.
I think the previous answer was on the right track. But there also looks to me to be an off-by-one error. Shouldn't you be increasing the index for your substring? You don't want to include the ")" in the parent parse, right?
this.parent.parse(pattern.substring(i + 1, pattern.length));
But this will still fail because of the error Juan mentioned. A quick temporary fix to test this would be to convert the i to a number:
this.parent.parse(pattern.substring(+i + 1, pattern.length));
This might do it for you. But you should probably go back and switch away from the for-in loop on the string. I think that's causing your issue. Turn it into an array with str.split('') and then use an integer to loop. That will prevent further such issues.
The real problem is the fact that you were using a for in to iterate through the characters of the string. With the for in loop, your i is going to be a string, therefore, when you try to do i+1, it does string concatenation.
If you change your iteration to be
for(var i=0; i < pattern.length; i++) {
Then it all works fine http://jsfiddle.net/XC6QM/2/
Scott's answer correctly identified the problem but I think his solution (converting the indexes to numbers) is not ideal. You're better off looping with a numeric index to begin with
Also, you should not use brackets to access characters within a string, that does not work in IE 7
switch(pattern[i]) {
should be
switch(pattern.charAt(i)) {
I am sorry for the very newbie question, but this is driving me mad.
I have a word. For each letter of the word, the characters position in one array is found and then returns the character at the same position found in a parallel array (basic cipher). This is what I already have:
*array 1 is the array to search through*
*array 2 is the array to match the index positions*
var character
var position
var newWord
for(var position=0; position < array1.length; position = position +1)
{
character = array1.charAt(count); *finds each characters positions*
position= array1.indexOf(character); *index position of each character from the 1st array*
newWord = array2[position]; *returns matching characters from 2nd array*
}
document.write(othertext + newWord); *returns new string*
The problem I have is that at the moment the function only writes out the last letter of the new word. I do want to add more text to the document.write, but if I place within the for loop it will write out the new word but also the other text inbetween each word. What i actually want to do is return the othertext + newWord rather than document.write so that I can use it later on. (just using doc.write to text my code) :-)
I know its something really simple, but I cant see where I am going wrong. Any advice?
Thanks
Issy
The solution is to build newWord within the loop using += instead of =. Just set it to an empty string before the loop.
There are other problems with this code. Variable count is never initialized. But let's assume that loops should be using count instead of position as it's principal counter. In that case, if I am not mistaken, this loop will just generate array2 as newWord. First two lines of loop's body cancel each other in a matter of speaking, and position will always be equal to count, so letters from array2 will be used sequentially from beginning to the end.
Could you provide one example of input and desired output, so that we understand what you actually want to accomplish?
A good way of structuring your code and your question is that you define a function that you need to implement. In your case this could look like:
function transcode(sourceAlphabet, destinationAlphabet, s) {
var newWord = "";
// TODO: write some code
return newWord;
}
That way, you clearly state what you want and which parameters are involved. It is also easy to write automatic tests later, for example:
function testTranscode(sourceAlphabet, destinationAlphabet, s, expected) {
var actual = transcode(sourceAlphabet, destinationAlphabet, s);
if (actual !== expected) {
document.writeln('<p class="error">FAIL: expected "' + expected + '", got "' + actual + '".</p>');
} else {
document.writeln('<p class="ok">OK: "' + actual + '".');
}
}
function test() {
testTranscode('abcdefgh', 'defghabc', 'ace', 'dfh');
}
test();