Natural Join of two dimensional Arrays - java

I'm trying to implement the same idea of Natural Join in Database but on Two dimensional Arrays, so What I'm trying to do is if I have
A={[a,b],[a',b']} and B={[b,c], [b',c],[b,c']}
The result of NaturalJoin(A,B) should be:
Result = {[a,b,c], [a,b,c'],[a',b',c]}
So after I find the shared column B and compare it in both arrays, how can I combine the rows? Can you please give me some hints on how to create the joinedTableau as I don't know the number of rows from the beginning of the join, how can I create it dynamically?
This is my pseudo code:
int[][] array1;
int[][] array2;
int shared = prtiallyEqualColumn(array1,array2);
for(int i = 0; i <array1.length; i++)
{
for(int j = 0 ; j < array2.length; j++)
{
if(array1[i][shared] == array2[j][shared])
{
for(int s = 0 ; s < shared; s++)
{
joinedTableau[joinedCountRow][s] = array1[i][s];
}
for(int y=shared+1; y<array2.length;y++)
{
joinedTableau[joinedCountRow][y] = array2[j][y];
}
}
}
}

I don't know what you've done in the code as you have hidden several implementations from the code presented here in the question. I am giving you the algo :-
Each column value of array1 must be compared with each row value of
array2 to produce a natural join,only in case if they are equal, else
not.
a1 = array1.countRow();
a2 = array1.countColumn();
b1 = array2.countRow();
b2 = array2.countColumn();
i = j = 1;
while(i<=a1)
while(j<=b1)
if(array1[i][a2]==array2[j][1]) // I've made array-indices start from 1
// perform natural-join operation between array1[i]+array2[j]-common_element
// Similarly iterate the array for next passes.
If there is some mistake or something which is unclear to you,please notify me. Good luck for your code.

This yields the right answer.
is it the most efficient? I posted the results of my timing. definitely exponential growth in times
count
avg time
10
1.931190E-05
100
4.734993E-04
1000
2.540604E-02
10000
1.400114E+00
100000
9.096992E+01
#!python3
from time import time
def natural_join( S, T):
theJoin = []
for i in T:
for j in S:
if i[0] == j[1]:
theJoin.append((i[1], j[0], j[1]))
break
return theJoin
for n in range(1, 6):
A = []
B = []
for i in range(10 ** n):
A.append(('x' + str(i), 'y' + str(i)))
for i in range(10 ** n):
B.append(('y' + str(i), 'z' + str(i)))
start = time()
joined = natural_join(A ,B)
end = time()
print('{:d}, {:E}'.format(10 ** n, (end-start)/n))

Related

Count the number of all possible distinct 3-digit numbers given a String array

Below is my code for counting the number of distinct 3 digit strings which works correctly, HOWEVER, I would like to optimize this code to where I can improve the time complexity. Can someone help me w/ this?
input: [1,2,1,4]
output: 12
Thanks.
static int countUnique(String [] arr)
{
Set<String> s = new TreeSet<>();
for (int i = 0; i<arr.length; i++)
{
for (int j = 0; j<arr.length; j++)
{
for (int k = 0; k<arr.length; k++)
{
if (i!=j && j != k && i!=k)
s.add((arr[i] +""+arr[j]+""+arr[k]));
}
}
}
return s.size();
}
Here's an O(n) solution:
Iterate over each distinct available digit in turn.
(A) Add 1 if there are three instances of it, accounting for one string of three of this digit.
(B) If there are two instances of it, add 3 times the number of digits already iterated over, accounting for 3 choose 2 ways to arrange two instances of this digit with one other digit already iterated over.
(C) Add the number of ways we can pick two of the digits seen so far, accounting for arranging just one instance of this digit with each of those.
(D) Finally, add to our record of the counts of ways to arrange two digits: if there are two instances of this digit, add 3 choose 2 = 3, accounting for just arranging two instances of this digit. Also add (2 * 3 choose 2 = 6) times the number of digits already iterated over, accounting for the number of ways to arrange this digit with another already seen.
For example:
1 2 1 4
1 -> D applies, add 3 to the two-digit-arrangements count
11x, 1x1, x11
2 -> C applies, add 3 to result
112, 121, 211
D applies, add 6 to the two-digit-arrangements count (total 9)
12x, 1x2, x12, 21x, 2x1, x21
4 -> C applies, add 9 to result
Result 12
JavaScript code with random tests, comparing with your brute force approach:
function f(A){
const counts = {};
for (let a of A)
counts[a] = counts[a] ? -~counts[a] : 1;
let result = 0;
let numTwoDigitArrangements = 0;
let numSeen = 0;
for (let d of Object.keys(counts)){
if (counts[d] > 2)
result += 1;
if (counts[d] > 1)
result += 3 * numSeen;
result += numTwoDigitArrangements;
if (counts[d] > 1)
numTwoDigitArrangements += 3;
numTwoDigitArrangements += 6 * numSeen;
numSeen = numSeen + 1;
}
return result;
}
function bruteForce(arr){
const s = new Set();
for (let i=0; i<arr.length; i++){
for (let j=0; j<arr.length; j++){
for (let k=0; k<arr.length; k++){
if (i != j && j != k && i != k)
s.add((arr[i] + "" + arr[j]+ "" + arr[k]));
}
}
}
return s.size;
}
// Random tests
var numTests = 500;
var maxLength = 25;
for (let i=0; i<numTests; i++){
const n = Math.ceil(Math.random() * maxLength);
const A = new Array(n);
for (let j=0; j<n; j++)
A[j] = Math.floor(Math.random() * 10);
const _f = f(A);
const _bruteForce = bruteForce(A);
if (_f != _bruteForce){
console.log('Mismatch found:');
console.log('' + A);
console.log(`f: ${ _f }`);
console.log(`brute force: ${ _bruteForce }`);
}
}
console.log('Done testing.');
Another way to solve this is by Backtracking algorithm. Any combination or permutation kind of problem can be solved using Backtracking.
Here is some information on Backtracking algorithm - https://en.wikipedia.org/wiki/Backtracking
Note: This is not most optimized solution nor O(n) solution. This solution is O(n! * n). But there are many opportunities to make it more optimized.
Java code using Backtracking:
int countUniqueOpt(String[] arr) {
//Set to avoid duplicates
Set<String> resultList = new HashSet<>();
backtracking(arr, 3, resultList, new ArrayList<>());
return resultList.size();
}
void backtracking(String[] arr, int k, Set<String> resultList, List<Integer> indexList) {
if (indexList.size() == k) {
String tempString = arr[indexList.get(0)] + arr[indexList.get(1)] + arr[indexList.get(2)];
resultList.add(tempString);
} else {
for (int i = 0; i < arr.length; i++) {
if (!indexList.contains(i)) {
indexList.add(i);
backtracking(arr, k, resultList, indexList);
indexList.remove(indexList.size() - 1);
}
}
}
}

How to randomly combine elements of 2 arrays while making sure to not reuse an element until all have been used at least once?

Essentially I'm writing a program that produces random poems out of an array of nouns and an array of adjectives.
This is accomplished basically using this line
String poem = adjectives[rand.nextInt(3)]+" "+ nouns[rand.nextInt(3)];
Simple enough, but I'm supposed to make sure that it doesn't reuse the same noun or adjective for the next poems until all of them have been used at least once already. I'm not sure how to do that.
Convert the arrays to list, so you can use Collections.shuffle to shuffle them. Once shuffled, you can then simply iterate over them. The values will be random order, and all words will be used exactly once. When you reach the end of an array of words, sort it again, and start from the beginning.
If a poem consists of 1 adjective + 1 noun as in your example, then the program could go something like this:
List<String> adjectives = new ArrayList<>(Arrays.asList(adjectivesArr));
List<String> nouns = new ArrayList<>(Arrays.asList(nounsArr));
Collections.shuffle(adjectives);
Collections.shuffle(nouns);
int aindex = 0;
int nindex = 0;
for (int i = 0; i < 100; ++i) {
String poem = adjectives.get(aindex++) + " " + nouns.get(nindex++);
System.out.println(poem);
if (aindex == adjectives.size()) {
aindex = 0;
Collections.shuffle(adjectives);
}
if (nindex == nouns.size()) {
nindex = 0;
Collections.shuffle(nouns);
}
}
The program will work with other number of adjectives and nouns per poem too.
If you must use an array, you can implement your own shuffle method, for example using the Fisher-Yates shuffle algorithm:
private void shuffle(String[] strings) {
Random random = new Random();
for (int i = strings.length - 1; i > 0; i--) {
int index = random.nextInt(i + 1);
String temp = strings[i];
strings[i] = strings[index];
strings[index] = temp;
}
}
And then rewrite with arrays in terms of this helper shuffle function:
shuffle(adjectives);
shuffle(nouns);
int aindex = 0;
int nindex = 0;
for (int i = 0; i < 100; ++i) {
String poem = adjectives[aindex++] + " " + nouns[nindex++];
System.out.println(poem);
if (aindex == adjectives.length) {
aindex = 0;
shuffle(adjectives);
}
if (nindex == nouns.length) {
nindex = 0;
shuffle(nouns);
}
}
What you can do is make two more arrays, filled with boolean values, that correspond to the adjective and noun arrays. You can do something like this
boolean adjectiveUsed = new boolean[adjective.length];
boolean nounUsed = new boolean[noun.length];
int adjIndex, nounIndex;
By default all of the elements are initialized to false. You can then do this
adjIndex = rand.nextInt(3);
nounIndex = rand.nextInt(3);
while (adjectiveUsed[adjIndex])
adjIndex = rand.nextInt(3);
while (nounUsed[nounIndex]);
nounIndex = rand.nextInt(3);
Note, once all of the elements have been used, you must reset the boolean arrays to be filled with false again otherwise the while loops will run forever.
There are lots of good options for this. One is to just have a list of the words in random order that get used one by one and are then refreshed when empty.
private List<String> shuffledNouns = Collections.EMPTY_LIST;
private String getNoun() {
assert nouns.length > 0;
if (shuffledNouns.isEmpty()) {
shuffledNouns = new ArrayList<>(Arrays.asList(nouns));
Collections.shuffle(wordOrder);
}
return shuffledNouns.remove(0);
}
Best way to do this is to create a shuffled queue from each array, and then just start popping off the front of the queues to build your poems. Once the queues are empty you just generate new shuffled queues and start over. Here's a good shuffling algorithm:
https://en.wikipedia.org/wiki/Fisher–Yates_shuffle
How about keeping two lists for the adjectives and nouns? You can use Collections.shuffle() to order them randomly.
import java.util.*;
class PoemGen {
static List<String> nouns = Arrays.asList("ball", "foobar", "dog");
static List<String> adjectives = Arrays.asList("slippery", "undulating", "crunchy");
public static void main(String[] args) {
for (int i = 0; i < 3; i++) {
System.out.println(String.format("\nPoem %d", i));
generatePoem();
}
}
private static void generatePoem() {
Collections.shuffle(nouns);
Collections.shuffle(adjectives);
int nounIndex = nouns.size() - 1;
int adjectiveIndex = adjectives.size() - 1;
while (nounIndex >= 0 && adjectiveIndex >= 0) {
final String poem = adjectives.get(adjectiveIndex--)+" "+ nouns.get(nounIndex--);
System.out.println(poem);
}
}
}
Output:
Poem 0
crunchy dog
slippery ball
undulating foobar
Poem 1
undulating dog
crunchy ball
slippery foobar
Poem 2
slippery ball
crunchy dog
undulating foobar
Assuming you have the same number of noums and adjectives shuffle both arrays and then merge result. you can shuffle the arrays multiple times if you need (once you get to the end)
shuffleArray(adjectives);
shuffleArray(nouns);
for(int i=0;i<3;i++) {
String poem = adjectives[i] + " " + nouns[i];
}
A simple method to shuffle the arrays:
static void shuffleArray( String[] data) {
for (int i = data.length - 1; i > 0; i--) {
int index = rnd.nextInt(i + 1);
int aux = data[index];
data[index] = data[i];
data[i] = aux;
}
}
This might be overkill for this specific problem but it's an interesting alternative in my opinion:
You can use a linear congruential generator (LCG) to generate the random numbers instead of using rand.nextInt(3). An LCG gives you a pseudo-random sequence of numbers using this simple formula
nextNumber = (a * x + b) % m
Now comes the interesting part (which makes this work for your problem):
The Hull-Dobell-Theorem states that if your parameters a, b and m fit the following set of rules, the generator will generate every number between 0 and m-1 exactly once before repeating.
The conditions are:
m and the offset c are relatively prime
a - 1 is divisible by all prime factors of m
a - 1 is divisible by 4 if m is divisible by 4
This way you could generate your poems with exactly the same line of code as you currently have but instead just generate the array index with the LCG instead of rand.nextInt. This also means that this solution will give you the best performance, since there is no sorting, shuffling or searching involved.
Thanks for the responses everyone! This helped immeasurably. I am now officially traumatized by the sheer number of ways there are to solve even a simple problem.

Produce repmat() method using java

we have the repmat(arr,2,1,2) method in matlab produce a format which is :
arr = [6,3,9,0];
L(:,:,1) =
6 3 9 0
6 3 9 0
L(:,:,2) =
6 3 9 0
6 3 9 0
the java code that i tried to produce same format is
class test24{
public static void main ( String [] args ) {
int[] arr = {6,3,9,0};
test24 test = new test24();
System.out.println(Arrays.deepToString(test.repmat(arr,2,1,2)));
}
public static int[][][] repmat (int[] array, int rows, int columns, int depth)
{
int arrayColumns = array.length;
int resultColumns = arrayColumns * columns;
int[][][] result = new int[rows][resultColumns][depth];
int z = 0;
for (int d = 0; d < depth; d++)
{
for (int r = 0; r < rows; r++)
{
for (int c = 0; c < resultColumns; c++)
{
result[r][c][d] = array[z++];
if (z >= arrayColumns)
{
z = 0;
}
}
}
}
return result;
}
}
the the result from the java code is :
[[6,6],[3,3],[9,9],[0,0]],[[[6,6],[3,3],[9,9],[0,0]]???
please any suggestion
I believe that the depth argument causes that each value within the array has two values (int[][][] result = new int[rows][resultColumns][depth]; would become (given the inputs rows=2, columns=1 and depth=2 and an initial array of 4) new int[2][1][2]).
Not entirely sure what the repmat method exactly should do put it might be that changing the creation of the array into int[][][] result = new int[depth][rows][resultColumns]; fixes the issue.
I imagine that this is because MATLAB used column-major indexing whereas Java uses Iliffe vectors. So MATLAB stores multidimensional vectors using a single contiguous block of memory where Java stores an array of pointers and each pointer points to another array.
It's difficult to tell exactly what the Java data-structure your code resulted in was. Do you think maybe you could rather post a screen shot from a debugger? What you have now does not look correct, the brackets don't even match.
At a guess though, I would suggest that you maybe change this line
result[r][c][d] = array[z++];
To something more like
result[d][r][c] = array[z++];
Or possibly to even alter the inner loop to something like
for (int c = 0; c < columns; c++) {
result[d][r][c] = array;
}

Improving the algorithm for removal of element

Problem
Given a string s and m queries. For each query delete the K-th occurrence of a character x.
For example:
abcdbcaab
5
2 a
1 c
1 d
3 b
2 a
Ans abbc
My approach
I am using BIT tree for update operation.
Code:
for (int i = 0; i < ss.length(); i++) {
char cc = ss.charAt(i);
freq[cc-97] += 1;
if (max < freq[cc-97]) max = freq[cc-97];
dp[cc-97][freq[cc-97]] = i; // Counting the Frequency
}
BIT = new int[27][ss.length()+1];
int[] ans = new int[ss.length()];
int q = in.nextInt();
for (int i = 0; i < q; i++) {
int rmv = in.nextInt();
char c = in.next().charAt(0);
int rr = rmv + value(rmv, BIT[c-97]); // Calculating the original Index Value
ans[dp[c-97][rr]] = Integer.MAX_VALUE;
update(rmv, 1, BIT[c-97], max); // Updating it
}
for (int i = 0; i < ss.length(); i++) {
if (ans[i] != Integer.MAX_VALUE) System.out.print(ss.charAt(i));
}
Time Complexity is O(M log N) where N is length of string ss.
Question
My solution gives me Time Limit Exceeded Error. How can I improve it?
public static void update(int i , int value , int[] arr , int xx){
while(i <= xx){
arr[i ]+= value;
i += (i&-i);
}
}
public static int value(int i , int[] arr){
int ans = 0;
while(i > 0){
ans += arr[i];
i -= (i &- i);
}
return ans ;
}
There are key operations not shown, and odds are that one of them (quite likely the update method) has a different cost than you think. Furthermore your stated complexity is guaranteed to be wrong because at some point you have to scan the string which is at minimum O(N).
But anyways the obviously right strategy here is to go through the queries, separate them by character, and then go through the queries in reverse order to figure out the initial positions of the characters to be suppressed. Then run through the string once, emitting characters only when it fits. This solution, if implemented well, should be doable in O(N + M log(M)).
The challenge is how to represent the deletions efficiently. I'm thinking of some sort of tree of relative offsets so that if you find that the first deletion was 3 a you can efficiently insert it into your tree and move every later deletion after that one. This is where the log(M) bit will be.

Efficient method to find permutations of variable number of arrays containing varibale number of elements [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How can I find all of the permutations consisting of 1 element from a variable number of arrays of variable length?
Suppose I have n arrays with elements like below
a1 -> e11,e12,e13
a2 -> e21,e22,e23,e24,e25
a3 -> e31,e32
a4 -> e41,e42,e43,e44
...
an -> en1,en2,en3,en4,en5,en6
I want to get all possible permutations with n elements in it from each array above.
For exm.
e11,e21,e31,e41.........,en1
e13,e25,e32,e41.........,en6
and so on...
Suggest me an efficient method and if possible code snippet in Java or C.
You may use following pseudo code:
Function to get next permutation:
function NextPermutation(int[] current)
{
current[0] = current[0] + 1;
int pointer = 0;
while(pointer <= n && current[pointer] == limit[pointer])
{
current[pointer] = 0;
pointer = pointer + 1;
current[pointer] = current[pointer] + 1;
}
}
Pre population code:
int[] limit = new int[n + 2];
int[] current = new int[n + 2];
limit[1] = a1.length;
...
limit[n] = an.length;
while(current[n+1] == 0)
{
Print(current);
NextPermutation(current);
}
current array containt indexes into arrays a1, a2, ... , an.
Since you are interested in all array combinations For loop will be great here
Here is a solution(should be modified for syntaxes though to get it working)
int i = 0
int j=0
int k =0
while(i<arraylength(a1))
{
while (j < arraylength(a2))
{
//and so till an
print a1[i],a2[j];
j++;
}
i++;
}

Categories

Resources