Find maximum triplet in an array - java

I have an array of numbers [1,2,6,4,105,111,1024] I want to check all possible triplets a,b,c such that b%a ==0 and c%b ==0. For such triplets get the middle element b. Now I want to return the maximum possible b for such triplets.
For this array the valid triplets are :
indices:
(0,1,2) = middle item = 2
(0,1,3) = middle item = 2
(0,1,6) = middle item = 2
(0,3,6) = middle item = 4
(1,3,6) = middle item = 4
So the maximum value is 4 is the answer.
Here is my code:
int process(List<Integer> list) {
int n = list.size();
int max = -1;
for(int i=0; i<n-2; i++) {
int a = list.get(i);
boolean valid = true;
for(int j=i+1; j<n-1; j++) {
int b = list.get(j);
valid = b % a == 0;
for(int k=j+1; valid && k<n; k++) {
int c = list.get(k);
if(c % b ==0) {
max = Math.max(max, b);
}
}
}
return max;
}
How to reduce the time complexity for this code.
constraints:
size of the input list is 1 to 10^5.
Each element in the list is also 1 to 10^5
Repetitions are allowed for input elements.

c % b = 0 and b % a = 0 means a is the lowest factor OR a possible GCD of both b and c. However, since we need to find the maximum greatest value of the middle element, we will take a different route.
We put all the elements of the array in the hashMap with a boolean falsy value by default.
For each element in arr, we check with all it's factors by iterating till square root of this number.
If any of the factor exists already in the map, we perform one more check as to whether this factor has a factor of it's own present in the array. This way, the current factor at hand makes it the middle element of the triplet.
We keep taking maximum of those and return the answer. We return -1 if no such triplet exists.
Snippet:
import java.util.*;
public class Main {
public static void main(String[] args) {
int[] arr = { 1,2,6,4,105,111,1024};
System.out.println(solve(arr));
}
private static int solve(int[] arr){
Map<Integer,Boolean> map = new HashMap<>();
int max = -1;
for(int i = 0 ; i < arr.length; ++i){
boolean factorExists = false;
for(int j = 1; j * j <= arr[i]; ++j){
if(arr[i] % j == 0 && map.getOrDefault(j, false)){
max = Math.max(max, j);
}
int cousin = arr[i] / j;
if(arr[i] % j == 0 && arr[i] % cousin == 0 && map.getOrDefault(cousin, false)){
max = Math.max(max, cousin);
}
factorExists = factorExists || arr[i] % j == 0 && map.containsKey(j) || arr[i] % j == 0 && arr[i] % cousin == 0 && map.containsKey(cousin);
}
map.putIfAbsent(arr[i], false);
map.put(arr[i], map.get(arr[i]) || factorExists);
}
return max;
}
}
Online Demo
Time Complexity: O(n1.5) since we walk through till square root of each element.
Space Complexity: O(n) since we store all the elements of the array in the map.

Here is a more efficient approach based on what #nice_dev already did. The improvement is to create a table of factors instead of checking up to the square root of each number.
If you have n numbers of size at most m, this approach is O((n+m) log(m)).
def find_max_mid(numbers):
# Find all potential factors.
max_n = max(numbers)
factors = {}
saw_n = set()
for n in numbers:
if n not in saw_n:
for m in range(n, max_n+1, n):
if m in factors:
factors[m].append(n)
else:
factors[m] = [n]
saw_n.add(n)
max_mid = -1
has_factor = set()
saw_n = set() # Reset
for n in numbers:
for f in factors[n]:
if f in saw_n:
if max_mid < f and f in has_factor:
max_mid = f
has_factor.add(n)
saw_n.add(n)
return max_mid
print(find_max_mid([1,2,6,4,105,111,1024]))
print(find_max_mid([3,9,27,32,64]))
print(find_max_mid([1,2,3]))
print(find_max_mid(list(range(1, 100000))))

Instead of using multiple for loops use single for loop and a HashMap to keep the modulo results for each position and with that you can do the same thing with O(n) time complexity

Related

Linear probing in Hashing implementation

I am trying to solve this problem where I need to implement Linear Probing.
Given an array of integers and a hash table size. Fill the array elements into a hash table using Linear Probing to handle collisions.
Example 1:
Input:
hashSize = 10
sizeOfArray = 4
Array[] = {4,14,24,44}
Output:
-1 -1 -1 -1 4 14 24 44 -1 -1
Example 2:
Input:
hashSize = 10
sizeOfArray = 4
Array[] = {9,99,999,9999}
Output:
99 999 9999 -1 -1 -1 -1 -1 -1 9
Your Task:
You don't need to read input or print anything.
Your task is to complete the function linearProbing() which takes as input a empty hash table (hash), the hash table size (hashSize), an integers array arr[] and its size N and inserts all the elements of the array arr[] into the given hash table.
The empty cells of the hash table are to be given a value of -1. Also, if there's no more space to insert a new element, just drop that element.
Expected Time Complexity: O(N).
Expected Auxiliary Space: O(1).
Constraints:
1 <= hashSize <= 100
1 <= sizeOfArray <= 100
0 <= Array[] <= 105
The code I wrote is:
static int[] linearProbing(int hash_size, int arr[], int N) {
int[] a = new int[hash_size];
for(int i = 0; i < hash_size; i++)
a[i] = -1;
for(int i = 0; i < N; i++) {
int probe = arr[i] % hash_size;
int offset = 1;
while(a[probe] != -1) {
probe = (probe + offset) % hash_size;
}
a[probe] = arr[i];
}
return a;
}
The given testcases are running. But when submitting I am getting TLE. Please help.
The driver code is given as follows =
https://i.stack.imgur.com/ULVdd.png
You missed out one single point, when the array size is bigger than the hash table, just skip the rest.
This could also be the simple point, Just replace N with hash_size and iterate. This would let you only iterate as long as arr contains elements
static int[] linearProbing(int hash_size, int arr[], int N) {
//This is what was missing from your code
int iterating_size = N>hash_size? hash_size : N;
int[] a = new int[hash_size];
for(int i = 0; i < hash_size; i++)
a[i] = -1;
int started = -1;
for(int i = 0; i < iterating_size ; i++) {
int probe = arr[i] % hash_size;
int offset = 1;
while(a[probe] != -1) {
probe = (probe + offset) % hash_size;
}
a[probe] = arr[i];
}
return a;
}

Sorting 2 Integer array list in alternating while descending order

Im trying to combine 2 arrays into in alternating order and sorted imagine a pyramid with alternating colors(you can't have the same color it has to interchange) and the value inside is the width.
Example
WhiteA{18,16,11,4,3,2}
BlackB{13,8,6}
Output should be
{18,13,11,8,4}
16 was skipped because 16>13 so the next is 11 and 6 was omitted because the the last one would have a double color
for (int i = 0; i < positive.size(); i++) {
for (int n = 0; n < negative.size(); n++) {
if (positive.get(i) > Math.abs(negative.get(n))) {
count.add(positive.get(i));
if (positive.get(i) < Math.abs(negative.get(n))) {
count.add(negative.get(n));
}
}
}
}
Positive just means white
Negative just means black
I expect the output should be {18,13,11,8,4} but when i try my code i get {18,18,18,16,16,16,11,11}
I'd try changing your loop type and alternating which array you check through a switch (e.g. i % 2), comparing the first element of the positive/negative array against the last element in the count array.
After comparing: add the value to the count array if it is lower, and then remove the element from the positive/negative array.
Sorry: I'm not at a computer to test it.
int ai = 0;
int bi = 0;
List<Integer> a = Arrays.asList(18,16,11,4,3,2); // this is your first list
List<Integer> b = Arrays.asList(13,8,6); // this is your second list
List<Integer> count = new ArrayList<>();
while (ai < a.size() && bi < b.size()) {
int current = a.get(ai);
count.add(current);
while (bi < b.size() && b.get(bi) > current) {
++bi;
}
if (bi == b.size()) {
break;
}
current = b.get(bi);
count.add(current);
while (ai < a.size() && a.get(ai) > current) {
++ai;
}
if (ai == a.size()) {
break;
}
}
It looks like the issue is with how you're using nested loops, inside the negative loop you're always comparing it to the same value of the positive loop, it doesn't increment until after the negative loop has run through all elements, thus the repeated numbers.
Additionally the check if positive is less than negative occurs inside the check that positive is greater than negative, so it'll never trigger.
It's been a while since I've worked with java and I don't have the tools to test it in that environment but here's some code which seems to do the trick in python:
count = []
positive = [18, 16, 11, 4, 3, 2]
negative = [13, 10, 6]
lastGrabPos = False
positiveIndex = 0
negativeIndex = 0
while positiveIndex < len(positive) and negativeIndex < len(negative):
if positive[positiveIndex] > negative[negativeIndex]:
if not lastGrabPos:
count.append(positive[positiveIndex])
lastGrabPos = True
positiveIndex += 1
if positive[positiveIndex] < negative[negativeIndex]:
if lastGrabPos:
count.append(negative[negativeIndex])
lastGrabPos = False
negativeIndex += 1
if not lastGrabPos:
count.append(positive[positiveIndex])
else:
count.append(negative[negativeIndex])
Translated to java I believe is...
int positiveIndex = 0;
int negativeIndex = 0;
Boolean lastGrabPos = false;
while(positiveIndex < positive.size() && negativeIndex < negative.size()) {
if (positive.get(positiveIndex) > Math.abs(negative.get(negativeIndex))){
if(!lastGrabPos){
count.add(positive.get(positiveIndex));
lastGrabPos = true;
}
positiveIndex += 1;
}
if (positive.get(positiveIndex) < Math.abs(negative.get(negativeIndex))){
if(lastGrabPos){
count.add(negative.get(negativeIndex));
lastGrabPos = false;
}
negativeIndex += 1;
}
}
if(!lastGrabPos){
count.add(positive.get(positiveIndex));
}
else{
count.add(negative.get(negativeIndex));
}
for(Integer element : count) {
System.out.println(element);
}

Calculate the largest best combination of denominations for a number

Problem Statement:
I need to get the best combination of denomination for a given number.
Example: I have three denominations {50,25,10} and given number is 30 then list should return <10,10,10>. for number 80 it should return <50,10,10,10> as remaining 30 is not completely divide by 25.
For 35 it should return <25,10>
for 75 <50,25>
for 65 <50,10>
This is somewhat similar to coin problem but I am not able to get the values of denominations.
Refence StackOverFlow Coin change DP solution to keep track of coins
Here is what I have tried so far :
public static int[] minChange(int[] denom, int changeAmount) {
int n = denom.length;
int[] count = new int[changeAmount + 1];
int[] from = new int[changeAmount + 1];
count[0] = 1;
for (int i = 0; i < changeAmount; i++ )
if (count[i] > 0)
for (int j = 0; j < n; j++ ) {
int p = i + denom[j];
if (p <= changeAmount) {
if (count[p] == 0 || count[p] > count[i] + 1) {
count[p] = count[i] + 1;
from[p] = j;
}
}
}
// No solutions:
if (count[changeAmount] == 0)
return null;
// Build answer.
int[] result = new int[count[changeAmount] - 1];
int k = changeAmount;
while (k > 0) {
result[count[k] - 2] = denom[from[k]];
k = k - denom[from[k]];
}
return result;
}
This works well if value are completely divisible by one of denomination other wise i doesn't work at all.
Once you have the solution in the 2D array for the dynamic programming solution, you can find out what denominations were optimal by backtracking through your array from the end (arr[n][n]).

I am stuck at implementing Radix sort recursively

I'm required to implement a programm that sorts numbers ranging from 0 to 99999 recursively (this is basically Radix sort). The process itself is kinda simpel: The user types in an array that contains those numbers in the main method. Then, the main method calls for the sort-method where I create a two-dimensional array named 'space' with 10 rows and 1 column. Then, I divide every number in the array by the digit, which would be 10.000 in the first run. So, for example, 23456 / 10000 = 2,3456 = 2 (in java), hence, the programm puts this number in space[2][0], so in the second row. Then, we take this entire row and extend it, which is done in the putInBucket-method. We do this in order to make sure that we can put another number into the same row.
We do this for every number that is inside the 'numbers'-array. Then, we want to work with these rows and sort them again by the same principle, but now we take a look at the second digit. We want to do this from left to right, not from right to left. So, if our second row would look like this
[23456, 24567],
we'd want to compare the 3 and the 4, which leads to 23456 < 24567.
We do this with the help of the recursive call at the end of the sort method. Now, this is where I am lost. I simply don't know how to manipulate the digit-variable in order to be able to work with the second, third, ... digit of each number. In the first run, as you see, this can be simply done by dividing through 10.000, but I didn't find a way to go further from here.
Please note: Yes, this is a homework question, hence, I'm only allowed to use primitives here. We didn't go through stuff like math.pow(...) yet. Thanks in advance!
public static int[] sort(int[] numbers, int digit) {
if (numbers.length == 0)
return numbers;
int[][]space = new int[10][1];
int i, j = 0;
for (j = 0; j < numbers.length; j++) {
i = numbers[j] / digit;
space[i][0] = numbers[j];
space[i] = putInBucket(space[i], numbers[j]);
}
for (i = 0; i < space[i].length; i++) {
sort(space[i], digit); //not sure how to work with digit here
}
return ... //not sure what to return here
}
private static int[] putInBucket(int[] bucket, int number) {
int[] bucket_new = new int[bucket.length+1];
for (int i = 1; i < bucket_new.length; i++) {
bucket_new[i] = bucket[i-1];
}
return bucket_new;
}
public static void main (String [] argv) {
int[] numbers = IO.readInts("Numbers: ");
int digit = 10000;
int[] bucket = sort(numbers, digit);
}
To extract the last digit, the remainder operator % is your friend:
123 % 10 == 3
if you haven't covered the % operator yet, you can use
123 % 10 == 123 - (123 / 10 * 10) == 3
To extract another digit, you can first move it to the end with /:
123 / 10 == 12
12 % 10 == 2
You can therefore extract an arbitrary digit using
(number / mask) % 10
where mask ∈ {..., 10000, 1000, 100, 10, 1}.
Extra credit
Radix sort is usually implemented in the binary number system instead because a binary digit (or a sequence thereof) can be extracted without performing a division, which is more efficient:
x % 16 == x & 15;
x \ 16 == x >> 4;
Also, if you are implementing this for real, you'd need a more efficient way to grow buckets (your implementation takes O(n) to add a single element to the bucket, adding n elements to the bucket therefore takes O(n^2), which makes your radix sort slower than insertion sort). Dynamic arrays are usually implemented with a more efficient geometric expansion.
This should work:
public static int[] sort(int[] numbers, int digit) {
if (numbers.length == 0 || digit <= 0)
return numbers;
int[][]space = new int[10][10];
int[] len = new int[10];
int i, j = 0;
for (j = 0; j < numbers.length; j++) {
i = (numbers[j] / digit) % 10;
len[i]++;
for (int k = len[i] - 1; k > 0; k--) {
space[i][k] = space[i][k - 1];
}
space[i][0] = numbers[j];
}
for (i = 0; i < 10; i++) {
int[] bucket = new int[len[i]];
for (int k = 0; k < len[i]; k++)
bucket[k] = space[i][k];
space[i] = sort(bucket, digit / 10);
}
int k = 0;
for (i = 0; i < 10; i++) {
for (j = 0; j < len[i]; j++) {
numbers[k] = space[i][j];
k++;
}
}
return numbers;
}
a) Firstly, space is allocated as having only one column. So, space[i] = bucket will not work.
Instead, you could declare it as int[10][10]. (Note: it will only support max of 10 values in one bucket). Or you may allocate new arrays programmatically. Or of course, a List might be better suited.
b) i = (numbers[j] / digit) % 10;
To get the required digit only. For eg: if the number is 12130, and digit = 1000, we want to set i to 2, not 12.
c) putInBucket replaced with an in-place loop.
d) For each bucket of space, we sort it by one digit lower by calling sort recursively.
e) Finally, the result to be returned (numbers), can be created by looping through space from digit 0 to 9.
Note:
This solution could probably be made better.

