FloodDepth

Solution:

This java solution for the problem FloodDepth scored a 100%

Logic:

So the logic here is to imagine you are walking down the rocks..as you go down you try to set the minimum depth with how low you have reached, when you go up then at that point you must calculate the maximm depth so far and put it in a depths queue.

Also if you are climbing up higher than ever before then you need to actually reset the minimum node to null because its as good as entering a new valley. At this point reset the minimum depth to null and your highest altitude is also reset to this new high.

Keep doing that until you reach zero altitude, that is end of array!

And because we are collecting the depths in a PriorityQueue, whose comparator is set to maintain the elements in reverse order then in that case we have depths stored in descending order. so when you poll for the first time..you get your answer! maximum depth. Nevertheless if the size is zero..there was no water harvesting 🙂

I hope this makes sense with the algo I have written here, its the first pass..perhaps this can be enhanced with all optimised functions…I leave that to you coder!

import java.util.Collections;
import java.util.PriorityQueue;
import java.util.Queue;

public class FloodDepth {

    public int solution(int[] A) {

        Integer minNode = null;
        Integer highNode = A[0];
        Queue<Integer> depths = new PriorityQueue<>(Collections.reverseOrder());

        for (int i = 1; i < A.length; i++) {
            //we are going up

            if (A[i] > A[i - 1]) {
                if (A[i] > highNode && minNode != null) {
                    //new high, highest altitude, so entering new valley
                    int depth = highNode - minNode;
                    depths.offer(depth);
                    highNode = A[i];
                    minNode = null;
                } else if (A[i] <= highNode && minNode != null) {
                    //going up, though we are still in the valley
                    if (A[i - 1] > minNode) {
                        int depth = A[i] - minNode;
                        depths.offer(depth);
                    } else {
                        int depth = A[i] - A[i - 1];
                        depths.offer(depth);
                    }
                }
                if (A[i] > highNode) {
                    //we need this for boundary conditions
                    highNode = A[i];
                }
            } else {
                //we are going down
, lets evaluate our min node.
                if ((minNode == null) || A[i] < minNode) {
                    minNode = A[i];
                }
            }
        }
        if (depths.size() > 0) {
            return depths.poll();
        }
        return 0;
    }

    public static void main(String[] args) {
        FloodDepth floodDepth = new FloodDepth();
        int depth = floodDepth.solution(new int[] {1, 3, 2, 1, 2, 1, 5, 3, 3, 4, 2});
        System.out.println(depth);

        depth = floodDepth.solution(new int[]{100000000, 1, 2, 99999999});
        System.out.println(depth);
    }
}

Substring Size K

Problem:

Given a string s and an int k, return all unique substrings of s of size k with k distinct characters.

Example 1:

Input: s = "abcabc", k = 3
Output: ["abc", "bca", "cab"]

Example 2:

Input: s = "abacab", k = 3
Output: ["bac", "cab"]

Example 3:

Input: s = "awaglknagawunagwkwagl", k = 4
Output: ["wagl", "aglk", "glkn", "lkna", "knag", "gawu", "awun", "wuna", "unag", "nagw", "agwk", "kwag"]
Explanation: 
Substrings in order are: "wagl", "aglk", "glkn", "lkna", "knag", "gawu", "awun", "wuna", "unag", "nagw", "agwk", "kwag", "wagl" 
"wagl" is repeated twice, but is included in the output once.

Constraints:

  • The input string consists of only lowercase English letters [a-z]
  • 0 ≤ k ≤ 26

Solution:

Logic:

import java.util.HashSet;
import java.util.Set;

public class SusbstringSizeK {

    public static void printUniqueSubstrings(String s, int k) {

        if (k <= s.length()) {
            Set<Character> uniqueCharacters = new HashSet<>();
            Set<String> uniqueSubstrings = new HashSet<>();
            for (int i = 0; i <= s.length() - k; i++) {
                String shorterString = s.substring(i, i + k);
                for (int j = 0; j < k; j++) {
                    uniqueCharacters.add(shorterString.charAt(j));
                }
                if (uniqueCharacters.size() == k) {
                    uniqueSubstrings.add(shorterString);
                }
                uniqueCharacters.clear();
            }
            uniqueSubstrings.stream().forEach(value -> System.out.println(value));
        }
    }

