Generate a sequence of all permutation of some range of numbers - java

The following algorithm is given and we are supposed to write it out in java. However, when I try to understand line by line, it gets confusing, especially the part:
A[k+1:N-1] = the values in S in ascending order
To my understand, the set only have 1 number at anytime. How can we replace A[k+1:N-1] when the set only has 1 number?
Let A be a sequence of integers 0 to N-1 in ascending order (let's assume its an array of int[N]).
next_permutation(A):
k = N-1
S = { }
while k >= 0:
if S contains a value larger than A[k]:
v = the smallest member of S that is larger than A[k]
remove v from S
insert A[k] in S
A[k] = v
A[k+1:N-1] = the values in S in ascending order.
return true
else:
insert A[k] in S
k -= 1
return false

The algorithm shown is similar to the Generation in lexicographic order. You can read the article for further information.
#templatetypedef Any clue on how I can replace items in an array by values in a set in ascending order? e.g. A[k+1:N-1] = the values in S in ascending order. Should I use toArray()?
This is not needed. You can try to keep the S array sorted all the time. Every time you want to insert a new number in the array, you insert it in such, so the array could stay sorted.
For example, if you have S = [5 7 8] so far and you want to insert 6, you inserted between 5 and 7 - S = [5 6 7 8]. This way the replacement step is just copying the elements from S to A[k+1:N-1].

Related

Minimum absolute difference of a set of numbers

I am given a number set of size n, and a list of Q inputs. Each input will either remove or add a number to this set. After each input, I am supposed to output the minimum absolute difference of the set of numbers.
Constraints:
2 <= N <= 10^6
1 <= Q <= 10^6
-10^9 <= set[i] <= 10^9
Example:
input:
set = [2, 4, 7]
ADD 6
REMOVE 7
REMOVE 4
ADD 2
output:
1
2
4
0
I am tasked to solve this using an algorithm of time complexity O((N+Q)log(N+Q)) or better.
My current implementation is not fast enough, but it is as follows:
TreeSet<Integer> tree = new TreeSet<>();
HashMap<Integer, Integer> numberFreq = new HashMap<>();
int dupeCount = 0;
for (int i : set) {
tree.add(i);
if (numberFreq.get(i) > 0) dupeCount++;
numberFreq.put(i, numberFreq.getOrDefault(i, 0) + 1);
}
void add(int i) {
if (numberFreq.get(i) > 0) dupeCount++;
numberFreq.put(i, numberFreq.getOrDefault(i, 0) + 1);
tree.add(i); // if duplicate nothing gets added anyway
if (dupeCount > 0) Console.write(0);
else {
int smallestBall = ballTree.first();
int absDiff;
int maxAbsDiff = Integer.MAX_VALUE;
while (ballTree.higher(smallestBall) != null) {
absDiff = Math.abs(smallestBall - ballTree.higher(smallestBall));
maxAbsDiff = Math.min(absDiff, maxAbsDiff);
smallestBall = ballTree.higher(smallestBall);
}
Console.write(maxAbsDiff);
}
}
void remove(int i) {
if (numberFreq.get(i) > 0) dupeCount--;
else tree.remove(i);
numberFreq.put(i, numberFreq.get(i) - 1);
if (dupeCount > 0) Console.write(0);
else {
int smallestBall = ballTree.first();
int absDiff;
int maxAbsDiff = Integer.MAX_VALUE;
while (ballTree.higher(smallestBall) != null) {
absDiff = Math.abs(smallestBall - ballTree.higher(smallestBall));
maxAbsDiff = Math.min(absDiff, maxAbsDiff);
smallestBall = ballTree.higher(smallestBall);
}
Console.write(maxAbsDiff);
}
}
I've tried at it for 2 days now and I'm quite lost.
Here's one algorithm that should work (though I don't know if this is the intended algorithm):
Sort the list of numbers L (if not already sorted): L = [2, 4, 7]
Build a corresponding list D of "sorted adjacent absolute differences" (i.e., the differences between adjacent pairs in the sorted list, sorted themselves in ascending order): D = [2, 3]
For each operation... Suppose the operation is ADD 6, as an example. a) insert the number (6) into L in the correct (sorted) location: L = [2, 4, 6, 7]; b) based on where you inserted it, determine the corresponding adjacent absolute difference that is now obsolete and remove it from D (in this case, the difference 7-4=3 is no longer relevant and can be removed, since 4 and 7 are no longer adjacent with 6 separating them): D = [2]; c) Add in the two new adjacent absolute differences to the correct (sorted) locations (in this case, 6-4=2 and 7-6=1): D = [1, 2, 2]; d) print out the first element of D
If you encounter a remove operation in step 3, the logic is similar but slightly different. You'd find and remove the element from L, remove the two adjacent differences from D that have been made irrelevant by the remove operation, add the new relevant adjacent difference to D, and print the first element of D.
The proof of correctness is straightforward. The minimum adjacent absolute difference will definitely also be the minimum absolute difference, because the absolute difference between two non-adjacent numbers will always be greater than or equal to the absolute difference between two adjacent numbers which lie "between them" in sorted order. This algorithm outputs the minimum adjacent absolute difference after each operation.
You have a few options for the sorted list data structures. But since you want to be able to quickly insert, remove, and read ordered data, I'd suggest something like a self-balancing binary tree. Suppose we use an AVL tree.
Step 1 is O(N log(N)). If the input is an array or something, you could just build an AVL tree; insertion in an AVL tree is log(N), and you have to do it N times to build the tree.
Step 2 is O(N log(N)); you just have to iterate over the AVL tree for L in ascending order, computing adjacent differences as you go, and insert each difference into a new AVL tree for D (again, N insertions each with log(N) complexity).
For a single operation, steps 3a), 3b), 3c), and 3d) are all O(log(N+Q)), since they each involve inserting, deleting, or reading one or two elements from an AVL tree of size < N+Q. So for a single operation, step 3 is O(log(N+Q)). Step 3 repeats this across Q operations, giving you O(Q log(N+Q)).
So the final algorithmic runtime complexity is O(N log(N)) + O(Q log(N+Q)), which is less than O((N+Q) log(N+Q)).
Edit:
I just realized that the "list of numbers" (L) is actually a set (at least, it is according to the question title, but that might be misleading). Sets don't allow for duplicates. But that's fine either way; whenever inserting, just check if it's a duplicate (after determining where to insert it). If it's a duplicate, the whole operation becomes a no-op. This doesn't change the complexity. Though I suppose that's what a TreeSet does anyways.

