Issue implementing a recursive shuffle array method in nlog(n) time - java

I'm trying to implement a recursive shuffle method that will take nlog(n) time but am having major difficulty, given I am restricted to a single parameter and can't include the size of n in my params when calling the recursive method. I looked at the structure of a similar shuffling problem with different parameters and got the idea for how to structure the shuffling using Random, but I've spent way too much time trying to figure out how to implement this.
If I could implement the method taking two parameters, a and n, I don't feel like I would be having so much trouble. My question is, should I have n be a global variable for the purpose of decrementing it? How would I go about either decrementing n for the purpose of managing the recursion, or modify a somehow to eventually end the recursion?
*Also, would declaring the objects in the indices like this cause a referential issue? If so, how would I fix this? I tried clone and couldn't get it to function within the requirements of the problem.
public static void shuffle(Object[] a) {
int n = a.length;
if (n == 0) {
return;
}
int d = (int) (Math.random() * (n-1)); //random index
Object c = a[n - 1]; //value at n-1
a[n-1]= a[d]; //a[n-1] index = val at rand index
a[d] = c; //val at rand index set to val at n-1
shuffle(a);
shuffle(a);
}
***What I've started to implement which looks a lot more like it would work in nlogn time complexity, but not sure if it's right or how it would need to be finished...
public static void shuffle(Object[] a){
if(a.length == 1) return; //return if length = 1: base case
Object[] b = new Object[a.length/2]();
Random rand = new Random(0,a.length); //random index to swap
for(int i = 0; i < b.length; i++){
b[i] = a[rand]; //how do I make sure no index of a is
//repeated?
}
shuffle(b); //recursively call shuffle on b, dividing size by 2
for(int i = 0; i < a.length; i++){
a[i] = b[i]; //copy values from b to a (I guess you could use arraycopy)
}
}

If I could implement the method taking two parameters, a and n, I don't feel like I would be having so much trouble. My question is, should I have n be a global variable for the purpose of decrementing it?
It does not have to be a global variable. You can create a class inside your method as follows. This should support any requirement that the implementation must be kept inside the publicly available method. Of course, you'll need to decide if this is in accordance with any other restrictions not mentioned in your question. I leave the actual algorithm up to you. But the array can be shuffled in-place in O(n).
public static void shuffle(Object[] a) {
class Shuffle {
private void recShuffle(Object[] ob, int n) {
// your shuffle algorithm here
}
}
Shuffle s = new Shuffle();
int n = ... // up to you
s.recShuffle(a, n);
}

So I was able to figure out a way to solve it this morning by implementing a helper method and moving most of my code there in case anyone ever comes across a problem like this:
//calls helper shuffle method
public static void shuffle(Object[] a) {
int n = a.length;
helperShuffle(a, n);
}
public static Object[] helperShuffle(Object[] a, int n) {
if (n <= 1)
return a; //base case: size of array is 1
Random rand = new Random(); //declare new random
int d = (rand.nextInt(n)); //random index < n
Object c = a[n - 1]; //value at n-1
a[n-1]= a[d]; //a[n-1] index = val at rand index
a[d] = c; //val at rand index set to val at n-1
return helperShuffle(a,n-1);
}

Related

Accessing member variables vs creating new object

