You are on page 1of 9

1.

/*You are given a list of songs where the ith song has a duration of time[i]
seconds.
Return the number of pairs of songs for which their total duration in seconds
is divisible by 60. Formally, we want the number of indices i, j
such that i < j with (time[i] + time[j]) % 60 == 0.

Example 1:

Input: time = [30,20,150,100,40]


Output: 3
Explanation: Three pairs have a total duration divisible by 60:
(time[0] = 30, time[2] = 150): total duration 180
(time[1] = 20, time[3] = 100): total duration 120
(time[1] = 20, time[4] = 40): total duration 60

Input: time = [60,60,60]


Output: 3
Explanation: All three pairs have a total duration of 120, which is divisible by
60.
*/
class Solution {
public int numPairsDivisibleBy60(int[] time) {
int count=0;
int []freq=new int[60];

for(int i: time){
if(i%60==0)count+=freq[0];
else
count+=freq[60-(i%60)];
freq[i%60]++;
}

return count;
}
}

Time Complexity: o(n)


Space Complexity: o(constant)

Optimising Alexa Suggestions


2. /*Given a list of points on the 2-D plane and an integer K. The task is to find
K closest points to the origin and print them.
Note: The distance between two points on a plane is the Euclidean distance.

Examples:

Input : point = [[3, 3], [5, -1], [-2, 4]], K = 2


Output : [[3, 3], [-2, 4]]
Square of Distance of origin from this point is
(3, 3) = 18
(5, -1) = 26
(-2, 4) = 20
So rhe closest two points are [3, 3], [-2, 4].

Input : point = [[1, 3], [-2, 2]], K = 1


Output : [[-2, 2]]
Square of Distance of origin from this point is
(1, 3) = 10
(-2, 2) = 8
So the closest point to origin is (-2, 2)*/

Solution:

// Java program for implementation of


// above approach
import java.util.*;

class GFG{

// Function to print required answer


static void pClosest(int [][]pts, int k)
{
int n = pts.length;
int[] distance = new int[n];
for(int i = 0; i < n; i++)
{
int x = pts[i][0], y = pts[i][1];
distance[i] = (x * x) + (y * y);
}

Arrays.sort(distance);

// Find the k-th distance


int distk = distance[k - 1];

// Print all distances which are


// smaller than k-th distance
for(int i = 0; i < n; i++)
{
int x = pts[i][0], y = pts[i][1];
int dist = (x * x) + (y * y);

if (dist <= distk)


System.out.println("[" + x + ", " + y + "]");
}
}

// Driver code
public static void main (String[] args)
{
int points[][] = { { 3, 3 },
{ 5, -1 },
{ -2, 4 } };

int K = 2;

pClosest(points, K);
}
}
Time Complexity: O(n log n).
Time complexity to find the distance from the origin for every point is O(n) and to
sort the array is O(n log n)
Space Complexity: O(1).
As no extra space is required.
3./*You are given an array of logs. Each log is a space-delimited string of words,
where the first word is the identifier.

There are two types of logs:

Letter-logs: All words (except the identifier) consist of lowercase English


letters.
Digit-logs: All words (except the identifier) consist of digits.
Reorder these logs so that:

The letter-logs come before all digit-logs.


The letter-logs are sorted lexicographically by their contents. If their contents
are the same, then sort them lexicographically by their identifiers.
The digit-logs maintain their relative ordering.
Return the final order of the logs.

Example 1:

Input: logs = ["dig1 8 1 5 1","let1 art can","dig2 3 6","let2 own kit dig","let3
art zero"]
Output: ["let1 art can","let3 art zero","let2 own kit dig","dig1 8 1 5 1","dig2 3
6"]
Explanation:
The letter-log contents are all different, so their ordering is "art can", "art
zero", "own kit dig".
The digit-logs have a relative order of "dig1 8 1 5 1", "dig2 3 6".
Example 2:

Input: logs = ["a1 9 2 3 1","g1 act car","zo4 4 7","ab1 off key dog","a8 act zoo"]
Output: ["g1 act car","a8 act zoo","ab1 off key dog","a1 9 2 3 1","zo4 4 7"] */

Solution:
class Solution {
public String[] reorderLogFiles(String[] logs) {
Arrays.sort(logs, (log1, log2)->{
String[] str1=log1.split(" ", 2);
String[] str2=log2.split(" ", 2);
boolean d1=Character.isDigit(str1[1].charAt(0));
boolean d2=Character.isDigit(str2[1].charAt(0));
if(!d1 && !d2) {
int c=str1[1].compareTo(str2[1]);
if(c!=0)return c;
return str1[0].compareTo(str2[0]);
}
return d1?(d2?0:1):-1;
});

return logs;
}
}

Stable Sort

One might notice that in the above implementation one can find the logic that
corresponds each of the rules, except the Rule (3).
Indeed, we did not do anything explicitly to ensure the order imposed by the Rule
(3).