Why HashMap is not good for a big dataset of integer keys?

I've a non-empty array A consisting of N integers is given. The array contains an odd number of elements, and each element of the array can be paired with another element that has the same value, except for one element that is left unpaired.
For example, in array A such that below:
A[0] = 9 , A[1] = 3 , A[2] = 9 , A[3] = 3 , A[4] = 9 , A[5] = 7 , A[6] = 9
I need to write a functon that returns the value of the unpaired element.
One of my first native solutions was to create a hashmap structure with unique keys - N integers of given array and iterate through the array adding values if the key is already exists in the hashmap. After all the key that has only 1 at it's value field is the unpaired element.
I know that the hashcode of Integer is it's int unique value...
So I soposed that there will not be a duplicate keys of different Integers..So I supposed that there will not be a duplicate keys for different Integers..But for a big sets of data this solution does not work...I think this has something to do with load factor.
But I can't get on it. I don't need an alterntive solution, becouse I have it already, I just want to understand what's wrong with hashmap when we use a big sets of integer keys..
Here is my code and thank you very much!:
Map a = new HashMap();
for(int i=0;i<A.length;i++) {
if(a.containsKey(A[i])){
a.put(A[i], a.get(A[i])+1);
}else a.put(A[i], 1);
}
for (Integer i : a.keySet()) {
if(a.get(i)==1)
return i;
}
return -1;
enter image description here
I think this has something to do with load factor.
No, the problem is not in the HashMap, it's in the way you are using it.
Your solution is not complete because it assumes all the pairs are unique. i.e. it assumes there can be at most one pair of 9 (which is not true in the example you posted, which contains 2 pairs of 9).
Having multiple identical pairs will not necessarily result in a wrong answer, but what
if, for example, there are 3 9's, two of them are paired, but the 3rd is not? Your solution won't find it, since a.get(9) would return 3, but you check if it's equal to 1.
Instead of checking
if(a.get(i)==1)
you should check if it's odd
if(a.get(i)%2==1)

