Linear probing in Hashing implementation - java

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;
}

Related

Find maximum triplet in an array

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

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]).

Java cut the sticks

I am very new to Java and I was trying to solve this problem on Hackerrank:
Here's the task:
https://www.hackerrank.com/challenges/cut-the-sticks
You are given N sticks, where the length of each stick is a positive
integer. A cut operation is performed on the sticks such that all of
them are reduced by the length of the smallest stick.
Suppose we have six sticks of the following lengths:
5 4 4 2 2 8
Then, in one cut operation we make a cut of length 2 from each of the six
sticks. For the next cut operation four sticks are left (of non-zero length), > whose lengths are the following:
3 2 2 6
The above step is repeated until no sticks are left.
Given the length of N sticks, print the number of sticks that are left before > each subsequent cut operations.
Note: For each cut operation, you have to recalcuate the length of smallest
sticks (excluding zero-length sticks).
Here is my attempt at it, but it doesnt seem to be working. The output gets stuck in while loop (4 gets printed out infinitely)
import java.io.*;
import java.util.*;
public class Solution {
private static int findMin (int[] A)
{
int min = A[0];
for (int i =0; i<A.length; i++)
{
if (A[i] < min)
{
min = A[i];
}
}
return min;
}
private static int countNonZeros (int[] A)
{
int zeros = 0;
for (int i =0; i<A.length; i++)
{
if (A[i] == 0)
{
zeros++;
}
}
int nonZeros = A.length - zeros;
return nonZeros;
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
int[] A = new int[n];
for (int i=0; i<n; i++)
{
A[i] = scanner.nextInt();
}
int nums = countNonZeros(A);
while (nums > 0)
{
int mins = findMin(A);
for (int j = 0; j<A.length; j++)
{
A[j]=A[j]-mins;
}
nums = countNonZeros(A);
System.out.println(nums);
}
}
}
Any help is appreciated
(PS I know I can just look the solution up somewhere, but I want to know why my code isn't working)
The problem that you have is that your findMin is not excluding zero-length elements, so once you have a zero that will be the min, and as a result an iteration of the while loop will be the same as the previous iteration, having subtracted 0 from each of the elements of A.

Find the largest sum including at most two consecutive elements from an array

I've been playing around a bit with the algorithms for getting the largest sum with no two adjacent elements in an array but I was thinking:
If we have an array with n elements and we want to find the largest sum so that 3 elements never touch. That's to say if we have the array a = [2, 5, 3, 7, 8, 1] we can pick 2 and 5 but not 2, 5 and 3 because then we have 3 in a row. The larget sum with these rules for this array would be: 22 (2 and 5, 7 and 8. 2+5+7+8=22)
I'm not sure how I would implement this, any ideas?
Edit:
I've only come so far as to think about what might be good to do:
Let's just stick to the same array:
int[] a = {2, 5, 3, 7, 8, 1};
int{} b = new int[n}; //an array to store results in
int n = a.length;
// base case
b[1] = a[1];
// go through each element:
for(int i = 1; i < n; i++)
{
/* find each possible way of going to the next element
use Math.max to take the "better" option to store in the array b*/
}
return b[n]; // return the last (biggest) element.
This is just a thought I got in my head, hasn't reached longer than this.
Algorithm for Maximum sum such that no two elements are adjacent:
Loop for all elements in arr[] and maintain two sums incl and excl where incl = Max sum including the previous element and excl = Max sum excluding the previous element.
Max sum excluding the current element will be max(incl, excl) and max sum including the current element will be excl + current element (Note that only excl is considered because elements cannot be adjacent).
At the end of the loop return max of incl and excl.
Implementation:
#include<stdio.h>
/*Function to return max sum such that no two elements
are adjacent */
int FindMaxSum(int arr[], int n)
{
int incl = arr[0];
int excl = 0;
int excl_new;
int i;
for (i = 1; i < n; i++)
{
/* current max excluding i */
excl_new = (incl > excl)? incl: excl;
/* current max including i */
incl = excl + arr[i];
excl = excl_new;
}
/* return max of incl and excl */
return ((incl > excl)? incl : excl);
}
/* Driver program to test above function */
int main()
{
int arr[] = {5, 5, 10, 100, 10, 5};
printf("%d \n", FindMaxSum(arr, 6));
getchar();
return 0;
}
Time Complexity: O(n)
Space Complexity: O(1)
Edit 1:
If you understand the above code, we can easily do this problem by maintaining the count of already adjacent numbers for previous position.
Here is a working implementation to the required question
//We could assume we store optimal result upto i in array sum
//but we need only sum[i-3] to sum[i-1] to calculate sum[i]
//so in this code, I have instead maintained 3 ints
//So that space complexity to O(1) remains
#include<stdio.h>
int max(int a,int b)
{
if(a>b)
return 1;
else
return 0;
}
/*Function to return max sum such that no three elements
are adjacent */
int FindMaxSum(int arr[], int n)
{
int a1 = arr[0]+arr[1];//equivalent to sum[i-1]
int a2 =arr[0];//equivalent to sum[i-2]
int a3 = 0;//equivalent to sum [i-3]
int count=2;
int crr = 0;//current maximum, equivalent to sum[i]
int i;
int temp;
for (i = 2; i < n; i++)
{
if(count==2)//two elements were consecutive for sum[i-1]
{
temp=max(a2+arr[i],a1);
if(temp==1)
{
crr= a2+arr[i];
count = 1;
}
else
{
crr=a1;
count = 0;
}
//below is the case if we sould have rejected arr[i-2]
// to include arr[i-1],arr[i]
if(crr<(a3+arr[i-1]+arr[i]))
{
count=2;
crr=a3+arr[i-1]+arr[i];
}
}
else//case when we have count<2, obviously add the number
{
crr=a1+arr[i];
count++;
}
a3=a2;
a2=a1;
a1=crr;
}
return crr;
}
/* Driver program to test above function */
int main()
{
int arr[] = {2, 5, 3, 7, 8, 1};
printf("%d \n", FindMaxSum(arr, 6));
return 0;
}
Time Complexity: O(n)
Space Complexity: O(1)
adi's solution can be easily generalized to allow up to n adjacent elements to be included in the sum. The trick is to maintain an array of n + 1 elements, where the k-th element in the array (0 ≤ k ≤ n) gives the maximum sum assuming that the k previous inputs are included in the sum and the k+1-th isn't:
/**
* Find maximum sum of elements in the input array, with at most n adjacent
* elements included in the sum.
*/
public static int maxSum (int input[], int n) {
int sums[] = new int[n+1]; // new int[] fills the array with zeros
int max = 0;
for (int x: input) {
int newMax = max;
// update sums[k] for k > 0 by adding x to the old sums[k-1]
// (loop from top down to avoid overwriting sums[k-1] too soon)
for (int k = n; k > 0; k--) {
sums[k] = sums[k-1] + x;
if (sums[k] > newMax) newMax = sums[k];
}
sums[0] = max; // update sums[0] to best sum possible if x is excluded
max = newMax; // update maximum sum possible so far
}
return max;
}
Like adi's solution, this one also runs in linear time (to be exact, O(mn), where m is the length of the input and n is the maximum number of adjacent elements allowed in the sum) and uses a constant amount of memory independent of the input length (O(n)). In fact, it could even be easily modified to process input streams whose length is not known in advance.
I would imagine putting the array into a binary tree in that order. That way you can keep track of which element is next to each other. Then just simply do an if (node is not directly linked to each other) to sum the nodes which are not next to each other. You can potentially do it with recursion and return the maximum number, makes things easier to code. Hope it helps.
For a set with n entries, there are 2^n ways to partition it. So to generate all possible sets, just loop from 0:2^n-1 and pick the elements from the array with those entries set to 1 (bear with me; I'm getting to your question):
max = 0;
for (i = 0; i < 1<<n; ++i) {
sum = 0;
for (j = 0; j < n; ++j) {
if (i & (1<<j)) { sum += array[j]; }
}
if (sum > max) { /* store max and store i */ }
}
This will find the maximum way to sum the entries of an array. Now, the issue you want is that you don't want to allow all values of i - specifically those that contain 3 consecutive 1's. This can be done by testing if the number 7 (b111) is available at any bit-shift:
for (i = 0; i < 1<<n; ++i) {
for (j = 0; j < n-2; ++j) {
if ((i & (7 << j)) == (7 << j)) { /* skip this i */ }
}
...

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