The short answer is that the Rule (3) is ensured implicitly by an important
property of sorting algorithms, called stability.

It is stated as "stable sorting algorithms sort equal elements in the same order
that they appear in the input."

Not all sort algorithms are stable, e.g. merge sort is stable.

The Arrays.sort() interface that we used is stable, as one can find in the
specification.

Therefore, the Rule (3) is implicitly respected thanks to the stability of the
sorting algorithm that we used.

Complexity Analysis

Let N be the number of logs in the list and M be the maximum length of a single
log.

Time Complexity: O(M⋅N⋅logN)

First of all, the time complexity of the Arrays.sort() is O(N⋅logN), as stated in


the API specification, which is to say that the compare() function would be invoked
O(N⋅logN) times.

For each invocation of the compare() function, it could take up to O(M) time, since
we compare the contents of the logs.

Therefore, the overall time complexity of the algorithm is O(M⋅N⋅logN).

Space Complexity: O(M⋅logN)

For each invocation of the compare() function, we would need up to O(M) space to
hold the parsed logs.

In addition, since the implementation of Arrays.sort() is based on quicksort


algorithm whose space complexity is O(logn), assuming that the space for each
element is O(1). Since each log could be of O(M) space, we would need O(M⋅logN)
space to hold the intermediate values for sorting.

In total, the overall space complexity of the algorithm is O(M+M⋅logN)=O(M⋅logN).

4. /* prime air route/optimize memory usage


Give a computer with total K memory space, and an array of foreground tasks and
background tasks the computer needs to do. Write an algorithm to find a pair of
tasks from each array to maximize the memory usage. Notice the tasks could be done
without origin order.

Input
The input to the function/method consists of three arguments :
foregroundTask, an array representing the memory usage of the foreground tasks,
backgroundTask, an array representing the memory usage of the background tasks,
K, the total memory space of the computer.

Output
Return a list of pairs of the task ids.
Examples 1
Input:
foregroundTasks = [1, 7, 2, 4, 5, 6]
backgroundTasks = [3, 1, 2]
K = 6

Output:
[(3, 2), (4, 1), (5,-1)]

Explaination:
Here we have 5 foreground tasks: task 0 uses 1 memeory. task 1 uses 7 memeory. task
2 uses 2 memeory..
And 5 background tasks: task 0 uses 3 memeory. task 1 uses 1 memeory. task 2 uses 2
memeory..
We need to find two tasks with total memory usage sum <= K.
Here we can return the foreground task 3 and background task 2, which total use 6
units of memory.
Or we can return the foreground task 4 and background task 1. Also use total 6
units of memory.
Or we can return the foreground task 5 only without any background task. Also use
total 6 units of memory.*/

Solution:

import java.util.*;

public class Solution {


public List<int[]> optimizeMemoryUsage(int[] foregroundTasks, int[]
backgroundTasks, int K) {
List<int[]> result = new ArrayList<>();
if (K == 0 || (foregroundTasks.length == 0 && backgroundTasks.length == 0))
result.add(new int[]{-1, -1});

List<int[]> foregroundTaskList = new ArrayList<>();


List<int[]> backgroundTaskList = new ArrayList<>();

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


foregroundTaskList.add(new int[]{i, foregroundTasks[i]});
}

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


backgroundTaskList.add(new int[]{i, backgroundTasks[i]});
}

foregroundTaskList.sort((p1, p2) -> p1[1] - p2[1]);


backgroundTaskList.sort((p1, p2) -> p1[1] - p2[1]);

int max = Integer.MIN_VALUE;


for(int i = 0; i < foregroundTasks.length; i++){
if (foregroundTaskList.get(i)[1] == K) {
result.add(new int[]{foregroundTaskList.get(i)[0], -1});
max = foregroundTaskList.get(i)[1];
}
}

for(int i = backgroundTasks.length-1; i >= 0; i--){


if (backgroundTaskList.get(i)[1] == K) {
result.add(new int[]{-1, backgroundTaskList.get(i)[0]});
max = backgroundTaskList.get(i)[1];
}
}

if(foregroundTasks.length > 0 && backgroundTasks.length == 0){


for (int i = 0; i < foregroundTasks.length; i++) {
if (foregroundTaskList.get(i)[1] < K) {
result.add(new int[]{foregroundTaskList.get(i)[0], -1});
}
}

return result;
}

if(backgroundTasks.length > 0 && foregroundTasks.length == 0){


for (int i = backgroundTasks.length - 1; i >= 0; i--) {
if (backgroundTaskList.get(i)[1] < K) {
result.add(new int[]{-1, backgroundTaskList.get(i)[0]});
}
}

return result;
}