Longest sequence of numbers

I was recently asked this question in an interview for which i could give an O(nlogn) solution, but couldn't find a logic for O(n) . Can someone help me with O(n) solution?
In an array find the length of longest sequence of numbers
Example :
Input : 2 4 6 7 3 1
Output: 4 (because 1,2,3,4 is a sequence even though they are not in consecutive positions)
The solution should also be realistic in terms of space consumed . i.e the solution should be realistic even with an array of 1 billion numbers
For non-consecutive numbers you needs a means of sorting them in O(n). In this case you can use BitSet.
int[] ints = {2, 4, 6, 7, 3, 1};
BitSet bs = new BitSet();
IntStream.of(ints).forEach(bs::set);
// you can search for the longer consecutive sequence.
int last = 0, max = 0;
do {
int set = bs.nextSetBit(last);
int clear = bs.nextClearBit(set + 1);
int len = clear - set;
if (len > max)
max = len;
last = clear;
} while (last > 0);
System.out.println(max);
Traverse the array once and build the hash map whose key is a number from the input array and value is a boolean variable indicating whether the element has been processed or not (initially all are false). Traverse once more and do the following: when you check number a, put value true for that element in the hash map and immediately check the hash map for the existence of the elements a-1 and a+1. If found, denote their values in the hash map as true and proceed checking their neighbors, incrementing the length of the current contigous subsequence. Stop when there are no neighbors, and update longest length. Move forward in the array and continue checking unprocessed elements. It is not obvious at the first glance that this solution is O(n), but there are only two array traversals and hash map ensures that every element of the input is processed only once.
Main lesson - if you have to reduce time complexity, it is often neccesary to use additional space.

Create all possible ways of putting n users into k groups

Given n users (u_1, u_2,..., u_n) and k groups (g_1, g_2, ..., g_k), create all possible combinations of all groups. basically, in the end, each combination is a Map<Integer,Integer>, where the first Integer is user ID, and the second Integer is group ID.For example, [(u_1,g_1), (u_2,g_1)....,(u_n, g_1)] is one possible combination.
There will be k^n combinations.
I searched and saw similar problems, but they do have some extra conditions that do not apply for my problem. In my case, there is no limit in each group, and there is no evenness or uniform distribution.
Can you suggest a quick way to do this in Java?
Thanks
My tries so far:
I tried to create a for loop for each possibility for each user, but I face the problem that I cannot define the number of for loops.
So I switched to recursion, but stuck at creating parameters for inside calls to the functions. Still working on it though.
Please, also note that this is not "n choose k". "n choose k" is when all users are identical, but here users are obviously not identical.
OK. I created a solution for this. Basically, it's a dynamic programming problem. Assume you have created a List of Maps (combinations) for j users and k locations. TO create for j+1 users and k locations, need 2 loop: for each Map, for each i=1 to k, Map.put(user_j+1, k)). Is is both recursive and iterative. Recursive because you need to pass the old maps to the new iterations. That's it.
The traditional solution to these kinds of problems is using recursion: If there are n = 0 users the only grouping possible is the empty group. Otherwise, take out the first user and generate the solution for the other n-1 users. Using the solution for the subproblem, generate the final solutions by assigning the first user to each of the k possible groups.
In code:
import java.util.*;
class Grouping {
public static void main(String[] args) {
List<?> groups = grouping(Arrays.asList(1,2,3), Arrays.asList(4,5,6,7));
System.out.println(groups.size());
System.out.println(groups);
}
static List<Map<Integer,Integer>> grouping(List<Integer> users, List<Integer> groups) {
if (users.isEmpty()) {
Map<Integer,Integer> empty = Collections.emptyMap();
return Collections.singletonList(empty);
} else {
Integer user = users.get(0);
List<Map<Integer,Integer>> subs = grouping(users.subList(1,users.size()), groups);
List<Map<Integer,Integer>> solutions = new ArrayList<>();
for (Integer group: groups) {
for (Map<Integer,Integer> sub : subs) {
Map<Integer,Integer> m = new HashMap<>(sub);
m.put(user, group);
solutions.add(m);
}
}
return solutions;
}
}
}
Ok, here is simple idea.
Lets first assume that each user_id is in {0, ... n-1}, and group_id is in {0, ... k-1}, we can map this numbers back to real ids later.
Now, what you basically want to do is to iterate thru all n-digit numbers in Base k numeral system, i.e. where each digit 0 <= base < k.
So, you start with number is 0000...00 (n-zeroes) and you end with kkkk....kk (n digits of nominal k). For each such number the position indicates user_id and digit value is this user's group_id.
So, the main workhorse you need to implement is the class Combination representing such n-digits sequence(try ArrayList or simple int[] array), with increment() operation implemented correctly (I imagine recursion is the best way to do this implementation). May be you could also have method isMaxReached() to check if all digits are of value k.
Then you would have a single loop :
Combination combination = new Combination(); // initialized with n -zeroes
while (!combination.isMaxReached()) {
combination.increment();
}
Please let me know if you would need more details on implementation.
Hope that helps.
It looks like we have the following:
n different numbers (users)
k sets (groups)
Objective is:
Find all the k-tuples with k sets S_k, such that for all i,j in 1..k the pairwise intersection of S_i and S_j is empty and the union S_1 .. S_k is the set 1..n
If this is what you want, then I would attack this recursively:
If n is 0, then the result is 1 k-tuple of empty sets.
If n is 1, then the results are k tuples, where for all elements S_j with j = 1..k it is the empty set except for the j-th element that is set {1}.
If n is m, then compute the list of tuples for m-1. Then replicate the list k times, and let the i-th set be the union of the i-th set and {n}. (Note that this is just a more general form of the previous rule for n=1).
Example:
n = 3, k = 2
n = 2, k = 2
n = 1, k = 2
n = 0, k= 2
result: [({},{})]
result: [({1},{}), ({},{1})]
result: [({1,2},{}), ({2},{1}), // j=1, union 1st with {2}
({1},{2}), ({},{1,2})] // j=2, union 2nd with {2}
result: [
({1,2,3},{}), ({2,3},{1}), ({1,3},{2}), ({3},{1,2}), // j=1, union 1st with {3}
({1,2},{3}), ({2},{1,3}), ({1},{2,3}), ({},{1,2,3}) // j=2, union 2nd with {3}
]
So u want maps like k1,n1, k1,nN .. kN,nN..
You will need 2 loops
Start by looping the groups . In each group, loop over all the users... and in the second loop , put(group,user) in a hashmap...
Code using the above algorithm.