    public static void main(String[] args) {
        printUniqueSubstrings("abcabc", 3);
        printUniqueSubstrings("awaglknagawunagwkwagl", 4);
    }
}

Partition Labels

A string S of lowercase English letters is given. We want to partition this string into as many parts as possible so that each letter appears in at most one part, and return a list of integers representing the size of these parts.

Example 1:

Input: S = "ababcbacadefegdehijhklij"
Output: [9,7,8]
Explanation:
The partition is "ababcbaca", "defegde", "hijhklij".
This is a partition so that each letter appears in at most one part.
A partition like "ababcbacadefegde", "hijhklij" is incorrect, because it splits S into less parts.

Note:

  • S will have length in range [1, 500].
  • S will consist of lowercase English letters ('a' to 'z') only.

Solution:

Logic:

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

public class PartitionLabels {

    public static List<Integer> partitionLabels(String S) {
        List<Character> values = new ArrayList<>();

        for (int i=0; i< S.length(); i++) {
            if (!values.contains(S.charAt(i))) {
                values.add(S.charAt(i));
            }
        }

        List<String> partitions = new ArrayList<>();
        int partitionBegin = S.indexOf(values.get(0));
        int partitionEnd = S.lastIndexOf(values.get(0));


        for(int i=1; i< values.size(); i++) {
            int startIndex = S.indexOf(values.get(i));
            int endIndex = S.lastIndexOf(values.get(i));
            if ((startIndex> partitionEnd)) {
                partitions.add(S.substring(partitionBegin, partitionEnd + 1));
                partitionBegin = startIndex;
                partitionEnd = endIndex;
            } else if (endIndex > partitionEnd) {
                partitionEnd = endIndex;
            }
        }
        partitions.add(S.substring(partitionBegin, partitionEnd + 1));
        partitions.stream().forEach(x -> System.out.print(x + " " ));
        return partitions.stream().map(x -> x.length()).collect(Collectors.toList());
    }

    public static void main(String[] args) {
        List<Integer> values = partitionLabels("ababcbacadefegdehijhklij");
        values.stream().forEach(x -> System.out.print(x + " " ));
    }
}

Amazon Fresh Promotion

Problem:

Amazon Fresh is running a promotion in which customers receive prizes for purchasing a secret combination of fruits. The combination will change each day, and the team running the promotion wants to use a code list to make it easy to change the combination. The code list contains groups of fruits. Both the order of the groups within the code list and the order of the fruits within the groups matter. However, between the groups of fruits, any number, and type of fruit is allowable. The term “anything” is used to allow for any type of fruit to appear in that location within the group.
Consider the following secret code list: [[apple, apple], [banana, anything, banana]]
Based on the above secret code list, a customer who made either of the following purchases would win the prize:
orange, apple, apple, banana, orange, banana
apple, apple, orange, orange, banana, apple, banana, banana
Write an algorithm to output 1 if the customer is a winner else output 0.

Input
The input to the function/method consists of two arguments:
codeList, a list of lists of strings representing the order and grouping of specific fruits that must be purchased in order to win the prize for the day.
shoppingCart, a list of strings representing the order in which a customer purchases fruit.
Output
Return an integer 1 if the customer is a winner else return 0.
Note
‘anything’ in the codeList represents that any fruit can be ordered in place of ‘anything’ in the group. ‘anything’ has to be something, it cannot be “nothing.”
‘anything’ must represent one and only one fruit.
If secret code list is empty then it is assumed that the customer is a winner.

Example 1:

Input: codeList = [[apple, apple], [banana, anything, banana]] shoppingCart = [orange, apple, apple, banana, orange, banana]
Output: 1
Explanation:
codeList contains two groups - [apple, apple] and [banana, anything, banana].
The second group contains 'anything' so any fruit can be ordered in place of 'anything' in the shoppingCart. The customer is a winner as the customer has added fruits in the order of fruits in the groups and the order of groups in the codeList is also maintained in the shoppingCart.

Example 2:

