combination sum coding challenge - javascript

I am trying to solve a coding challenge "Combination Sum" (https://leetcode.com/problems/combination-sum/discuss/127208/Simple-Javascript-Solution) and found a solution but I can not understand why currArr.pop() inside if (target >= candidates[i]) is required. I tried to understand by removing it and replacing it but still can not figure it out. Could someone explain why this is necessary to me? Thanks!
var combinationSum = function(candidates, target) {
candidates.sort((a,b) => a - b);
const results = [];
const innerFunction = (currArr, target, index) => {
if (target === 0) {
results.push(currArr.slice());
return;
}
for (let i = index; i < candidates.length; i++) {
if (target >= candidates[i]) {
const newTarget = target - candidates[i];
currArr.push(candidates[i]);
innerFunction(currArr, newTarget, i);
currArr.pop();
} else {
return;
}
}
}
innerFunction([], target, 0);
return results;
};
console.log(combinationSum([2,3,6,7], 7));

This technique is called backtracking.
Backtracking is a technique used to build up to a solution to a problem incrementally. These "partial solutions" can be phrased in terms of a sequence of decisions. Once it is determined that a "partial solution" is not viable (i.e. no subsequent decision can convert it into a solution) then the backtracking algorithm retraces its step to the last viable "partial solution" and tries again.
the key point here is that after currArr.push(candidates[i]) flow is recurcion call innerFunction(currArr, newTarget, i); so currArr is constantly growing, at some point if (target === 0) desired result has found and you do deep copy of your currArr with currArr.slice() and now with return, code goes 1 step back to currArr.pop() since this come after innerFunction recursion call.
I hope this could help you -)

Related

Why Hasn't My Time Complexity Improved On This Leet Code Challenge?