So I have some code which returns the min and max of an array in an object called min max. My question is inside the for loop do we need to create a new MinMax object at each iteration. Or could we just update MinMax's member variables like so:
globalMinMax.largest = Math.min(globalMinMax.smallest, localMinMax.smallest);
globalMinMax.smallest = Math.max(globalMinMax.largest, localMinMax.largest));
Instead of creating a new MinMax each time like we do on the starred line in the code below
private static class MinMax {
public Integer smallest;
public Integer largest;
public MinMax(Integer smallest, Integer largest) {
this.smallest = smallest;
this.largest = largest;
}
private static MinMax minMax(Integer a, Integer b) {
return Integer.compare(b, a) < 0 ? new MinMax(b, a) : new MinMax(a, b);
}
}
public static MinMax findMinMax(List<Integer> A) {
if (A.size() <= 1) {
return new MinMax(A.get(0), A.get(0));
}
MinMax globalMinMax = MinMax.minMax(A.get(0), A.get(1));
// Process two elements at a time.
for (int i = 2; i + 1 < A.size(); i += 2) {
MinMax localMinMax = MinMax.minMax(A.get(i), A.get(i + 1));
**********Do we need to create a new object here?*****
globalMinMax
= new MinMax(Math.min(globalMinMax.smallest, localMinMax.smallest),
Math.max(globalMinMax.largest, localMinMax.largest));
}
// If there is odd number of elements in the array, we still
// need to compare the last element with the existing answer.
if ((A.size() % 2) != 0) {
globalMinMax
= new MinMax(Math.min(globalMinMax.smallest, A.get(A.size() - 1)),
Math.max(globalMinMax.largest, A.get(A.size() - 1)));
}
return globalMinMax;
}
This code is too complex for what its doing. You should use the MinMax class you've generated to act as a store of the min/max of a list but should not use it during computation.
Finding the minimum/maximum of a list is as simple as:
int minimum = A.get(0);
int maximum = A.get(0);
for(int i=1; i < A.size(); i++){
if(A.get(i) < minimum) minimum = A.get(i);
if(A.get(i) > maximum) maximum = A.get(i);
}
return new MinMax(minimum, maximum);
If you want to incorporate the MinMax class more into the your overall program you can add a static method to the class called something like generateMinMaxFromList that will statically generate minMax objects from supplied Integer lists.
Updating globalMinMax would be the better solution of the two provided if the data is not accessed in a multithreaded environment. You also need not spin up a lot of objects (especially inside a loop) just to find the minimum and maximum value. this can cause overhead when the source collection you're iterating over has a lot of elements.
However, there is one situation in which you'll want to create a new instance of MinMax objects within each iteration. This would be when you spin up multiple threads to act on the data.
Note - the first check within the MinMax method would throw an exception if the list passed in is empty. thus make a check for A.size() == 0 as the first statement within the method and perform the appropriate action.

understanding recursion for dot product in java