Input: codeList = [[apple, apple], [banana, anything, banana]]
shoppingCart = [banana, orange, banana, apple, apple]
Output: 0
Explanation:
The customer is not a winner as the customer has added the fruits in order of groups but group [banana, orange, banana] is not following the group [apple, apple] in the codeList.

Example 3:

Input: codeList = [[apple, apple], [banana, anything, banana]] shoppingCart = [apple, banana, apple, banana, orange, banana]
Output: 0
Explanation:
The customer is not a winner as the customer has added the fruits in an order which is not following the order of fruit names in the first group.

Example 4:

Input: codeList = [[apple, apple], [apple, apple, banana]] shoppingCart = [apple, apple, apple, banana]
Output: 0
Explanation:
The customer is not a winner as the first 2 fruits form group 1, all three fruits would form group 2, but can't because it would contain all fruits of group 1.

Solution:

Logic:

public class FindFruitCombo {

    public static int winPrize(String[][] codeList, String[] shoppingCart) {
        // checking corner cases
        if(codeList == null || codeList.length == 0)
            return 1;
        if(shoppingCart == null || shoppingCart.length == 0)
            return 0;

        int i = 0, j = 0;
        while (i < codeList.length && j + codeList[i].length <= shoppingCart.length) {
            boolean match = true;
            for (int k = 0; k < codeList[i].length; k++) {
                if (!codeList[i][k].equals("anything") && !shoppingCart[j+k].equals(codeList[i][k])) {
                    match = false;
                    break;
                }
            }
            if (match) {
                j += codeList[i].length;
                i++;
            } else {
                j++;
            }
        }
        return (i == codeList.length) ? 1 : 0;
    }

    public static void test(String[][] codeList, String[] shoppingCart, int expect) {
        System.out.println(winPrize(codeList, shoppingCart) == expect);
    }

    public static void main(String[] args) {
        // test cases
        String[][] codeList1 = { { "apple", "apple" }, { "banana", "anything", "banana" } };
        String[] shoppingCart1 = {"orange", "apple", "apple", "banana", "orange", "banana"};
        String[][] codeList2 = { { "apple", "apple" }, { "banana", "anything", "banana" } };
        String[] shoppingCart2 = {"banana", "orange", "banana", "apple", "apple"};
        String[][] codeList3 = { { "apple", "apple" }, { "banana", "anything", "banana" } };
        String[] shoppingCart3 = {"apple", "banana", "apple", "banana", "orange", "banana"};
        String[][] codeList4 = { { "apple", "apple" }, { "apple", "apple", "banana" } };
        String[] shoppingCart4 = {"apple", "apple", "apple", "banana"};
        String[][] codeList5 = { { "apple", "apple" }, { "banana", "anything", "banana" } };
        String[] shoppingCart5 = {"orange", "apple", "apple", "banana", "orange", "banana"};
        String[][] codeList6 = { { "apple", "apple" }, { "banana", "anything", "banana" }  };
        String[] shoppingCart6 = {"apple", "apple", "orange", "orange", "banana", "apple", "banana", "banana"};
        String[][] codeList7= { { "anything", "apple" }, { "banana", "anything", "banana" }  };
        String[] shoppingCart7 = {"orange", "grapes", "apple", "orange", "orange", "banana", "apple", "banana", "banana"};
        String[][] codeList8 = {{"apple", "orange"}, {"orange", "banana", "orange"}};
        String[] shoppingCart8 = {"apple", "orange", "banana", "orange", "orange", "banana", "orange", "grape"};
        String[][] codeList9= { { "anything", "anything", "anything", "apple" }, { "banana", "anything", "banana" }  };
        String[] shoppingCart9 = {"orange", "apple", "banana", "orange", "apple", "orange", "orange", "banana", "apple", "banana"};

        // test
        test(codeList1, shoppingCart1, 1);
        test(codeList2, shoppingCart2, 0);
        test(codeList3, shoppingCart3, 0);
        test(codeList4, shoppingCart4, 0);
        test(codeList5, shoppingCart5, 1);
        test(codeList6, shoppingCart6, 1);
        test(codeList7, shoppingCart7, 1);
        test(codeList8, shoppingCart8, 1);
        test(codeList9, shoppingCart9, 1);
    }
}