int i = 0;
int j = backgroundTasks.length - 1;
while (i < foregroundTasks.length && j >= 0) {
int sum = foregroundTaskList.get(i)[1] + backgroundTaskList.get(j)
[1];

if (sum > K) {
j = j - 1;
} else {
if (max <= sum) {
if (max < sum) {
max = sum;
result.clear();
}
result.add(new int[]{foregroundTaskList.get(i)[0],
backgroundTaskList.get(j)[0]});
int index = j - 1;
while (index >= 0 &&
backgroundTaskList.get(index)[1] ==
backgroundTaskList.get(index + 1)[1]) {
result.add(new int[]{foregroundTaskList.get(i)[0],
backgroundTaskList.get(index)[0]});
index--;
}
}
++i;
}
}

return result;
}
}
5. Order Delivery Route
/*You have a map that marks the location of a treasure island. Some of the map area
has jagged rocks and dangerous reefs. Other areas are safe to sail in. There are
other explorers trying to find the treasure. So you must figure out a shortest
route to the treasure island.

Assume the map area is a two dimensional grid, represented by a matrix of


characters. You must start from the top-left corner of the map and can move one
block up, down, left or right at a time. The treasure island is marked as X in a
block of the matrix. X will not be at the top-left corner. Any block with dangerous
rocks or reefs will be marked as D. You must not enter dangerous blocks. You cannot
leave the map area. Other areas O are safe to sail in. The top-left corner is
always safe. Output the minimum number of steps to get to the treasure.

Example:

Input:
[['O', 'O', 'O', 'O'],
['D', 'O', 'D', 'O'],
['O', 'O', 'O', 'O'],
['X', 'D', 'D', 'O']]

Output: 5
Explanation: Route is (0, 0), (0, 1), (1, 1), (2, 1), (2, 0), (3, 0) The minimum
route takes 5 steps.*/

Solution:

public class Main {


private static final int[][] DIRS = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}};

public static int minSteps(char[][] grid) {


Queue<Point> q = new ArrayDeque<>();
q.add(new Point(0, 0));
grid[0][0] = 'D'; // mark as visited
for (int steps = 1; !q.isEmpty(); steps++) {
for (int sz = q.size(); sz > 0; sz--) {
Point p = q.poll();

for (int[] dir : DIRS) {


int r = p.r + dir[0];
int c = p.c + dir[1];

if (isSafe(grid, r, c)) {
if (grid[r][c] == 'X') return steps;
grid[r][c] = 'D';
q.add(new Point(r, c));
}
}
}
}
return -1;
}

private static boolean isSafe(char[][] grid, int r, int c) {


return r >= 0 && r < grid.length && c >= 0 && c < grid[0].length && grid[r]
[c] != 'D';
}
private static class Point {
int r, c;
Point(int r, int c) {
this.r = r;
this.c = c;
}
}

public static void main(String[] args) {


char[][] grid = {{'O', 'O', 'O', 'O'},
{'D', 'O', 'D', 'O'},
{'O', 'O', 'O', 'O'},
{'X', 'D', 'D', 'O'}};
System.out.println(minSteps(grid));
}
}

Time Complexity= o(r*c)


Space Complexity= 0(r*c)

// ask yourself clarifying question- there could be multiple ways of reaching to


treasure location, how this algo gets shortest of all of them?
// answer- at every location, code is scanning in all 4 directions. whichever route
will reach X first, will be automatically shortest route and same would be returned
// step 1- create three loops. One for processing queue till its empty, other for
current queue size and last for scanning across directions
// step 2- First loop- creates levels. Second loop- polls items from the queue. 3rd
loop, gets new coordinates, validates & adds them to queue

6. Given n number of sorted files, the task is to find the minimum computations
done to reach Optimal Merge Pattern.

When two or more sorted files are to be merged all together to form a single file,
the minimum computations done to reach this file are known as Optimal Merge
Pattern.

If more than 2 files need to be merged then it can be done in pairs. For example,
if need to merge 4 files A, B, C, D. First Merge A with B to get X1, merge X1 with
C to get X2, merge X2 with D to get X3 as the output file.

If we have two files of sizes m and n, the total computation time will be m+n.
Here, we use greedy strategy by merging two smallest size files among all the files
present.

Examples:
Given 3 files with size 2, 3, 4 units.Find optimal way to combine these files
Input: n = 6, size = {2, 3, 4, 5, 6, 7}
Output: 68
Explanation: Optimal way to combine these files

Algorithm:
Node represents a file with a given size also given nodes are greater than 2

Add all the nodes in a priority queue (Min Heap).{node.weight = file size}
Initialize count = 0 // variable to store file computations.
Repeat while (size of priority Queue is greater than 1)
create a new node
new node = pq.poll().weight+pq.poll().weight;//pq denotes priority queue, remove
1st smallest and 2nd smallest element and add their weights to get a new node
count += node.wight
add this new node to priority queue;
count is the final answer

You might also like