loading...
Cover image for Interview Qs Decoded - # 1

Interview Qs Decoded - # 1

catcarbn profile image Cat Carbonell Updated on ・3 min read

Hello everyone! Welcome to the first in a series! I'm going to try to explain a common software engineering interview question to better understand it and hopefully remember it when the time comes!

These problems will primarily be solved in JavaScript, as that is my language of choice when testing (and I just want to become a good front-end dev. 🥺)


Q: Find the second largest number in a given array.

Params: We are given an array of whole, positive integers (no negative numbers or floats). We are to write a function and return the second largest integer.

Let's start!

We'll write the skeleton of our function, setting the input/argument as "arr" for array:

function secondLargest(arr){};

Then, we'll need to set two empty variables: largest and second.

Why? We will need placeholders for both our prospective largest and second largest numbers as we loop through our array.
We want to keep track of each integer that is in the array and measure the value against the others

function secondLargest(arr){ 
    let largest = '';
    let second = '';
}

...Which brings us to our next step: create a for-loop!
As we iterate through the array, we will measure each value against each other, comparing the variable "largest" to the current iteration value (arr[i]).

function secondLargest(arr){
    let largest = '';
    let second = '';
    //
    for(let i=0; i < arr.length; i++){};
    //
};

To compare, we will create an if-statement comparing largest to arr[i].

If arr[i] is greater than largest, then replace it with the current value of arr[i] by redeclaring largest and setting it equal to arr[i]

function secondLargest(arr){
    let largest = '';
    let second = '';
    for(let i=0; i < arr.length; i++){
        //
        if(arr[i] > largest){
           largest = arr[i]
        };
       //
    };
};

We found the largest number! But how do we get the second largest?
We did find it already (kind of): we'll just set the former "largest" number to the "second" variable.

HOWEVER, we must declare the second variable BEFORE we declare the new largest number, simply because order matters-- JavaScript executes code from the top-down.

function secondLargest(arr){
    let largest = '';
    let second = '';
    for(let i=0; i < arr.length; i++){
        if(arr[i] > largest){
           //
           second = largest;
           //
           largest = arr[i];
        }; 
    };
};

Speaking of order and specificity, it's time we find the "true" second-largest number in the array.

Let's create another if-statement with more specific parameters:

If the arr[i] is GREATER THAN second AND LESS THAN largest, then set arr[i] as second

function secondLargest(arr){
    let largest = '';
    let second = '';
    for(let i=0; i < arr.length; i++){
        if(arr[i] > largest){
           second = largest;
           largest = arr[i];
        };
        //
        if(arr[i] > second && arr[i]< largest){
           second = arr[i];
        };
        // 
    };
};

Finally, we'll return our second variable to complete the requirement.

function secondLargest(arr){
    let largest = '';
    let second = '';
    for(let i=0; i < arr.length; i++){
        if(arr[i] > largest){
           second = largest;
           largest = arr[i];
        };
        if(arr[i] > second && arr[i]< largest){
           second = arr[i];
        };
    };
    //
    return second;
    //
};

And there you have it! It's a fairly simple solution, a bit long since we're using a traditional for-loop, but it works!

Feel free to post your own solutions in your programming language of choice in the comments!


Thanks for reading!

If you'd like to keep in touch, please reach out to me on Twitter!

Posted on Jun 11 by:

catcarbn profile

Cat Carbonell

@catcarbn

Learner Advocate @eggheadio! UX/UI Engineer! General Assembly alum [SEI 08]!

Discussion

markdown guide
 

Hi Cat!

Amazing solution!

There are several testcases that would not not pass.
in case [0,1] -> 0 is the second largest, but function returns ' '.
in case [1, 0] -> 0 again is the second largest, but the function will return 1.
in case [1,1,1,0] -> same as in the previous testcase.

This happens because of comparison of 0 with an empty string.
' ' === 0 // false
' ' > 0 // false
' ' < 0 // false

The small change that I would do:

  1. Sort the array.
  2. If the array is not empty, take its first element as a potential largest and second. let largest = arr[0]; let second = arr[0];

