I am trying to calculate the Big-O time complexity for these 3 algorithms, but seems like I have a lack of knowledge on this topic.
1st:
private void firstAlgorithm(int size) {
int[] array = new int[size];
int i=0; int flag=0;
while(i<size) {
int num=(int)(Math.random()*(size));
if (num==0 && flag==0) {
flag=1;
array[i]=0;
i++;
} else if(num==0 && flag==1) {
continue;
} else if(!checkVal(num, array)) {
array[i]=num;
i++;
}
}
}
private static boolean checkVal(int val, int[] arr) {
int i = 0;
for (int num:arr) {
if (num==val) {
return true;
}
}
return false;
}
2nd:
private void secondAlgorithm(int size) {
int i = 0;
int[] array = new int[size];
boolean[] booleanArray = new boolean[size];
while (i < array.length) {
int num = (int) (Math.random() * array.length);
if (!booleanArray[num]) {
booleanArray[num] = true;
array[i] = num;
i++;
}
}
}
3rd:
private void thirdAlgorithm(int size) {
int[] array = new int[size];
for (int i = 0; i < array.length; i++) {
int num = (int) (Math.random() * (i - 1));
if (i > 0) {
array = swap(array, i, num);
}
}
}
private static int[] swap(int[] arr, int a, int b) {
int i = arr[a];
arr[a] = arr[b];
arr[b] = i;
return arr;
}
Would be nice, if you could explain your results.
In my opinion, 1st - O(n^2) because of two loops, 2nd don't know, 3rd O(n)
THank you
I assume that in all your algorithms, where you are generating a random number, you meant to take the remainder of the generated number, not multiplying it with another value (example for the first algorithm: Math.random() % size). If this is not the case, then any of the above algorithms have a small chance of not finishing in a reasonable amount of time.
The first algorithm generates and fills an array of size integers. The rule is that the array must contain only one value of 0 and only distinct values. Checking if the array already contains a newly generated value is done in O(m) where m is the number of elements already inserted in the array. You might do this check for each of the size elements which are to be inserted and m can get as large as size, so an upper bound of the running-time is O(size^2).
The second algorithm also generates and fills an array with random numbers, but this time the numbers need not be distinct, so no need to run an additional O(m) check each iteration. The overall complexity is given by the size of the array: O(size).
The third algorithm generates and fills an array with random numbers and at each iteration it swaps some elements based on the given index, which is a constant time operation. Also, reassigning the reference of the array to itself is a constant time operation (O(1)). It results that the running-time is bounded by O(size).
Related
Requirement : There's an input List and an input shift no.
The first line contains two space-separated integers that denote :
n, the number of integers, and
d, the number of left rotations to perform.
The second line contains space-separated integers that describe arr[].
Constraints
1 <= n <= 10^5
1 <= d <= n
1 <= arr[i] <= 10^6
Sample Input
5 , 4
1 2 3 4 5
Sample Output
5 1 2 3 4
I have written this code which is working correctly but getting timeout while large operation. So I need to optimize my code to successfully run all the test cases. How to achieve that.
public static List<Integer> rotateLeft(int d, List<Integer> arr) {
int size = arr.size();
while(d>0) {
int temp = arr.get(0);
for(int i = 0; i<size; i++){
if(i != size-1){
arr.set(i,arr.get(i+1));
} else {
arr.set(i,temp);
}
}
d--;
}
return arr;
}
Failing for this input :
n = 73642
d = 60581
And a huge Integer List of size 73642.
Instead of using nested loops, this can be done in one loop. The final index of an element at index i after n shifts, can be calculated as (i + n) % listLength, this index can be used to populate a shifted list. Like this:
import java.util.*;
class HelloWorld {
public static void main(String[] args) {
List<Integer> arr = Arrays.asList(1,2,3,4,5);
System.out.println(rotateLeft(4, arr));
}
public static List<Integer> rotateLeft(int d, List<Integer> arr) {
List<Integer> rotatedList = new ArrayList<>(arr.size());
int i=0;
for(i=0; i< arr.size(); i++) {
int rotatedElementIndex = ((i+d) % arr.size());
rotatedList.add(arr.get(rotatedElementIndex));
}
return rotatedList;
}
}
Never liked hackerrank puzzles. What does "and a huge Integer array" mean? May we create a new list or we need to modify existing one? If we ought to modify existing one why our method is not void?
If we may create new list the optimal solution would be creating new Integer[] array and call System.arraycopy() twice.
In case of inline modifications the solution is:
public static List<Integer> rotateLeft(int d, List<Integer> arr) {
int i = 0, first = arr.get(0);
int n = arr.size();
while (true) {
int source = (i + d) % n;
if (source == 0) {
arr.set(i, first);
break;
}
arr.set(i, arr.get(source));
i = source;
}
return arr;
}
For an in-place solution:
reverse the subarrays arr[0, d) and arr[d, n) in-place. This is done by swapping the elements in symmetric pairs.
reverse the whole array.
E.g., abcdefghijk, d=4
abcd|efghijk -> dcba|kjihgfe -> efghijk|abcd
This question already has answers here:
Generating Unique Random Numbers in Java
(21 answers)
Closed 1 year ago.
I am trying to create a method that fills an array with random integers with no duplicate elements. I'm having trouble making sure each element that is put into the new array is distinct.
Ex. if numOfDigits is 5, then I'd like something like [3][8][2][6][1]. At the moment it either outputs something like [9][0][1][0][0] or infinitely loops.
private static int[] hiddenSet(int numOfDigits){
int[] numArray = new int[numOfDigits];
int temp;
for (int i = 0; i < numArray.length; i++){
do {
temp = getRandomNum(10);
numArray[i] = temp;
} while (isDigitNew(numArray, temp));
//Each random num must be unique to the array
}
return numArray;
}
private static boolean isDigitNew(int[] numArray, int index){
for (int i = 0; i < numArray.length; i++) {
if (numArray[i] == index) {
return false;
}
}
return true;
}
One easy approach is to fill the array with distinct digits then shuffle it.
public static int[] getRandomDistinct(int length) {
Random rand = new Random();
int[] array = new int[length];
// Fill with distinct digits
for (int i = 0; i < length; i++) {
array[i] = i;
}
// Swap every element with a random index
for (int i = 0; i < length - 1; i++) {
int swapWith = i + rand.nextInt(length - i);
int tmp = array[i];
array[i] = array[swapWith];
array[swapWith] = tmp;
}
return array;
}
Your algorithm takes quadratic time at best. When the choice of random numbers becomes less looping may take ages. Even infinite might be possible.
Add a positive random number + 1 to the previous generated number. The desired range of numbers needs a bit of care.
At he end shuffle. If you start with a List, you can use Collections. shuffle.
You can use IntStream like this.
private static int[] hiddenSet(int numOfDigits) {
return IntStream.iterate(getRandomNum(10), i -> getRandomNum(10))
.distinct()
.limit(numOfDigits)
.toArray();
}
and
public static void main(String[] args) {
int[] a = hiddenSet(5);
System.out.println(Arrays.toString(a));
}
output:
[7, 4, 5, 0, 1]
I'm doing a task where you input 3 parameters which are size, minimum value and maximum value. It then is meant to return a random number between the minimum and maximum value of the size inputted. There are also other validations such as if the min is more than the max which I've already done.
I am able to do the task using integer instead of short. As soon as I change the data type a bunch of errors come.
Below is what I've done so far, it works as expected but I am pretty sure that there is not meant to be a bottom return null, I get errors when I delete it. On the second loop, it should return the array instead of doing a system print line. The other issue is the data types at the top, it should be short maxVal and short minVal instead of int but I can't get it to work with short.
I would very much appreciate all help. Thanks!
public static ArrayList<Short> RandomArray1(int n, int maxVal, int minVal){
if(n <= 0) {
return null;
}
if(minVal > maxVal) {
return new ArrayList<Short>();
}
ArrayList<Integer> ran = new ArrayList<Integer>();
Random rand = new Random();
for(int i = 0; i < n; i++) {
int result = rand.nextInt(maxVal-minVal) + minVal;
//System.out.println(result);
ran.add(result);
}
for (int i = 0; i < ran.size(); i++) {
System.out.println(ran.get(i));
//return (ArrayList<Short>)ran.get(i);
}
return null;
I would do it like this.
first, method names by convention should start with lower case letters.
Use the method to generate the values and return the list
return interface types as opposed to implementation types (e.g. List)
throw exceptions if the arguments don't satisfy the requirements.
Note, having to cast the arguments to shorts is cumbersome but it prevents errors at compile time. Otherwise you may want to throw an additional run time exception if the values aren't within Short.MIN_VALUE and Short.MAX_VALUE.
public class RandomShorts {
public static void main(String[] args) {
List<Short> shortList = randomList(20, (short)200, (short)99);
shortList.forEach(System.out::println);
}
public static List<Short> randomList(short n, short maxVal,
short minVal) {
if (n <= 0 || minVal >= maxVal) {
throw new IllegalArgumentException(
"\nn must be > 0\nminVal must be < maxVal\n");
}
List<Short> ran = new ArrayList<>();
Random rand = new Random();
for (int i = 0; i < n; i++) {
short result =
(short) (rand.nextInt(maxVal - minVal) + minVal);
ran.add(result);
}
return ran;
}
}
If you just want to return a single random number using the supplied arguments, they you can do it like this.
public static short randomShort(int n, short maxVal, short minVal) {
return (short)((Math.random()*(maxVal - minVal))+minVal);
}
For adding the short to random list since there is not Random.nextShort(), you'll have to substitute the line
int result = rand.nextInt(maxVal-minVal) + minVal;
for
short result = (short) (rand.nextInt(maxVal-minVal) + minVal);
Where then you can add to your ran array instead of the second for loop returning the ArrayList as a short
public static short[] generateRandomShortArray (int sampleSize, short min, short max) {
short[] result = new short[sampleSize];
for (int index = 0; index < result.length; index++) {
result[index] = (short)((Math.random() * (max-min)) + min);
}
return result;
}
If an array list is required just return Arrays.asList(result);
Write a function:
class Solution{
public int solution(int[] A);
}
that, given an array A of N integers, returns the smallest positive integer(greater than 0)
that does not occur in A.
For example, given A = [1,3,6,4,1,2], the function should return 5.
Given A = [1,2,3], the function should return 4.
Given A = [-1, -3], the function should return 1.
Write an efficient algorithm for the following assumptions.
N is an integer within the range [1..100,000];
each element of array A is an integer within the range [-1,000,000..1,000,000].
I wrote the following algorithm in Java:
public class TestCodility {
public static void main(String args[]){
int a[] = {1,3,6,4,1,2};
//int a[] = {1,2,3};
//int b[] = {-1,-3};
int element = 0;
//checks if the array "a" was traversed until the last position
int countArrayLenght = 0;
loopExtern:
for(int i = 0; i < 1_000_000; i++){
element = i + 1;
countArrayLenght = 0;
loopIntern:
for(int j = 0; j < a.length; j++){
if(element == a[j]){
break loopIntern;
}
countArrayLenght++;
}
if(countArrayLenght == a.length && element > 0){
System.out.println("Smallest possible " + element);
break loopExtern;
}
}
}
}
It does the job but I am pretty sure that it is not efficient. So my question is, how to improve this algorithm so that it becomes efficient?
You should get a grasp on Big O, and runtime complexities.
Its a universal construct for better understanding the implementation of efficiency in code.
Check this website out, it shows the graph for runtime complexities in terms of Big O which can aid you in your search for more efficient programming.
http://bigocheatsheet.com/
However, long story short...
The least amount of operations and memory consumed by an arbitrary program is the most efficient way to achieve something you set out to do with your code.
You can make something more efficient by reducing redundancy in your algorithms and getting rid of any operation that does not need to occur to achieve what you are trying to do
Point is to sort your array and then iterate over it. With sorted array you can simply skip all negative numbers and then find minimal posible element that you need.
Here more general solution for your task:
import java.util.Arrays;
public class Main {
public static int solution(int[] A) {
int result = 1;
Arrays.sort(A);
for(int a: A) {
if(a > 0) {
if(result == a) {
result++;
} else if (result < a){
return result;
}
}
}
return result;
}
public static void main(String args[]){
int a[] = {1,3,6,4,1,2};
int b[] = {1,2,3};
int c[] = {-1,-3};
System.out.println("a) Smallest possible " + solution(a)); //prints 5
System.out.println("b) Smallest possible " + solution(b)); //prints 4
System.out.println("c) Smallest possible " + solution(c)); //prints 1
}
}
Complexity of that algorithm should be O(n*log(n))
The main idea is the same as Denis.
First sort, then process but using java8 feature.
There are few methods that may increase timings.(not very sure how efficient java 8 process them:filter,distinct and even take-while ... in the worst case you have here something similar with 3 full loops. One additional loop is for transforming array into stream). Overall you should get the same run-time complexity.
One advantage could be on verbosity, but also need some additional knowledge compared with Denis solution.
import java.util.function.Supplier;
import java.util.stream.IntStream;
public class AMin
{
public static void main(String args[])
{
int a[] = {-2,-3,1,2,3,-7,5,6};
int[] i = {1} ;
// get next integer starting from 1
Supplier<Integer> supplier = () -> i[0]++;
//1. transform array into specialized int-stream
//2. keep only positive numbers : filter
//3. keep no duplicates : distinct
//4. sort by natural order (ascending)
//5. get the maximum stream based on criteria(predicate) : longest consecutive numbers starting from 1
//6. get the number of elements from the longest "sub-stream" : count
long count = IntStream.of(a).filter(t->t>0).distinct().sorted().takeWhile(t->t== supplier.get()).count();
count = (count==0) ? 1 : ++count;
//print 4
System.out.println(count);
}
}
There are many solutions with O(n) space complexity and O(n) type complexity. You can convert array to;
set: array to set and for loop (1...N) check contains number or not. If not return number.
hashmap: array to map and for loop (1...N) check contains number or not. If not return number.
count array: convert given array to positive array count array like if arr[i] == 5, countArr[5]++, if arr[i] == 1, countArr[1]++ then check each item in countArr with for loop (1...N) whether greate than 1 or not. If not return it.
For now, looking more effective algoritm like #Ricola mentioned. Java solution with O(n) time complexity and O(1) space complexity:
static void swap(final int arr[], final int i,final int j){
final int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
static boolean isIndexInSafeArea(final int arr[], final int i){
return arr[i] > 0 && arr[i] - 1 < arr.length && arr[i] != i + 1 ;
}
static int solution(final int arr[]){
for (int i = 0; i < arr.length; i++) {
while (isIndexInSafeArea(arr,i) && arr[i] != arr[arr[i] - 1]) {
swap(arr, i, arr[i] - 1);
}
}
for (int i = 0; i < arr.length; i++) {
if (arr[i] != i + 1) {
return i+1;
}
}
return arr.length + 1;
}
I've just been looking at the following piece of code
package test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class Main {
public static void main(final String[] args) {
final int sizeA = 3;
final int sizeB = 5;
final List<int[]> combos = getAllCombinations(sizeA-1, sizeB);
int counter = 1;
for(final int[] combo : combos) {
System.out.println("Combination " + counter);
System.out.println("--------------");
for(final int value : combo) {
System.out.print(value + " ");
}
System.out.println();
System.out.println();
++counter;
}
}
private static List<int[]> getAllCombinations(final int maxIndex, final int size) {
if(maxIndex >= size)
throw new IllegalArgumentException("The maximum index must be smaller than the array size.");
final List<int[]> result = new ArrayList<int[]>();
if(maxIndex == 0) {
final int[] array = new int[size];
Arrays.fill(array, maxIndex);
result.add(array);
return result;
}
//We'll create one array for every time the maxIndex can occur while allowing
//every other index to appear, then create every variation on that array
//by having every possible head generated recursively
for(int i = 1; i < size - maxIndex + 1; ++i) {
//Generating every possible head for the array
final List<int[]> heads = getAllCombinations(maxIndex - 1, size - i);
//Combining every head with the tail
for(final int[] head : heads) {
final int[] array = new int[size];
System.arraycopy(head, 0, array, 0, head.length);
//Filling the tail of the array with i maxIndex values
for(int j = 1; j <= i; ++j)
array[size - j] = maxIndex;
result.add(array);
}
}
return result;
}
}
I'm wondering, how do I eliminate recursion from this, so that it returns a single random combination, rather than a list of all possible combinations?
Thanks
If I understand your code correctly your task is as follows: give a random combination of numbers '0' .. 'sizeA-1' of length sizeB where
the combination is sorted
each number occurs at least once
i.e. in your example e.g. [0,0,1,2,2].
If you want to have a single combination only I'd suggest another algorithm (pseudo-code):
Randomly choose the step-up positions (e.g. for sequence [0,0,1,1,2] it would be steps (1->2) & (3->4)) - we need sizeA-1 steps randomly chosen at sizeB-1 positions.
Calculate your target combination out of this vector
A quick-and-dirty implementation in java looks like follows
// Generate list 0,1,2,...,sizeB-2 of possible step-positions
List<Integer> steps = new ArrayList<Integer>();
for (int h = 0; h < sizeB-1; h++) {
steps.add(h);
}
// Randomly choose sizeA-1 elements
Collections.shuffle(steps);
steps = steps.subList(0, sizeA - 1);
Collections.sort(steps);
// Build result array
int[] result = new int[sizeB];
for (int h = 0, o = 0; h < sizeB; h++) {
result[h] = o;
if (o < steps.size() && steps.get(o) == h) {
o++;
}
}
Note: this can be optimized further - the first step generates a random permutation and later strips this down to desired size. Therefore it is just for demonstration purpose that the algorithm itself works as desired.
This appears to be homework. Without giving you code, here's an idea. Call getAllCombinations, store the result in a List, and return a value from a random index in that list. As Howard pointed out in his comment to your question, eliminating recursion, and returning a random combination are separate tasks.