Thursday, November 23, 2023

 #codingexercise 

Given an integer array arr, in one move you can select a palindromic subarray arr[i], arr[i+1], ..., arr[j] where i <= j, and remove that subarray from the given array. Note that after removing a subarray, the elements on the left and on the right of that subarray move to fill the gap left by the removal.

 

Return the minimum number of moves needed to remove all numbers from the array.

 

 

import java.util.*;

class Solution {

    public int minimumMoves(int[] arr) {

        int N = arr.length;

        int max = 1;

        int min = Integer.MAX_VALUE;

        List<Integer> A = new ArrayList<>();

        for (int i = 0; i < arr.length; i++) A.add(arr[i]);

        int count = 0;

        while(A.size() > 0) {

           boolean hasPalindrome = false;

           List<Integer> elements = new ArrayList<>();

           for (int i = 0; i < (1<<N); i++) {

              

               List<Integer> combination = new ArrayList<>();

                for (int j = 0; j < A.size(); j++) {

                  if ((i & (1 << j)) > 0) {

                    combination.add(j);

                  }

                }

                if (isPalindrome(A, combination) && (combination.size() > max) && getCharactersToRemove(A, combination) < min) {

                      hasPalindrome = true;

                      max = combination.size();

                      elements = new ArrayList<>(combination);               

                      if (getCharactersToRemove(A, combination) == 0) { break;}

                } else {

                    // System.out.println("A: " + print(A) + " Elements: " + print(elements) + " Combination: " + print(combination) + "isPalindrome=" + String.valueOf(isPalindrome(A, combination)) + " getCharsToRemove=" + getCharactersToRemove(A, combination) + " min = " + min);

                }

           }           

           if (!hasPalindrome) {

               count += 1;

               A.remove(A.size() - 1);

           } else {

               count += getCharactersToRemove(A, elements) + 1;

               A = removeCharacters(A, elements);

               // System.out.println("Removing " + count + " characters at indices:" + print(elements) + " and remaining elements: " + print(A));

               // elements = new ArrayList<>();

               max = 1;

               min = Integer.MAX_VALUE;

           }

        }

        return count;

    }

    public boolean isPalindrome(List<Integer> A, List<Integer> combination) {

        int start = 0;

        int end = combination.size()-1;

        while (start <= end) {

            if (A.get(combination.get(start)) != A.get(combination.get(end))) {

                return false;

            }

            start++;

            end--;

        }

        return true;

    }

    public int getCharactersToRemove(List<Integer> A, List<Integer> combination){

        if (combination.size() < 2) return 0;

        int start = combination.get(0);

        int end = combination.get(combination.size()-1);

        int count = 0;

        for (int i = start+1; i < end; i++) {

            if (combination.contains(i) == false){

                count++;

            }

        }

        return count;

    }

    public List<Integer> removeCharacters(List<Integer> A, List<Integer> combination) {

        int start = combination.get(0);

        int end = combination.get(combination.size()-1);

        List<Integer> result = new ArrayList<>();

        if (start > 0){

            result.addAll(A.subList(0, start));

        }

        if (end < A.size() - 1) {

            result.addAll(A.subList(end + 1,A.size()));

        }

        return result;

    }

    public String print(List<Integer> elements){

        StringBuilder sb = new StringBuilder();

        for (int i = 0; i < elements.size(); i++) {

            sb.append(elements.get(i) + " ");

        }

        return sb.toString();

    }

}

Wednesday, November 22, 2023

#codingexercise

Given an array of varying heights above sea level for adjacent plots, and the array of water levels on consecutive days, find the number of islands. An island is a slice of array such that plots adjacent to the boundary of the island are under water.

class Solution {

public int[] solution(int[] A, int[] B) {

    return Arrays

    .stream(B)

    .map(water -> IntStream

         .range(0, N)

         .filter(j -> (A[j] > water) && (j == N - 1 || A[j + 1] <= water))

         .map(i -> 1)

         .sum()) .toArray();

}

}

For example, given the following arrays A and B:

    A[0] = 2    B[0] = 0

    A[1] = 1    B[1] = 1

    A[2] = 3    B[2] = 2

    A[3] = 2    B[3] = 3

    A[4] = 3    B[4] = 1

Solution:

result[0] = 1

result[1] = 2

result[2] = 2

result[3] = 0

result[4] = 2

 

For a water level, the number of islands is just the sum of changes in the number of islands as the water level is decreasing.