You know that arr[0] element exists for sure if array is not empty.
Sorting will allow you to start with the smallest element whatever it is and find the second largest.


Small note for other solutions:
You cannot just sort an array and take a second element from the end ;)
in case of [0,1,2,2,2,2] code will return 2. You also need to make numbers unique.

This challenge also tests how creative you can be in your testcases and the ability to think what can potentially break your code.

 

How about checking array is valid (as an numeric array which length > 0) via:
if (!Array.isArray(array) || !array.length || array.some(isNaN)) {
return ("Not a valid array")
}

Regarding the 0 comparison, how about:
let max = -Infinity, second = -Infinity

 

Ooooh got it. Darn it, HackerRank, for giving me a false-positive. ;____;
I'll refactor the code above and credit you! Thanks Lia! You da best.

 

This is a great way of learning, growing and sharing. Keep it up please, I'll follow along.

For these kinds of things I really love the expressive power of functional programming that allows me to declaratively process the array (projecting, reducing, filtering, ...).

Your solution works well, no doubt. I just like it a bit more expressive (performance issues put aside), along the lines of (pseudocode):

return arr.sortDescending().skip(1).firstOrDefault();

 

Why not return arr.sortDescending()[1] ?

 

Depends on the implementation. I was biased to think of LINQ (C#).

If the object returned by 'sortDescending' contains less than two items, the index approach will throw an exception.

 

Just for the sake of brevity, but not improved performance:

    let [second, max] = array.sort().slice(-2)
 

I might be misunderstanding the docs (developer.mozilla.org/en-US/docs/W...), but it looks like there would be an issue with this implementation. When a callback function isn't passed to the sort method, all the non-undefined array elements are converted to strings and compared to another.

const array = [ 10000, 100, 1000, 10, 1, 11, 123, 45, 8900, 2 ];
array.sort();
// -> array = [ 1, 10, 100, 1000, 10000, 11, 123, 2, 45, 8900 ];

This means that second would point to 45 and max would point to 8900 even though 10,000 exists in the array.

 

Sure good point:

const [second, max] = array.sort((a,b)=>a-b).slice(-2)
 

Daaamn that’s slick. 👌🏾👌🏾👌🏾

 

Yeah but I bet yours is faster :)

 

The initializers should probably be undefined since the function will return the wrong result if the array consists of fewer than 2 items or if all items in the array consist of the same value.

Gotta watch out for those edge cases!

 

Thanks for posting, Cat!

This is my solution:

function secondLargestNum(nums) {
    // get length of array
    const arrLength = nums.length;
    /*
    Adjust for zero-based indexing of array and 
    return index of second last number
    */
    const secondLastIndex = arrLength - 2; 

    // sort numbers in ascending order
    nums.sort((currentNum, nextNum) => {
      if (currentNum > nextNum) {
        return 1;
      } else if (currentNum < nextNum) {
        return -1;
      }
    })

    return nums[secondLastIndex];
} 
 

I think the second 'if' should be an 'else if'.

What if the array given is something like [1,1], meaning there is no second largest integer?

 

Good point! Let me try that out and I'll fix it up. :) Thanks Sebastian!

 

My solution using using the Ramda library

const secondLargest = pipe(sort(subtract),dropLast(1),last)
 

As a learning lesson, this example could be improved:

First, there's a bug in that it doesn't handle cases like [2, 5, 10, 9, 10, 7] where the numbers aren't unique. (I double-checked, uniqueness was not part of your Params description above.) In that case, the code above will return 9, even though it's clearly not the second-largest.

Second, if you fix that by using >= in the first test, the second one isn't even needed. The storing of second in the first test takes care of the second largest, even if there's only one element in the array.

So the for loop could be simplified to just:

    for(let i=0; i < arr.length; i++){
        if(arr[i] >= largest){
           second = largest;
           largest = arr[i];
        };
    };
 
 

if(arr.length > 1)
return arr.sort((a,b)=> {return b-a})[1]

 

You may want to make it recursive for multi-dimensional arrays

 

Well the problem was toooo simple.