Thursday 31 December 2020

Two-Sum: C#, Javascript, Python, Java

There are quite a few things that you can learn by solving one computer programming problem in various computer programming languages. So I decided to try out solving Two-Sum problem in 4 languages - C#, JavaScript, Python, and Java.

C# 

public int[] TwoSum(int[] nums, int target) {

        Dictionary<int, int> dict = new Dictionary<int, int>();

        for(int i=0; i < nums.Length; i++){

            int searchTerm = target-nums[i];

            if(dict.ContainsKey(searchTerm)){

                return new int[2] { dict[searchTerm], i};

            }else{

                dict.Add(nums[i], i);

            }

        }       

        return null;

    }

JavaScript

var twoSum = function(nums, target) {

    const map = {};

    for (let i = 0; i < nums.length; i++){

        let diff = target - nums[i];

        if(map[diff] !== undefined){

            return [map[diff], i];

        }else{

            map[nums[i]] = i;

        }

    }

    return null;

};

Python

def twoSum(self, nums: List[int], target: int) -> List[int]:

        map = {}

        for i, num in enumerate(nums) :

            diff = target - num

            if(map.get(diff) != None) :

                return [map[diff], i];

            else :

                map[num] = i;

        return None

Java

public int[] twoSum(int[] nums, int target) {

        Map<Integer, Integer> map = new HashMap<>();

        for (int i = 0; i < nums.length; i++) {

            int complement = target - nums[i];

            if (map.containsKey(complement)) {

                return new int[] { map.get(complement), i };

            }

            map.put(nums[i], i);

        }

        return null;

    }

Observations:

1. Code written in Python is probably the most succinct and readable one than the code written in other languages.

2. Coming from a C# background, it was refreshing to note that primary constructs like dictionary, loop, if-else is pretty much same across other programming languages with a difference in syntax. I did have to struggle to find equivalent of Dictionary in Java though. 

3. Python and JavaScript are similar in tone. Java and C# are similar in tone. There is a lot less ceremony in Python and JavaScript than what is required in Java and C#.

4. When I ran these solutions in LeetCode, the CPU time and memory consumption for each of the languages was a learning experience.


Memory footprint : Python's memory consumption is < 50% of what is typically consumed by Java, C# and JavaScript (perhaps running on Node.JS?). 

Runtime: Somehow Java turned out to be the fastest, I am not sure what compile time/run time optimization would cause this (something for me to learn more about). C# was the slowest by an order of magnitude, perhaps due to the extra time required to load assembly, JIT the code etc. Python was much faster than my expectations :).

All of the above observations can also be result of a transient issue on LeetCode servers. So, don't go by the performance numbers right away - better to run these on local machine and make up your mind.

Saturday 12 December 2020

GitOps!!

Operations in any industry is a tough challenge. It is very different from creating something new. For example - creating a medicine for a disease requires a different process than the process required to industrialize production, distribution and sales processes and ensuring that we never run out of its supply.

Software is also similar. Process for writing code for building functionality is very different from the process required to package the artefacts, distributing it and operationalizing it in production. There are so many methods and tools available to handle these differences.

In the below video Kelsey Hightower talks about GitOps which focuses on providing a process that can simplify the process of managing production. The idea of segregating the production environment config from the actual code artefact (i.e. container image) is an interesting one. One of its core benefits is that it separates environment management and updates from code development. So developers can keep working much faster and we can have processes in place to have non-gated deployments for test environments and gated deployments (e.g. Test environments, UAT, Production rings etc.).

Truly speaking, if you are able to find the right definition of business functionalities and technical functionalities and be able to package them correctly, things can become simpler to upgrade/rollback/canary-test. 

Sunday 6 December 2020

[Recursion]: Finding maximum depth of a binary tree

Recursion in programming is quite common and yet quite tricky to get right. The only you can get it right is by writing code that uses recursion a few times and understand the thinking pattern required to identify smaller version of the same problem.

A typical example of recursion is to find depth of a binary tree.

Say, your tree class looks like following.

public class Node {

    public Node Left { get; set;}

    public Node Right {get; set;}

    public int Value { get; set;}

}

if your tree looks like following, then you can find its maximum depth by just looking at it.

                                                 8

                                          12         15

                                       6    null  null  9

                                                             30

Now, imagine that this tree is much larger. Inspection of the tree is not going to help much. Instead, it might be better to figure out the maximum depth at any given level by 1) looking at depth of its child nodes 2) finding maximum of the depths calculated for its children 3) adding 1 to  it.

So a recursive function that calculates the maximum depth will look like below.

public int FindMaximumDepth(Node node){

    if(node == null){

         return 0;

    }

    var left = FindMaximumDepth(node.Left);

    var right = FindMaximumDepth(node.Right);

    return 1 + Math.Max(left, right);

}

As you can see the above code is quite concise as it uses recursion by finding a smaller version of the same problem by identifying the recursive pattern to the problem. It is quite helpful to have practiced the identification of recursive pattern.