Perfect shuffle algorithm implementation error

Is this code correct for perfect shuffle algorithm ? I'm always trying to generate a number from 0 to n and swapping the number with the last element in the array thereby reducing the range of n. However when the n=0, I get an exception. How do I deal with this case ?
int [] array ={1,2,3,4,5};
Random random = new Random();
int n=array.length;
while(n--!=0)
{
int number = random.nextInt(n);
int temp = array[n];
array[n] = array[number];
array[number] = temp;
}
EDIT: if I change it to --n >0 then it works correctly but am I implementing the shuffling algorithm correctly in that case because I never do anything for n=0 ?
In your code segment
while(n--!=0)
if n is 1, it will become 0 and `random.nextInt(0)` will return an error.
Refer this link
I don't think nextInt works if you pass an argument of 0.
The best way to shuffle is by using the Fisher Yates algorithm. It's fast, works in-place, and is unbiased:
int [] array = {1,2,3,4,5};
Shuffle(array, new Random());
// Fisher Yates shuffle - see http://en.wikipedia.org/wiki/Fisher-Yates_shuffle
void Shuffle(int[] array, Random RNG)
{
for (int i = array.length - 1; i >= 1; i -= 1)
{
// get integer in range of j >= 0 && j < i + 1
int j = RNG.nextInt(i + 1);
//assert(j >= 0 && j <= i);
if (i != j)
{
// only swap if i and j are different
int temp = array[i];
array[i] = array[j];
array[j] = temp;
}
}
}

Categories