Optimized solution:

class Solution {

public int[] solution(int[] A, int[] B) {

     int limit = Math.max(maxLevel(A), maxLevel(B));

     int[] island = new int[limit + 2];

     IntStream.range(0, A.length - 1)

                       .filter( j -> A[j]  > A[j+1])

                      .forEach(j ->  {

                                       island[A[j]] += 1;

                                       island[A[j + 1]] -= 1;

                       });

     island[A[A.length-1]] += 1;

     IntStream.range(-limit, 0)

                      .forEach(i -> island[-i] += island[-i+1]);

     return Arrays.stream(B).map(water -> island[water + 1]).toArray();

}

public int maxLevel(int[] A) {

       return Arrays.stream(A).max().getAsInt();

}

}

 

// before cumulation

island[0] = 0

island[1] = -1

island[2] = 0

island[3] = 2

island[4] = 0

// after cumulation

island[0] = 1

island[1] = 1

island[2] = 2

island[3] = 2

island[4] = 0

 

result[0] = 1

result[1] = 2

result[2] = 2

result[3] = 0

result[4] = 2

 

 https://1drv.ms/w/s!Ashlm-Nw-wnWhNMJfj4kcj7MFloLBw?e=ech2Ur

Tuesday, November 21, 2023

 

Given an array of varying heights above sea level for adjacent plots, and the array of water levels on consecutive days, find the number of islands. An island is a slice of array such that plots adjacent to the boundary of the island are under water.

class Solution {

public int[] solution(int[] A, int[] B) {

    return Arrays

    .stream(B)

    .map(water -> IntStream

         .range(0, N)

         .filter(j -> (A[j] > water) && (j == N - 1 || A[j + 1] <= water))

         .map(i -> 1)

         .sum()) .toArray();

}

}

For example, given the following arrays A and B:

    A[0] = 2    B[0] = 0

    A[1] = 1    B[1] = 1

    A[2] = 3    B[2] = 2

    A[3] = 2    B[3] = 3

    A[4] = 3    B[4] = 1

Solution:

result[0] = 1

result[1] = 2

result[2] = 2

result[3] = 0

result[4] = 2

 

For a water level, the number of islands is just the sum of changes in the number of islands as the water level is decreasing.

Optimized solution:

class Solution {

public int[] solution(int[] A, int[] B) {

     int limit = Math.max(maxLevel(A), maxLevel(B));

     int[] island = new int[limit + 2];

     IntStream.range(0, A.length - 1)

                       .filter( j -> A[j]  > A[j+1])

                      .forEach(j ->  {

                                       island[A[j]] += 1;

                                       island[A[j + 1]] -= 1;

                       });

     island[A[A.length-1]] += 1;

     IntStream.range(-limit, 0)

                      .forEach(i -> island[-i] += island[-i+1]);

     return Arrays.stream(B).map(water -> island[water + 1]).toArray();

}

public int maxLevel(int[] A) {

       return Arrays.stream(A).max().getAsInt();

}

}

 

// before cumulation

island[0] = 0

island[1] = -1

island[2] = 0

island[3] = 2

island[4] = 0

// after cumulation

island[0] = 1

island[1] = 1

island[2] = 2

island[3] = 2

island[4] = 0

 

result[0] = 1

result[1] = 2

result[2] = 2

result[3] = 0

result[4] = 2

 

 

Monday, November 20, 2023

Azure Data Factory and its programmability.

 As with any resource in the Azure public cloud that can be provisioned with an ARM template, Azure Data Factory provides several way to automate its operations such as with the Command Line Interface, Its RESTful APIs and SDK in various languages. Since calling over the public internet with REST APIs allows the caller and the target to be in different networks, this article suggests some API calls for the frequently encountered usages. Specifically, it calls out two use cases: 1) to trigger a pipeline job  and 2) to link external storage accounts so that new pipelines can be created.

Use case 1: Triggering a pipeline job:

This is done with the help of a

POST https://management.azure.com/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.DataFactory/factories/{factoryName}/pipelines/{pipelineName}/createRun?api-version=2018-06-01

Request

With the parameters as

factoryName – for the name of the ADF

pipelineName – for the name of the pipeline within the ADF

resourceGroupName – for the name of the resource group

subscription id – for the id of the subscription

api-version – this could be set to 2018-06-01

The Authorization header will have the Bearer token corresponding to identity with which to execute the request.

The request body can take additional parameters as:
{

  "OutputBlobNameList": [

    "exampleoutput.csv"

  ]

}

