Quick meta-info:
I was looking for really right place for this question, there is none on stackoverflow. Still answering this question requires programming experience.
I am senior software engineer and lead node.js developer in company with 250 employees, therefore I am doing technical interviews. I am here only for 2 months, so I do not have that much experience with it (previous company was much smaller, so hiring new backend guy was very rare).
The part of interview is live-coding, usually through skype. I think this is quite important, because some people are really not able to do almost anything.
But there is one thing that bugs me - a lot people failing on task "find second biggest number in array" which I think is very easy.
I usually write them this piece of code with only limitation - dont sort an array and dont use any special functions for arrays:
const _arr = [1, 7, 8, 5, 4, 2];
function findSecondBiggest(arr){
}
console.log(findSecondBiggest(_arr));
And task is to write code into function that finds second biggest number. I thought this would be just "check" question and would be "just do it" for most programmers.
Even the developers that look quite promising are often failing on that. I know that they are under pressure, but I am even trying to guide them, calm them and they have at least 20 minutes (often even 30 as I stay 10 minutes more on the call to give them chance to finish it).
A lot of developers look very promising - they have good experience, knowledge, are able to evaluate why they are using this framework/technology... But are not able to do this one.
I have consulted it with Technical Lead and he says that if they are not able to do this, we should discontinue - as we are looking for the programmers and we are expecting to write code. Also the company is interested for mid to senior level developers.
Is this task really that hard? Or is it a good one that really shows if you can come up with at least simple algorithm and implement it?
I am also accepting the solution where you use two for-cycles when first one finds the biggest number, the second for-cycle finds the second biggest number as it is still O(n).
It's not hard, and it makes you think. I would definitely use this kind of question in an interview. However, I would prepare some guiding questions:
How would you find the largest?
How do you know that a number is the 2nd?
etc...
And here is my lovely solution (test cases stolen from #BrettDeWoody's answer). You can use the the standard way of finding the largest number, and then add in the lowest as well.
const _arr = [1, 7, 8, 5, 4, 2];
function findSecondBiggest(arr){
const r = {};
for(let i = 0; i < arr.length; i++) {
if(r.first === undefined || arr[i] > r.first) {
r.second = r.first;
r.first = arr[i];
} else if (arr[i] !== r.first && (r.second === undefined || arr[i] > r.second)) {
r.second = arr[i];
}
}
return r.second; // for arrays with length under 2, the answer would be undefined
}
console.log(findSecondBiggest([1, 7, 8, 5, 4, 2])); // 7
console.log(findSecondBiggest([1, 0, 0, 0, -1, -2])); // 0
console.log(findSecondBiggest([2, 2, 1, 0, -1, -2, 2])); // 1
console.log(findSecondBiggest([1, 1, 1, 1, 1])); // undefined
console.log(findSecondBiggest([0, 0, 0, 1])); // 0
console.log(findSecondBiggest([1, 2, 3, 4])); // 3
console.log(findSecondBiggest([Infinity, -Infinity])); // -Infinity
console.log(findSecondBiggest([-Infinity, Infinity])); // -Infinity
console.log(findSecondBiggest([1, 2, 3, 4, 5, Infinity])); // 5
console.log(findSecondBiggest([1])); // undefined
Completely agree with smac89's sentiment. As a member of an engineering hiring team, and code mentor, I'm not a fan of interview questions with unrealistic constraints.
Instead of asking a question a candidate will never encounter outside a technical interview, pose a challenging question relevant to what the candidate will be working on, and allow the candidate to demonstrate their knowledge of the language and skills they'll be using.
As a great example, a friend recently shared a frontend interview question - build a simple app without any libraries, within a time constraint.
Using a provided API endpoint (which returned paginated results using a ?page=N query param), the app had to take a user's search, retrieve all the results (which might involve multiple pages of results), sort all the results alphabetically, and display all the results at once. This required knowledge (and more importantly, awareness) of fetch, Promise (and Promise.all), array methods, event listeners, and vanilla JavaScript DOM manipulation.
The candidate could consult any docs, and use any built-in methods as needed. The time constraint allowed enough to time to complete as long as the candidate was somewhat familiar with the built-in JS methods, Fetch API, Promises, etc.
IMO, a near-perfect interview question (for frontend devs at least).
My 2ยข.
And here's my solution to the question which:
Uses ES5
Uses no array methods (other than Array.length)
Handles edge cases like a homogeneous array, array of length 1, etc
function findSecondBiggest(arr, startInd){
let start = startInd || 0;
let largest = arr[start];
let secondLargest = null;
const arrLength = arr.length;
if (start === arrLength - start) {
return null;
}
for (var i = start + 1; i < arrLength; i++) {
largest = arr[i] > largest ? setSecond(largest) && arr[i] : largest;
}
function setSecond(num, check) {
secondLargest = num;
return true;
}
if (secondLargest === null) {
arr[arrLength] = arr[0];
return findSecondBiggest(arr, start + 1);
}
return secondLargest;
}
console.log(findSecondBiggest([1, 7, 8, 5, 4, 2]));
console.log(findSecondBiggest([1, 0, 0, 0, -1, -2]));
console.log(findSecondBiggest([2, 2, 1, 0, -1, -2, 2]));
console.log(findSecondBiggest([1, 1, 1, 1, 1]));
console.log(findSecondBiggest([0, 0, 0, 1]));
console.log(findSecondBiggest([1, 2, 3, 4]));
console.log(findSecondBiggest([Infinity, -Infinity]));
console.log(findSecondBiggest([-Infinity, Infinity]));
console.log(findSecondBiggest([1, 2, 3, 4, 5, Infinity]));
console.log(findSecondBiggest([1]));
In reality, developers will take the path of least resistance. That is, they will sort the array and take the second last element. Less code to write and less thinking involved. A win in my book.
So the question you have to consider is whether you want developers who can remember how to implement this algorithm correctly from scratch (possibly buggy), or the ones who can reuse already existing methods to find the solution in the least amount of time, with nearly negligible time penalty, AND mostly bug free.
I mean when was the last time you wanted to find the second largest element in an array of millions of elements? Most developers will probably just opt for the method I described initially (sorting and take second largest), and leave the optimisation to O(n) for another time if it is found that the code is the bottleneck to any performance issues.
const _arr = [1, 7, 8, 5, 4, 2];
function findSecondBiggest(arr) {
if(arr.length < 2) {
return undefined;
}
var first = arr[0];
var second = arr[1];
if(second > first) {
[first, second] = [second, first];
}
for(var i = 2; i < arr.length; i++) {
var tmp = arr[i];
if(tmp > first) {
[first, second] = [tmp, first];
} else if(tmp > second) {
[first, second] = [first, tmp];
}
}
return first != second ? second : undefined;
}
console.log(findSecondBiggest(_arr));
No, I wouldn't say this is an exactly hard question. Even though there are a few catches which may easily throw off someone under stress:
Handling of bad input (not enough input elements)
Special handling for the head of the input
Swapping variables if you don't know ES6 syntax
Mixing up index and value
So while not hard, there are a couple of caches which can get candidates stuck easily, or cause them to get confused.
var a = [1, 7, 8, 5, 4, 2];
for (var i = 0; i < a.length ; i++) {
var big = 0;
for (var j = 0; j < a.length ; j++) {
if (a[j] > a[i]) big++;
}
if (big == 1) {
return a[i];
}
}
and with predefined methods
a[a.sort().length-2]
Related
const addTwo = [1, 2, 3, 4, 5];
for (let i = addTwo.length; i >= 5; i++) {
addTwo = addTwo += 2 //I know this does not work
}
console.log(addTwo); // -> should print [3, 4, 5, 6, 7];
Hi there,
New to js and working on using an array with a for loop. In this problem it's asking me to specifically use a for loop to get a solution. I was able to get my answer using splice. But, to be honest I thought this was a little heavy handed and lazy to me. I didn't think it was going to help me learn anything. I have exhausted many options online. Looking at various videos on the subject of for loops.
I just felt I could use some help from the pros. I get a "Type Error on line 4: Assignment to constant variable." Now, as I understand you can't change a constant variable. Any ideas what I could use as a beginner? Thank you for your patience and help!
You need to assign to the array element, not the whole array. And the indexes in the loop are wrong. You should start from 0 and go up to the length-1. Your loop will repeat infinitely because i >= 5 is always true when you start with i = 5 and keep adding 1 to it.
const addTwo = [1, 2, 3, 4, 5];
for (let i = 0; i < addTwo.length; i++) {
addTwo[i] += 2;
}
console.log(addTwo);
Write a "PrintZigZag" program that provides an array of 10 integers
containing any values and prints the elements in the following order:
the first-the last, the second-the last second, etc ... (The program
must be written pretending not to know what the values entered in the
array are)
This was a interview question for a position of "Junior Web Developer" and i didn't know how to solve it...
let numbers = [1,2,3,4,5,6,7,8,9,10];
this is the result you're looking for?
[1, 10, 2, 9, 3, 8, 4, 7, 5, 6]
I really enjoy interview questions, thankyou for sharing. please let me help explain what im doing here
let numbers = [1,2,3,4,5,6,7,8,9,10];
var result = [];
for(i=1; i< numbers.length+1 /2; i++) {
result.push(i);
result.push(numbers.pop());
}
I am looping over half the array starting at 1. Then I am pushing the first index onto the result array, and then straight after I am popping off the last number of the array.
This will build up a new array consisting of the first number and then the last number, eventually reaching the end.
Here's Sweet Chilly Philly's solution using .map. An interviewer will probably want to see you use the for loop, but knowing modern loops could help as well.
let arr = [];
numbers.map(item => {
arr.push(item);
arr.push(numbers[numbers.length - 1])
numbers.pop()
})
And here's a solution with a do, while loop as Peter S mentioned. Be careful with these since they can end in an infinite loop if not escaped correctly.
let arr = [];
do {
arr.push(numbers[0])
arr.push(numbers[numbers.length - 1])
numbers.shift()
numbers.pop()
} while (numbers.length > 0)
I was testing a few pieces of code out, and two statements that should return the same value return different values.
const arr = [3, 'foo', { bar: 'baz' }, false, 4, 5];
for(var i = 0; i < arr.length; i++) {
i = arr[i]
console.log(i)
}
returns [3, 4, 5], while
const arr = [3, 'foo', { bar: 'baz' }, false, 4, 5];
for(var i = 0; i < arr.length; i++) {
console.log(arr[i])
}
returns [3, 'foo', { bar: 'baz' }, false, 4, 5]
Why?
This is a great example of both the flexibility and pitfalls of imperative programming.
tl;dr you shouldn't be modifying i in you're for loops, and you also shouldn't be using for loops. A better way to iterate over the array is:
arr.forEach(function(item, i) {
console.log(item)
})
Imperative Programming
Copied from Wikipedia: In computer science, imperative programming is a programming paradigm that uses statements that change a program's state.
What does this mean?
In simple terms, whenever you are modifying variables (mutation), you're programming imperatively. For example:
var x = 1;
x = 5;
console.log(x + 5); // you would get 10
However, this can lead to unexpected problems which we can see in your example which is explained pretty well in other answers.
This is why in general, it's a good idea to avoid it (at least in Javascript) even though imperative programming is so convenient. This doesn't mean we always avoid it. Sometimes, programs need to run as efficient as possible, and imperatively modifying variables is the only way to achieve that.
In most cases, we don't need that efficiency if we're iterating (looping) through only a few hundred or even tens of thousands of variables. Our computers are fast enough that the difference in performance is not worth it.
Functional Programming
Functional programming is a great alternative. In practice, it boils down to one simple rule - no side effects. Side effects simply mean mutation, i.e modifying variables.
This avoids bugs that would be introduced in imperative programming since you know that once you initialize a variable, it will always be the same.
Below, I'll outline a pseudo introduction to functional programming and how it relates to your example. If you want to learn more about it, you can find countless resources online. Here's a pretty good article about functional programming with Javascript.
Some examples of functional programming
const x = 5; // we use const do denote x is constant and can't be changed ever
// x = 5 would give us an error!
const y = x + 5
// for (const i = 0; i < 10; ++i) is not functional since i is modified!
How should we loop without for loops? Recursion!
It's almost always good to avoid using for loops in the form of for (var i ...). This is because those loops are based on imperative programming, which we want to avoid if possible.
How do we print all the values of an array?
function printValues(arr, i = 0) {
if (i == arr.length) return; // exit when we reach the end
console.log(arr[i]); // let's call console.log
printValues(arr, i + 1); // do the same thing with the next index of the array
}
What if instead of just printing, we want to double every element in the array and double it? Instead of rewriting the same function, we can generalize this:
function forEach(arr, method, i = 0) {
if (i == arr.length) return;
method(arr[i], i)
return forEach(arr, method, i + 1)
}
// notice that forEach looks exactly like printValues, except now, we can pass in anything we would have passed into a normal for loop
forEach([1,2,3,4,5], function(item, i) {
const x = i * 2
console.log(x);
})
// now back to OP's example, we can use this forEach function
forEach(arr, function (item, i) {
console.log(item)
})
Of course, Javascript has these functions built-in and they are also optimized. So, you can just use the built-in forEach:
arr.forEach(function(item, i) {
console.log(item)
// or console.log(arr[i]);
})
There are other functions to use too other than forEach, these include:
map
filter
reduce
There are more, but these are the fundamental building blocks for iteration on arrays in functional Javascript and are must-haves in your toolkit!
I think second snippet explains itself only the first one needs explanation.
First of all there is no sense to write i = arr[i] inside a loop. It changes the looping number of the element at corresponding index. Which means anything unexpected could happen
What happened in your case is below
In first iteration i is 0 then its changed to 3 due to i = arr[i].
In second iteration i is 4 because last value of i is incremented due to i++. Due to i = arr[i] i becomes 4 the arr[4]
In third iteration i becomes 5 due to increment i++ and due i = arr[i] it remains 5.
In fourth iteration it becomes 6 and loop ends because i < arr.length becomes false
const arr = [3, 'foo', { bar: 'baz' }, false, 4, 5];
for(var i = 0; i < arr.length; i++) {
console.log(`Initial i = ${i}`)
i = arr[i];
console.log(`Final i = ${i}`);
console.log('\n')
}
I am looking for a way to create an 2 arrays of integers at the same time until one common value is find in the 2 arrays. I don't know when this common integer will be find, so I don't know where to stop my loop until the match is find.
Here is the example that I want to achieve when the 2 array are already created:
var arr1 = [3, 6, 9, 12, 15, 18, 21, 24, 27];
var arr2 = [5, 10, 15, 20, 25, 30, 35, 40, 45];
var arr3 = [];
for (var i = 0; i < arr2.length; i++){
if (arr1.includes(arr2[i])){
arr3.push(arr2[i]);
}
}
here, the common integer is 15. arr3 return 15.
I am trying to get to the same result without knowing with the common multiplier will be find but can't find the correct way to do it.
I would like to achieve this by doing something like this :
var num1 = [3, 5];
var res = [];
for (var i = 1; i <= 10; i++){
if (num1[0]*i.includes(num1[1]*i)){
res.push(i);
}
}
Any idea how I could achieve this?
Thank you!
If you're looking for this as a way to find the least common multiple (LCM), then this is far overblown, but if you want the list of multiples of each up to the least common multiple, this might do it:
const last = (arr) => arr[arr.length - 1]
const buildMultiples = (a, b) => {
while (last(a) < last(b)) {
a.push(last(a) + a[0])
}
if (last(a) == last(b)) {
return [a, b]
}
return buildMultiples (b, a)
}
console.log(buildMultiples ([3], [5]))
But if you're just looking for the LCM, then you should try a purely numeric technique.
Note that I use recursive rather than iterative techniques here. While there are many cases for which either makes sense, here it seems to me that any iterative technique would be much less understandable than this recursive one. (I'd love to be proven wrong on this.)
(Also note that there is no error checking. If you don't supply two arrays holding single positive integers, things could go very wrong.)
Having learned some Javascript from CodeAcademy, I wanted to try some exercises to test my knowledge.
The exercise was this
Write a JavaScript function which will take an array of numbers stored and find the second lowest and second greatest numbers, respectively. - See more at: http://www.w3resource.com/javascript-exercises/javascript-functions-exercises.php#EDITOR
My function was this
function checker(array) {
narray = array.sort();
console.log(narray);
console.log(narray[1] + "," + narray[array.length - 2]);
}
checker([1, 2, 3, 4, 5]);
Their function was this
function Second_Greatest_Lowest(arr_num)
{
arr_num.sort(function(x,y)
{
return x-y;
});
var uniqa = [arr_num[0]];
var result = [];
for(var j=1; j<arr_num.length; j++)
{
if(arr_num[j-1] !== arr_num[j])
{
uniqa.push(arr_num[j]);
}
}
result.push(uniqa[1],uniqa[uniqa.length-2]);
return result.join(',');
}
alert(Second_Greatest_Lowest([1,2,3,4,5]));
Do you see any reason why the second option would be better?
As noted, their answer wants the 2nd unique number and it is rather inefficient as well.
There are two differences between your solution and theirs:
sorting function
uniqueness
The implicit sorting function is a natural sort. This means that the objects are converted to strings and compared as strings:
[1, 2, 3, 11].sort() // [1, 11, 2, 3]
[1, 2, 3, 11].sort(function(a,b){ return a-b }); // [1, 2, 3, 11]
The second difference, the uniqueness of the numbers. Your solution gives the number on the second position in the array, while theirs gives the number with the second lowest value:
[1,1,2] // Your solution: 1,1
[1,1,2] // Their solution: 2,1
While you can argue that it is not required, that is a matter of definition.
Either way, an improvement could be made in their solution as well to make it more efficient, though not as readable:
function getNumbers(arr) {
if (!arr.length) throw new Error('arr has no items');
arr = arr.slice().sort(function(a,b){ return a-b }); // copy and sort the array
for (var i=0; arr[i] === arr[0]; i++);
if (i === arr.length) { // all numbers are identical
return [arr[0], arr[0]];
}
var a = arr[i]; // second lowest number
i = arr.length-1;
var b = arr[i];
while (arr[i] === b) i--;
return [a, arr[i]];
}
// usage
getNumbers([2,3,1,1,1,6,4,5,6,1,11]) //[2, 6]
As you can see, once you found the number you're interested in, you no longer iterate through the sorted array. Compared to the solution that computes an array of unique numbers, this one is far more efficient, especially for large arrays.
No. Your function is just better. Really.
Reason is that on w3resource.com wants to show you how it should work - it's tutorial. You are just practical programmer.
Both solutions will work also when you put string inside, or negative numbers ..
The text of an exercise is misunderstood. They SHOULD have ask for a second "unique" number from the beginning and from the end. Then:
1, 1, 1, 1, 1, 2, 3, 4, 5, 6, 6, 6, 6, 6
Real answers are: 2, 5. Answers from Your script are 1 and 6.
So Your answer is OF COURSE great and OK, but their question is a bit inaccurate.
But a fact that You have note their mistake, and make a better algorithm, sugest that You can skip to another lesson :).