Could anyone give me some clue about how could I Transform this code to recursion:
public class arrayExample {
public static void main (String[] args) {
int[] a = {2,2,2,2};
int[] b = {2,2,2,2};
int n = a.length;
int sum = 0;
for (int i = 0; i < n; i++) {
sum += a[i] * b[i];
}
System.out.println(sum);
}
}
So to do this do product with recursion.
You asked for a hint, so I'm not giving you the complete solution. When you want to process a list (or an array) recursively, the concept is nearly always:
public int recursiveFunction(List l, int carry) {
if (l.isEmpty()) {
return carry;
}
return recursiveFunction(l.subList(1, l.size()), operation(carry, l.get(0));
}
Where operation is whatever you want to do with your list. carry is used to provide an initial value (in the first call) and save the interim results.
You just have to change the code so it uses two arrays instead of one list and choose the correct operation.
Ok so hoping you have tried it before this is one possible way to code it.
public class ArrayExample {
public static void main (String[] args) {
int[] a = {2,2,2,2};
int[] b = {2,2,2,2};
int n = a.length;
int result = recurseSum(a, b, n-1);
System.out.println(result);
}
public static int recurseSum(int[] a, int[] b, int n){
if(n == 0)
return a[0]*b[0];
else{
return (a[n] * b[n]) + recurseSum(a,b,n-1);
}
}
}
This code is basically doing the same thing in the iteration.
The recursive call happens 4 times. When n hits 0, a[0]*b[0] is returned to the higher call. so basically from right to left it happens as follows:
a[3]*b[3] + a[2]*b[2] + a[1]*b[1] + a[0]*b[0]
One simple way to make a loop into a recursion is to answer these two questions:
What happens when the loop executes zero times?
If the loop has already executed n-1 times, how do I compute the result after the n-th iteration?
The answer to the first case produces your base case; the answer to the second question explains how to do the recursive invocation.
In your case, the answers are as follows:
When the loop executes zero times, the sum is zero.
When the loop executed n-1 times, add a[n] * b[n] to the previous result.
This can be translated into a recursive implementation
static int dotProduct(int[] a, int[] b, int n) {
... // your implementation here
}

Finding the sum of common elements between n number of arrays in java

I have a program that sums the common elements of two arrays. For that I used two for loops and if I have three then I could use three for loops. But how to sum the common elements of n number of arrays where n is coming during run time.
I don't know how to change the number of loops during run time or is there any other relevant concept for this ?
Here is the code I've tried for summing twoarrays:
import java.util.Scanner;
public class Sample {
public static void main(String... args)
{
Scanner sc=new Scanner(System.in);
int arr1[]={1,2,3,4,5},arr2[]={4,5,6,7,8},sum=0;
for (int i=0;i<arr1.length;i++)
{
for (int j=0;j<arr2.length;j++)
{
if (arr1[i]==arr2[j])
{
sum+=(arr1[i]);
}
}
}
}
}
There can be different implementation for that. You can use the following approach. Here is the pseudo code
use a 2D array to store the array. if the number of array is n and size is m then the array will be input[n][m]
Use a ArrayList commonItems to store the common items of. Initiate it with the elements of input[0]
Now iterate through the array for i = 1 to n-1. compare with every input[i], store only the common items of commonItems and input[i] at each step. You can do it by converting the input[i] into a list and by using retainAll method.
At the end of the iteration the commonItem list will contains the common numbers only. Now sum the value of this list.
There is actually a more general method, that also answers the question "how to change the number of loops during run time?".
The general question
We are looking for a way to implement something equivalent to this:
for (i1 = 0; i1 < k1; i1++) {
for (i2 = 0; i2 < k2; i2++) {
for (i3 = 0; i3 < k3; i3++) {
...
for (in = 0; in < kn; in++) {
f(x1[i1], x2[i2], ... xn[in]);
}
...
}
}
}
where, n is given at runtime and f is a function taking a list of n parameters, processing the current n-tuple.
A general solution
There is a general solution, based on the concept of recursion.
This is one implementation that produces the desired behavior:
void process(int idx, int n, int[][] x, int[] k, Object[] ntuple) {
if (idx == n) {
// we have a complete n-tuple,
// with an element from each of the n arrays
f(ntuple);
return;
}
// this is the idx'th "for" statement
for (int i = 0; i < k[idx]; i++) {
ntuple[idx] = x[idx][i];
// with this recursive call we make sure that
// we also generate the rest of the for's
process(idx + 1, n, x, k, ntuple);
}
}
The function assumes that the n arrays are stored in a matrix x, and the first call should look like this:
process(0, n, x, k, new Object[n]);
Practical considerations
The solution above has a high complexity (it is O(k1⋅k2⋅..⋅kn)), but sometimes it is possible to avoid going until the deepest loop.
Indeed, in the specific problem mentioned in this post (which requires summing common elements across all arrays), we can skip generating some tuples e.g. if already x2[i2] ≠ x1[i1].
In the recursive solution, those situations can easily be pruned. The specific code for this problem would probably look like this:
void process(int idx, int n, int[][] x, int[] k, int value) {
if (idx == n) {
// all elements from the current tuple are equal to "value".
// add this to the global "sum" variable
sum += value;
return;
}
for (int i = 0; i < k[idx]; i++) {
if (idx == 0) {
// this is the outer "for", set the new value
value = x[0][i];
} else {
// check if the current element from the idx'th for
// has the same value as all previous elements
if (x[idx][i] == value) {
process(idx + 1, n, x, k, value);
}
}
}
}
Assuming that the index of the element is not important: a[1] = 2 and a[5] = 2, you only need two nested loops.
First you need to put n-1 arrays in a list of sets. Then loop over nth array and check if each element exists in all of the sets in the list. If it does exist then add to total.

how to improve this code?

I have developed a code for expressing the number in terms of the power of the 2 and I am attaching the same code below.
But the problem is that the expressed output should of minimum length.
I am getting output as 3^2+1^2+1^2+1^2 which is not minimum length.
I need to output in this format:
package com.algo;
import java.util.Scanner;
public class GetInputFromUser {
public static void main(String[] args) {
// TODO Auto-generated method stub
int n;
Scanner in = new Scanner(System.in);
System.out.println("Enter an integer");
n = in.nextInt();
System.out.println("The result is:");
algofunction(n);
}
public static int algofunction(int n1)
{
int r1 = 0;
int r2 = 0;
int r3 = 0;
//System.out.println("n1: "+n1);
r1 = (int) Math.sqrt(n1);
r2 = (int) Math.pow(r1, 2);
// System.out.println("r1: "+r1);
//System.out.println("r2: "+r2);
System.out.print(r1+"^2");
r3 = n1-r2;
//System.out.println("r3: "+r3);
if (r3 == 0)
return 1;
if(r3 == 1)
{
System.out.print("+1^2");
return 1;
}
else {
System.out.print("+");
algofunction(r3);
return 1;
}
}
}
Dynamic programming is all about defining the problem in such a way that if you knew the answer to a smaller version of the original, you could use that to answer the main problem more quickly/directly. It's like applied mathematical induction.
In your particular problem, we can define MinLen(n) as the minimum length representation of n. Next, say, since we want to solve MinLen(12), suppose we already knew the answer to MinLen(1), MinLen(2), MinLen(3), ..., MinLen(11). How could we use the answer to those smaller problems to figure out MinLen(12)? This is the other half of dynamic programming - figuring out how to use the smaller problems to solve the bigger one. It doesn't help you if you come up with some smaller problem, but have no way of combining them back together.
For this problem, we can make the simple statement, "For 12, it's minimum length representation DEFINITELY has either 1^2, 2^2, or 3^2 in it." And in general, the minimum length representation of n will have some square less than or equal to n as a part of it. There is probably a better statement you can make, which would improve the runtime, but I'll say that it is good enough for now.
This statement means that MinLen(12) = 1^2 + MinLen(11), OR 2^2 + MinLen(8), OR 3^2 + MinLen(3). You check all of them and select the best one, and now you save that as MinLen(12). Now, if you want to solve MinLen(13), you can do that too.
Advice when solo:
The way I would test this kind of program myself is to plug in 1, 2, 3, 4, 5, etc, and see the first time it goes wrong. Additionally, any assumptions I happen to have thought were a good idea, I question: "Is it really true that the largest square number less than n will be in the representation of MinLen(n)?"
Your code:
r1 = (int) Math.sqrt(n1);
r2 = (int) Math.pow(r1, 2);
embodies that assumption (a greedy assumption), but it is wrong, as you've clearly seen with the answer for MinLen(12).
Instead you want something more like this:
public ArrayList<Integer> minLen(int n)
{
// base case of recursion
if (n == 0)
return new ArrayList<Integer>();
ArrayList<Integer> best = null;
int bestInt = -1;
for (int i = 1; i*i <= n; ++i)
{
// Check what happens if we use i^2 as part of our representation
ArrayList<Integer> guess = minLen(n - i*i);
// If we haven't selected a 'best' yet (best == null)
// or if our new guess is better than the current choice (guess.size() < best.size())
// update our choice of best
if (best == null || guess.size() < best.size())
{
best = guess;
bestInt = i;
}
}
best.add(bestInt);
return best;
}
Then, once you have your list, you can sort it (no guarantees that it came in sorted order), and print it out the way you want.
Lastly, you may notice that for larger values of n (1000 may be too large) that you plug in to the above recursion, it will start going very slow. This is because we are constantly recalculating all the small subproblems - for example, we figure out MinLen(3) when we call MinLen(4), because 4 - 1^2 = 3. But we figure it out twice for MinLen(7) -> 3 = 7 - 2^2, but 3 also is 7 - 1^2 - 1^2 - 1^2 - 1^2. And it gets much worse the larger you go.
The solution to this, which lets you solve up to n = 1,000,000 or more, very quickly, is to use a technique called Memoization. This means that once we figure out MinLen(3), we save it somewhere, let's say a global location to make it easy. Then, whenever we would try to recalculate it, we check the global cache first to see if we already did it. If so, then we just use that, instead of redoing all the work.
import java.util.*;
class SquareRepresentation
{
private static HashMap<Integer, ArrayList<Integer>> cachedSolutions;
public static void main(String[] args)
{
cachedSolutions = new HashMap<Integer, ArrayList<Integer>>();
for (int j = 100000; j < 100001; ++j)
{
ArrayList<Integer> answer = minLen(j);
Collections.sort(answer);
Collections.reverse(answer);
for (int i = 0; i < answer.size(); ++i)
{
if (i != 0)
System.out.printf("+");
System.out.printf("%d^2", answer.get(i));
}
System.out.println();
}
}
public static ArrayList<Integer> minLen(int n)
{
// base case of recursion
if (n == 0)
return new ArrayList<Integer>();
// new base case: problem already solved once before
if (cachedSolutions.containsKey(n))
{
// It is a bit tricky though, because we need to be careful!
// See how below that we are modifying the 'guess' array we get in?
// That means we would modify our previous solutions! No good!
// So here we need to return a copy
ArrayList<Integer> ans = cachedSolutions.get(n);
ArrayList<Integer> copy = new ArrayList<Integer>();
for (int i: ans) copy.add(i);
return copy;
}
ArrayList<Integer> best = null;
int bestInt = -1;
// THIS IS WRONG, can you figure out why it doesn't work?:
// for (int i = 1; i*i <= n; ++i)
for (int i = (int)Math.sqrt(n); i >= 1; --i)
{
// Check what happens if we use i^2 as part of our representation
ArrayList<Integer> guess = minLen(n - i*i);
// If we haven't selected a 'best' yet (best == null)
// or if our new guess is better than the current choice (guess.size() < best.size())
// update our choice of best
if (best == null || guess.size() < best.size())
{
best = guess;
bestInt = i;
}
}
best.add(bestInt);
// check... not needed unless you coded wrong
int sum = 0;
for (int i = 0; i < best.size(); ++i)
{
sum += best.get(i) * best.get(i);
}
if (sum != n)
{
throw new RuntimeException(String.format("n = %d, sum=%d, arr=%s\n", n, sum, best));
}
// New step: Save the solution to the global cache
cachedSolutions.put(n, best);
// Same deal as before... if you don't return a copy, you end up modifying your previous solutions
//
ArrayList<Integer> copy = new ArrayList<Integer>();
for (int i: best) copy.add(i);
return copy;
}
}
It took my program around ~5s to run for n = 100,000. Clearly there is more to be done if we want it to be faster, and to solve for larger n. The main issue now is that in storing the entire list of results of previous answers, we use up a lot of memory. And all of that copying! There is more you can do, like storing only an integer and a pointer to the subproblem, but I'll let you do that.
And by the by, 1000 = 30^2 + 10^2.

java mergesort count homework

I am working on getting the counts of comparisons and movers when merge sorting. I think I have the recursion I need thanks to this Sort Comparisons Counter but I can not get it to print out. I am obviously very new at programming so I'd be appreciative if you could explain what it is that I am missing.
import java.util.Arrays;
public class MergeSort {
int count = 0;
/**
* #param args
*/
// Rearranges the elements of a into sorted order using
// the merge sort algorithm (recursive).
public int mergeSort(int[] a, int howMany) {
if (a.length >= 2) {
// split array into two halves
int[] left = Arrays.copyOfRange(a, 0, a.length/2);
int[] right = Arrays.copyOfRange(a, a.length/2, a.length);
// sort the two halves
howMany = mergeSort(left,howMany);
howMany = mergeSort(right, howMany);
// merge the sorted halves into a sorted whole
howMany = merge ( left, right, a, howMany);
}
return howMany;
}
// Merges the left/right elements into a sorted result.
// Precondition: left/right are sorted
public static int merge(int[] result, int[] left,
int[] right, int howMany) {
int i1 = 0; // index into left array
int i2 = 0; // index into right array
for (int i = 0; i < result.length; i++) {
if (i2 >= right.length ||
(i1 < left.length && left[i1] <= right[i2])) {
result[i] = left[i1]; // take from left
i1++;
} else {
result[i] = right[i2]; // take from right
i2++;
}
}
return howMany;
}
System.out.println(howMany); // ???
}
you need to call the method through its object wherever you wanna print. something like this (may be in your main method):
MergeSort mObj - new MergeSort();
int[] array = {1,2,3};
int count = mObj.mergeSort(array, 2);
System.out.println(count);
Basically, you need a driver method. When a java class is run, it will look for a public static void main(String[] args) method; if this method doesn't exist, nothing will happen. With what you have now, you should actually get a compile error from System.out.println(howMany); since the variable howMany only exists within the scope (brackets) of the merge method. To understand this better I'd review your notes on variable and method scope and class members. For a quick fix, remove the line at the bottom that I mentioned above, and place this method somewhere in your class:
public static void main(String[] args) {
int[] array = {2,5,8,1,3};
int howMany = mergeSort(array, 5);
System.out.println(howMany);
}
You also need to make your mergeSort method static, so change its definition to
public **static** int mergeSort(int[] a, int howMany)
I tested your code and I'm pretty sure that it doesn't give the answer you want, so be sure to check that. Best of luck learning object oriented programming!

Categories