I am taking a course on algorithms and big O on Udemy.
I learned that nested loops are bad for performance. I wrote a Leet Code challenge before starting this course, and I wanted to try it again using some things I learned on the course. I was expecting it to be much faster than it was the last time. But it was the same speed. Can someone explain to me where I'm going wrong and why there's no improvement in the performance of this function?
Challenge: function with array and target integer arguments, find the two integers from the array whose sum is the target.
New code: Time: 212ms
var twoSum = function(nums, target) {
let right = nums.length - 1;
let left = 0;
// as long as left > nums.lenth - 2
while (left < nums.length) {
if (nums[left] + nums[right] === target) {
return [right, left];
}
if (right > left + 1) {
right--;
} else {
left++;
right = nums.length - 1;
}
}
};
Old code: Time: 204ms
var twoSum = function(nums, target) {
for (let i = 0; i < nums.length; i++) {
for (let ii = 0; ii < nums.length; ii++) {
if (i !== ii && nums[i] + nums[ii] === target) {
return [i, ii];
break;
}
}
}
};
Big-o is purely theoretical, yet LeetCode's benchmarking is something practical, not to mention that their measurements are highly inaccurate and unreliable, which you can fully ignore. It's just something there without much benefit.
var twoSum = function(nums, target) {
let numsMap = {};
for(let index = 0; index < nums.length; index++) {
const num = nums[index];
if(numsMap[target - num] !== undefined) {
return [numsMap[target - num], index];
}
numsMap[num] = index;
}
return [];
}
References
For additional details, you can see the Discussion Board. There are plenty of accepted solutions with a variety of languages and explanations, efficient algorithms, as well as asymptotic time/space complexity analysis1, 2 in there.
If you are preparing for interviews:
We would want to write bug-free and clean codes based on standards and conventions (e.g., c1, 2, c++1, 2, java1, 2, c#1, 2, python1, javascript1, go1, rust1). Overall, we would like to avoid anything that might become controversial for interviews.
There are also other similar platforms, which you might have to become familiar with, in case you'd be interviewing with specific companies that would use those platforms.
If you are practicing for contests1:
Just code as fast as you can, almost everything else is very trivial.
For easy questions, brute force algorithms usually get accepted. For interviews, brute force is less desired, especially if the question would be an easy level.
For medium and hard questions, about 90% of the time, brute force algorithms fail mostly with Time Limit Exceeded (TLE) and less with Memory Limit Exceeded (MLE) errors.
Contestants are ranked based on an algorithm explained here.

recursion on returning vectors c++

Hey guys I am trying trying to right this javascript code into c++. I am doing quick sort and everything is straight forward minus the last step.
function quickSort(arr)
{
//base case if the arr is 1 or 0 then return the array
if(arr.length === 1 || arr.length === 0)
{
return arr;
}
var pivotIndex = Math.floor(arr.length/2);
var pivotValue = arr[pivotIndex];
var before = [];
var after = [];
for(var counter = 0; counter < arr.length; counter++)
{
if(counter === pivotIndex)
continue;
if(pivotValue <= arr[counter])
{
before.push(arr[counter])
}
else
{
after.push(arr[counter])
}
}
//this step I am having trouble rewriting in c++
return quickSort(after).concat(pivotValue).concat(quickSort(before));
}
I am having a hard time rewriting the recursive step in c++. I am not sure how concat 2 vector. I tried using the insert method but I keep getting an error about invalid use of void expression.
vector<int> quickSort(vector<int> arr)
{
if(arr.size() == 1 || arr.size() == 0)
{
return arr;
}
int pivotIndex = arr.size()/2;
int pivotValue = arr[pivotIndex];
vector<int> before;
vector<int> after;
//put values in before or after the piv
for(size_t counter = 0; counter < arr.size(); counter++)
{
if(counter == pivotIndex)
continue;
if(pivotValue <= arr[counter])
before.push_back( arr[counter]);
else
after.push_back( arr[counter]);
}
return //????? not sure how to do this
}
So, you realized that your core question was "how to concatenate two vectors", and you found a right answer: using insert. Now your question is about why you were getting "an error about invalid use of void expression." (That's the assumption my answer is for, at least.)
That's because you were likely trying to do something like the following:
return quickSort(after).insert( /* stuff */ );
which is wrong. In JavaScript, array.concat returns the concatenated array. It's return type is effectively Array, and so doing return arr.concat(arr2) returns an Array because arr.concat would return an Array. Further, in JavaScript, array.concat doesn't modify the array it was called on, but rather returns a new array.
In C++, however, vector.insert (#4 in the reference) returns void. That means it returns nothing. So when you try to return the result of insert, you get that error about invalid use of a void expression. Further, in C++, vector.insert does modify the vector it was called on.
So how do you use insert in this case?
vector<int> quickSort(vector<int> arr)
{
// ...
// Sort `before` and `after`
before = quickSort(before);
after = quickSort(after);
// Modify `after` and return it.
after.push_back(pivotValue);
after.insert(after.end(), before.begin(), before.end());
return after;
}
Note: My code isn't optimal and the idea of rewriting JS in C++ is also oddly specific. My answer is to simply outline the problem asked in the question, not to give a good C++ implementation of quick sort.
To concat two vector , you can use std::merge
like:std::merge(v1.begin(), v1.end(), v2.begin(), v2.end(), std::back_inserter(dst));

Turn Coffeescript loop using range into ES6

Disclaimer: I don't know Coffeescript and, although I appreciate it has contributed towards the ES6 spec, I can't wait to see the back it.
This Coffeescript loop (wrote by someone else)
if #props.total>1
for page in [1..#props.total]
active = (page is +#props.current)
is, according to js2coffee, equivalent to this JS
var active, i, page, ref;
if (this.props.total > 1) {
for (page = i = 1, ref = this.props.total; 1 <= ref ? i <= ref : i >= ref; page = 1 <= ref ? ++i : --i) {
active = page === +this.props.current;
}
}
Now I would like to use a for..of loop to shorten that JS, but I can't figure out how.
I've tried to implement this idea(the generator function bit at the bottom), but I can't get it right.
My question is: Is there a way of making ranges in ES6?
The generator solution you are looking for would be
function* range(i, end=Infinity) {
while (i <= end) {
yield i++;
}
}
// if (this.props.total > 1) - implicitly done by `range`
for (let page of range(1, this.props.total) {
active = page === +this.props.current;
}
For generating any range of sequential integers of length k starting at n in JavaScript the following should work:
Array.apply(null, Array(k)).map((x, i) => i + n);
While not quite the same as the coffeescript range functionality, its probably close enough for most uses. Also despite being significantly more verbose has one decided advantage: you don't have to remember which of .. and ... is exclusive and which is inclusive.

Javascript: recursion + for loop + scope

For the past few days I have tried to solve this problem, but up until now I have not been able to find a solution.
The code below recursively finds paths on a graph. Instead of outputting nodePath's with four nodes, it seems to output 'one nodePath' with a newly added node from every cycle (resulting in path's from 1 to 200+ nodes incrementally). The recursive path call does not seem to make a fresh 'nodePath', however it does with neighbors[node_nw] and depth.
var startNode = s.graph.nodes('n0');
var emptyNodeRoute = [];
path(startNode, 0, emptyNodeRoute);
function path (node, depth, nodePath) {
nodePath.push(node);
if (depth == 3) {
printPath (nodePath);
} else {
depth ++;
var neighbors = s.graph.neighbors(node.id);
for (var node_nw in neighbors) {
(function() {
path (neighbors[node_nw], depth, nodePath);
}());
}
}
}
//prints node route
function printPath (nodePath) {
var str = '';
for(var k = 0; k < nodePath.length; k++) {
str = str.concat(' ', nodePath[k].label);
}
console.log ('nodePath: ' + str);
}
I guess it has to do with the specificity's of javascript regarding (no) block scoping, closures and recursion? Or maybe something small I am overlooking? I have referenced several resources (amongst http://zef.me/2843/javascript-the-scope-pitfall) and topics on this site but none of them got me into solving this problem.
Any help would be greatly appreciated!
This is not an scoping, closure or recursion problem, but a reference problem.
You always call the path function with the same nodePath reference.
Copy the nodePath variable and everything works as expected.
Here is what you have to change:
for (var node_nw in neighbors) {
// the method slice makes a copy of the array
path (neighbors[node_nw], depth, nodePath.slice());
}
Have a look at the working jsFiddle demo.

Debugging loop and function - javascript

My browser is crashing from this loop that doesn't appear to be unterminated.
function checkLetters(word){
for(i=0;i<5;i++){
for(j=i+1;j<5;j++){
if(word.charAt(i) == word.charAt(j)){
return false;
break;
}
}
}
return true;
}
var compLibrary = [];
for (var k=0;k<library.length;k++) {
if(checkLetters(library[k]) == true) {
compLibrary.push(library[k]);
}
}
I am trying to search the library for words with no repeating letters and pushing it into a new array
The whole library is five letter words.
It's not an infinite loop, but it does look like a pretty expensive operation. There's not any really elegant way to detect an infinite loop (or recursion) so most engines just resort to either
Not trying to detect it, and running forever until some lower-level controller (like, the kernel) kills it.
Automatically killing itself when it gets to a certain recursion depth, loop count, or run time.
Your algorithm loops 5 * 4 * library.length times, so depending on how long your library actually is, your code could certainly trigger #2. But there are faster ways to find duplicate letters:
function checkLetters(word) {
var i=word.length;
var seenChars={};
var c;
while (i-->0) {
c = word.CharAt(i); # The current character
if (c in seenChars) return false;
seenChars[c] = 1;
}
return true;
}
var compLibrary = [];
for (var k=0; k < library.length; k++) {
if (checkLetters(library[k]) == true) {
compLibrary.push(library[k]);
}
}
Shouldn't this loop
for(i=0;i<5;i++){
for(j=i+1;j<5;j++){
be something in these lines
for(var i=0; i< word.length ;i++){
for(j=i+1; j<word.length/2; j++){
Can't see what your issue is but here's the solution I suggest for your problem:
var words = ['hello', 'bye', 'foo', 'baz'];
function hasUniqLetters(word){
var uniq = word.split('').filter(function(letter, idx){
return word.indexOf(letter) == idx;
});
return uniq.length == word.length;
}
var result = words.filter(hasUniqLetters);
console.log(result); //=> ["bye","baz"]
function checkLetters(word){
for(i=0;i<5;i++){ //both i and j were not instantiated
for(j=i+1;j<5;j++){
if(word.charAt(i) == word.charAt(j)){ //It could be crashing if
return false; //word <= 5
break;//a break after a return
} //statement is redundant.
}
}
return true;
}
You must put var before declaring a variable.
word.charAt(i) can be written like word[i]
Try this:
function checkLetters(word){
for(var i=0,j=1,l=word.length-1; i<l; i++,j++){
if(word.charAt(i) == word.charAt(j)){
return false;
}
}
return true;
}
var compLibrary = [];
for(var i=0,l=library; i<l; i++){
if(checkLetters(library[i]) == true){
compLibrary.push(library[i]);
}
}
tldr; The code originally posted should not crash the browser.
The following explains why nested loops are not always bad for efficiency and shows a counter-example where the original code works successfully without crashing the browser when running over 100,000 simulated words.
The complexity of the posted code is low and it should run really fast. It executes here in a fraction of a second (under 20ms!), even at all "20 * 8000" - i.e. C * O(n). Note that the time complexity is linear because the nested loops in checkLetters have a constant time: due to this small fixed limit ("20 loops" max each call) it does not represent a performance problem here.
As such, I maintain that it is not an issue wrt it being an efficiency problem. I assert that the original code will not "crash" a modern browser environment. For longer or unbound words then using a (presumably) lower complexity probe attempt may pay off - but the inner loop runs in small constant time here. (Actually, due to distribution of letters within words and word lengths I would imagine that the constant rarely exceeds "90 loops" for a natural language like English.)
See http://jsfiddle.net/FqdX7/6/
library = []
for (w = 0; w < 100000; w++) {
library.push((w + "12345").slice(0,5))
}
function checkLetters(word){
for(i=0;i<5;i++){
for(j=i+1;j<5;j++){
if(word.charAt(i) == word.charAt(j)){
return false;
}
}
}
return true;
}
$('#time').text("running")
start = +(new Date)
var compLibrary = [];
for (var k=0;k<library.length;k++) {
if(checkLetters(library[k]) == true) {
compLibrary.push(library[k]);
}
}
time = +(new Date) - start
$('#time').text(time + "ms")
On my machine (in Safari) the code runs in ~30 milliseconds (~40ms if the "return false" is removed) for an input of 100,000 words!
In comparison, the answer with a probe (seenChars lookup) actually runs worse in Safari/Chrome. See http://jsfiddle.net/Hw2wr/5/, where for 100k words it takes about 270ms - or about 9x slower. However, this is highly browser dependent and the jsperf in the comments shows that in Firefox the probing approach is faster (by about 2x) but is slower again in IE (say 4-5x).
YMMV. I think the original code is acceptable for the given situation and the "crashing" problem lies elsewhere.

Categories