The result will usually have a runId with a GUID as value.

Use case 2: Creating a linked service to an external Amazon S3 compatible storage such as ones hosted on-premise.

This is done with the help of a

PUT https://management.azure.com/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.DataFactory/factories/{factoryName}/linkedservices/{linkedServiceName}?api-version=2018-06-01

request

again, with the same parameters as in use case 1.

The request header will carry an authorization with Bearer token of the identity of the caller.

The request body will carry the details for the corresponding service.

{

  "properties": {

    "type": "AzureStorage",

    "typeProperties": {

      "connectionString": {

        "type": "SecureString",

        "value": "DefaultEndpointsProtocol=https;AccountName=examplestorageaccount;AccountKey=<storage key>"

      }

    }

  }

}

The example here shows AzureStorage but for Amazon S3 compatible storage, an account name, an access key and secret will suffice as payload to the API request above.

The response will be similar to what’s shown below except that it will be for Amazon S3 Compatible storage.

{

  "id": "/subscriptions/12345678-1234-1234-1234-12345678abc/resourceGroups/exampleResourceGroup/providers/Microsoft.DataFactory/factories/exampleFactoryName/linkedservices/exampleLinkedService",

  "name": "exampleLinkedService",

  "type": "Microsoft.DataFactory/factories/linkedservices",

  "properties": {

    "type": "AzureStorage",

    "typeProperties": {

      "connectionString": {

        "type": "SecureString",

        "value": "**********"

      },

      "encryptedCredential": "ew0KICAiVmVyc2lvbiI6ICIyMDE3LTExLTMwIiwNCiAgIlByb3RlY3Rpb25Nb2RlIjogIktleSIsDQogICJTZWNyZXRDb250ZW50VHlwZSI6ICJQbGFpbnRleHQiLA0KICAiQ3JlZGVudGlhbElkIjogIkRGLURPR0ZPT0QtWUFOWkhBTkctV1VfM2FiMTk0NjYtNWUxNi00NzU1LWJlNzktMjI2ZTVmZWU3YzY0Ig0KfQ=="

    }

  },

  "etag": "0a0062d4-0000-0000-0000-5b245bcf0000"

}

Reference:

1.       https://learn.microsoft.com/en-us/azure/data-factory/connector-amazon-s3-compatible-storage?tabs=data-factory

2.       https://learn.microsoft.com/en-us/rest/api/datafactory/linked-services/create-or-update?view=rest-datafactory-2018-06-01&tabs=HTTP#linkedservices_create

3.       Prior articles on IaC: IaCResolutionsPart41.docx

Sunday, November 19, 2023

Given clock hands positions for different points of time as pairs A[I][0] and A[I][1] where the order of the hands does not matter but their angle enclosed, count the number of pairs of points of time where the angles are the same 

    public static int[] getClockHandsDelta(int[][] A) { 

        int[] angles = new int[A.length]; 

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

            angles[i] = Math.max(A[i][0], A[i][1]) - Math.min(A[i][0],A[i][1]); 

        } 

        return angles; 

    } 

    public static int NChooseK(int n, int k) 

    { 

        if (k < 0 || k > n || n == 0) return 0; 

        if ( k == 0 || k == n) return 1; 

        return Factorial(n) / (Factorial(n-k) * Factorial(k)); 

    } 

  

    public static int Factorial(int n) { 

        if (n <= 1) return 1; 

        return n * Factorial(n-1); 

    } 

 

    public static int countPairsWithIdenticalAnglesDelta(int[] angles){ 

        Arrays.sort(angles); 

        int count = 1; 

        int result = 0; 

        for (int i = 1; i < angles.length; i++) { 

            if (angles[i] == angles[i-1]) { 

                count += 1; 

            } else { 

                if (count > 0) { 

                    result += NChooseK(count, 2); 

                } 

                count = 1; 

            } 

        } 

        if (count > 0) { 

            result += NChooseK(count, 2); 

            count = 0; 

        } 

        return result; 

    } 

 

        int [][] A = new int[5][2]; 
         A[0][0] = 1;    A[0][1] = 2; 
         A[1][0] = 2;    A[1][1] = 4; 
         A[2][0] = 4;    A[2][1] = 3; 
         A[3][0] = 2;    A[3][1] = 3; 
         A[4][0] = 1;    A[4][1] = 3; 
1 2 1 1 2  
1 1 1 2 2  
4