I am practicing some coding algorithms. In some interviews they don't only ask you to solve a problem, but to solve it in the most efficient way, and also specify the efficiency of the algorithm (aka Big O notation). I've always had issues measuring that efficiency, so I would really appreciate someone explaining how to calculate the efficiency of the algorithmor to point to some resources in order to check it (did not find very useful docs so far).
For example, take a look to this problem below. I have solved it in two different ways. using Java. The first way is using an imperative approach (which I find it more efficient as we don't need to iterate over the lists many times) and the second approach, with functional programming approach and stream API (that I find much less efficient in this case).
Could someone tell me with an explanation what is the Big O notation of both approaches, explaining the way to calculate it?
package exercises;
import org.junit.Assert;
import org.junit.Test;
import java.util.*;
import java.util.stream.Collectors;
/**
* You are given two non-empty linked lists representing two non-negative integers. The digits are stored in reverse order, and each of their nodes contains a single digit. Add the two numbers and return the sum as a linked list.
*
* You may assume the two numbers do not contain any leading zero, except the number 0 itself.
*/
public class AddTwoNumbers {
//Most efficient implemention of the two
private List<Integer> addTwoNumbersImplementation1(LinkedList<Integer> l1, LinkedList<Integer> l2) {
Integer carry = 0;
List<Integer> result = new ArrayList<Integer>();
while (l1.size() > 0 || l2.size() > 0) {
Integer l1Last = Optional.ofNullable(l1.pollLast()).orElse(0);
Integer l2Last = Optional.ofNullable(l2.pollLast()).orElse(0);
Integer partialResult = l1Last + l2Last + carry;
if (partialResult >= 10) {
result.add(Character.getNumericValue(partialResult.toString().charAt(1)));
carry = 1;
} else {
result.add(partialResult);
carry = 0;
}
}
if(carry == 1) {result.add(1);}
return result;
}
//Least efficient implemention of the two
private List<Integer> addTwoNumbersImplementation2(LinkedList<Integer> l1, LinkedList<Integer> l2) {
Integer n1 = Integer.parseInt(new StringBuffer(l1.stream().map(e -> e.toString()).collect(Collectors.joining())).reverse().toString());
Integer n2 = Integer.parseInt(new StringBuffer(l2.stream().map(e -> e.toString()).collect(Collectors.joining())).reverse().toString());
Integer result = n1 + n2;
return new StringBuffer(result.toString()).reverse().toString().chars().mapToObj(Character::getNumericValue).collect(Collectors.toList());
}
@Test
public void test() {
LinkedList<Integer> list1 = new LinkedList<>();
list1.addAll(Arrays.asList(2,4,3));
LinkedList<Integer> list2 = new LinkedList<>();
list2.addAll(Arrays.asList(5,6,4));
List<Integer> resultList = new LinkedList<>();
resultList.addAll(Arrays.asList(7,0,8));
Assert.assertEquals(resultList, addTwoNumbersImplementation1(list1, list2));
}
@Test
public void test2() {
LinkedList<Integer> list1 = new LinkedList<>();
list1.add(0);
LinkedList<Integer> list2 = new LinkedList<>();
list2.add(0);
List<Integer> resultList = new LinkedList<>();
resultList.add(0);
Assert.assertEquals(resultList, addTwoNumbersImplementation1(list1, list2));
}
@Test
public void test3() {
LinkedList<Integer> list1 = new LinkedList<>();
list1.addAll(Arrays.asList(9,9,9,9,9,9,9));
LinkedList<Integer> list2 = new LinkedList<>();
list2.addAll(Arrays.asList(9,9,9,9));
List<Integer> expected = new LinkedList<>();
expected.addAll(Arrays.asList(8,9,9,9,0,0,0,1));
Assert.assertEquals(expected, addTwoNumbersImplementation1(list1, list2));
}
@Test
public void test4() {
LinkedList<Integer> list1 = new LinkedList<>();
list1.addAll(Arrays.asList(2,4,3));
LinkedList<Integer> list2 = new LinkedList<>();
list2.addAll(Arrays.asList(5,6,4));
List<Integer> resultList = new LinkedList<>();
resultList.addAll(Arrays.asList(7,0,8));
Assert.assertEquals(resultList, addTwoNumbersImplementation2(list1, list2));
}
@Test
public void test5() {
LinkedList<Integer> list1 = new LinkedList<>();
list1.add(0);
LinkedList<Integer> list2 = new LinkedList<>();
list2.add(0);
List<Integer> resultList = new LinkedList<>();
resultList.add(0);
Assert.assertEquals(resultList, addTwoNumbersImplementation2(list1, list2));
}
@Test
public void test6() {
LinkedList<Integer> list1 = new LinkedList<>();
list1.addAll(Arrays.asList(9,9,9,9,9,9,9));
LinkedList<Integer> list2 = new LinkedList<>();
list2.addAll(Arrays.asList(9,9,9,9));
List<Integer> expected = new LinkedList<>();
expected.addAll(Arrays.asList(8,9,9,9,0,0,0,1));
Assert.assertEquals(expected, addTwoNumbersImplementation2(list1, list2));
}
}