Looking for a hint (not the answer) on how to return the longest acsending non contiguous substring when I already have the length

My code currently returns the length of the largest substring:
for(int i = 1; i<=l-1;i++)
{
counter = 1;
for(int j = 0; j<i;j++)
{
if(seq[j]<seq[j+1])
{
count[j] = counter++;
}
}
}
for(int i = 0;i<l-1;i++)
{
if(largest < count[i+1])
{
largest = count[i+1];
}
}
assuming seq is the numbers in the sequence. So if the sequence is: 5;3;4;8;6;7, it prints out 4. However, I would like it to also print out 3;4;6;7 which is the longest subsisting in ascending order.
I am trying to get the length of the largest sub sequence itself and the actual sequence, but I already have length..
My instinct is to store each number in the array, while it is working out the count, with the count. So returning the longest count, can also return the array attatched to it. I think this can be done with hashtables, but I'm not sure how to use those.
I am just looking for a hint, not the answer.
Thanks
You need to implement a dynamic programming algorithm for the longest ascending subsequence. The idea is to store a pair of values for each position i:
The length of the longest ascending subsequence that ends at position i
The index of the item preceding the current one in such ascending subsequence, or -1 if all prior numbers are greater than or equal to the current one.
You can easily build both these arrays by setting the first pair to {Length=1, Prior=-1}, walking the array in ascending order, and looking for the "best" predecessor for the current item at index i. The predecessor must fit these two conditions:
It must have lower index and be smaller than the item at i, and
It must end an ascending subsequence of length greater than the one that you have found so far.
Here is how the data would look for your sequence:
Index: 0 1 2 3 4 5
Value: 5 3 4 8 6 7
------------ ----------------
Length: 1 1 2 3 3 4
Predecessor: -1 -1 1 2 2 4
Once you finish the run, find the max value among lengths array, and chain it back to the beginning using the predecessor's indexes until you hit -1.

Categories