I need to calculate the minimum number of comparisons that the implementation of the BST will be effectuate, given an array of numbers with length N and changing the order in which the elements are added.
For example, if I have an array [1 2 3], it will print that the minimum amount of comparisons with a given order is 2, from the 6 different ways of adding the numbers to the tree.
The code that I actually write may already calculate this, creating a new tree for every combination to find the number of comparisons and finally calculating the minimum value from them by using the method comparisonTree.findMin();. It goes well until the number of elements in the array is bigger; the implementation isn't efficient enough.
The code I use for acquire the combinations is a modified version of the one from Generating all permutations of a given string. I'm searching for a more efficient way for completing this task, if any.
public static int[] readInts(String cad) {
String lines[] = cad.split("");
int arr[] = new int[lines.length];
for (int i = 0; i < arr.length; i++) {
arr[i] = Integer.parseInt(lines[i]);
}
return arr;
}
public static int findMinimumComp(String str, BinarySearchTree<Integer> t) throws Exception {
BinarySearchTree<Integer> compTree = new BinarySearchTree<>();
int compAux = 100;
findMinimumComp("", str, t, compTree, compAux);
return compTree.findMin();
}
private static BinarySearchTree<Integer> findMinimumComp(String prefix, String str, BinarySearchTree<Integer> t, BinarySearchTree<Integer> compTree, int compAux) throws Exception {
int n = str.length();
int arr[] = new int[n];
int comparation;
if (n == 0) {
arr = readInts(prefix);
for (int a = 0; a < arr.length; a++) { // add elements
t.insert(arr[a]);
}
comparation = t.getCompareCount(); //method for getting number of comparisons
if (comparation < compAux || compTree.isEmpty()){
compTree.insert(comparation); //comparisons tree
compAux = comparation;
}
t.initializeCompareCount();
t.makeEmpty();
} else {
for (int i = 0; i < n; i++) {
findMinimumComp(prefix + str.charAt(i), str.substring(0, i) + str.substring(i + 1, n), t, compTree, compAux);
}
}
return compTree;
}
Related
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 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).
I have to create a program which adds two integers and prints the sum vertically.
For example, I have.
a=323, b=322.
The output should be:
6
4
5
I've created the code for when the integers are up to two digits, but I want it to work for at least three digits.
Below is the best I could think of.
It may be completely wrong, but the only problem I'm facing is the declaration of array.
It says that the array might not be initialized.
If I set it to null then also it won't assign values to it later.
I know maybe I'm making a big mistake here, but I'll really appreciate if anyone could help me out.
Please keep in mind that I must not use any other functions for this code.
Hope I'm clear.
public class Vert
{
public static void main(String args[])
{
int n,i=0,j,a=323,b=322;
int s[];
n=a+b;
while(n>9)
{
s[i]=n%10;
i++;
s[i]=n/10;
if(s[i]>9)
{
n=s[i];
}
}
j=i;
for(j=i;j>=0;j--)
{
System.out.println(+s[j]);
}
}
}
String conversion seems like cheating, so here's a Stack.
int a = 323, b = 322;
java.util.Stack<Integer> stack = new java.util.Stack<>();
int n = a + b;
while (n > 0) {
stack.push(n % 10);
n = n / 10;
}
while (!stack.isEmpty())
System.out.println(stack.pop());
If an array is required, you need two passes over the sum
int a = 323, b = 322;
// Get the size of the array
int n = a + b;
int size = 0;
while (n > 0) {
size++;
n = n / 10;
}
// Build the output
int s[] = new int[size];
n = a + b;
for (int i = size - 1; n > 0; i--) {
s[i] = n % 10;
n = n / 10;
}
// Print
for (int x : s) {
System.out.println(x);
}
To initialize an array, you need to specify the size of your array as next:
int s[] = new int[mySize];
If you don't know the size of your array, you should consider using a List of Integer instead as next:
List<Integer> s = new ArrayList<Integer>();
Here is how it could be done:
// Convert the sum into a String
String result = String.valueOf(a + b);
for (int i=0; i <result.length();i++) {
// Print one character corresponding to a digit here per line
System.out.println(result.charAt(i));
}
I'd do it like this:
int a = 322;
int b = 322;
int sum = a + b;
String s = Integer.toString(sum);
for(int i = 0; i < s.length(); i++) {
System.out.println(s.charAt(i));
}
But your problem looks like an array is required.
The steps are same as in my solution:
Use int values
Sum the int values (operation)
Convert the int value in an array/string
Output the array/string
This question already has answers here:
Algorithm to return all combinations of k elements from n
(77 answers)
Closed 9 years ago.
For example, I have an array ["Sam", "Mary", "John"].
I would like to display the combination of choose 2 out of 3.
The results should be:
[Sam, Mary]
[Sam, John]
[Mary, John]
I have researched a lot but still dun know how to do it.
Of course, this example only contain 3 people.
In fact, the number of total people will be larger, e.g. 15
Here is what I found:
Algorithm to return all combinations of k elements from n
What is a good way to implement choose notation in Java?
Some of them is only display the value of nCr, but not giving out the combination.
public static int width;
public static void main(String [] args){
String[] array = {"one", "two", "three", "four", "five"};
width = 3;
List<String> list = new ArrayList<String>();
for (int i = 0; i < array.length; i++){
method(array, list, i, 1, "[" + array[i]);
}
System.out.println(list);
}
public static void method(String[] array, List<String> list, int i, int depth, String string){
if (depth == width){
list.add(string + "]");
return;
}
for (int j = i+1; j < array.length; j++){
method(array, list, j, depth+1, string + ", " + array[j]);
}
}
Simple recursive function to print out combination(nCr) of a given string array (named array):
String[] array = {"Sam", "Mary", "John"};
public void function(int counter, String comb_Str, int r) {
if (r == 0) {
System.out.println(comb_Str);
} else {
for (; counter < array.length; ++counter) {
function(counter + 1, comb_Str + " " + array[counter], r - 1);
}
}
}
called using function(0, "", #r value#)
r value should be <= n value (array length)
Here's some pseudocode to get you started with a recursive solution. Lists will be easier to work with than string arrays, as you can change their size easily. Also, once you get your combos, you can iterate over them to display them however you want. However, though it's a good problem to think about, the number of combos will get out of hand pretty quickly, so displaying them all to a user will become a bad idea if you are working with more than a handful of results...
/**
* #param list The list to create all combos for
* #param comboSize The size of the combo lists to build (e.g. 2 for 2 items combos)
* #param startingIndex The starting index to consider (used mainly for recursion). Set to 0 to consider all items.
*/
getAllCombos(list, comboSize, startingIndex){
allCombos;
itemsToConsider = list.length - startingIndex;
if(itemsToConsider >= comboSize){
allCombos = getAllCombos(list, comboSize, startingIndex + 1);
entry = list[startingIndex];
if(comboSize == 1){
singleList;
singleList.add(entry);
allCombos.add(singleList);
} else {
subListCombos = getAllCombos(list, comboSize - 1, i+1);
for(int i = 0; i < subListCombos.length; i++){
subListCombo = subListCombos[i];
subListCombo.add(entry);
allCombos.add(subListCombo);
}
}
}
return allCombos;
}
This probably isn't perfect, but it should get you on the right track. Create a function to get combinations for each element. Then you just have to loop through each element and call your function on each of them.
int num = 2; //Number of elements per combination
for(int i=0; i <= (array.length - num); i++) {
String comb = "[" + array[i];
comb += getComb(i,num);
comb += "]";
println(comb);
}
String getComb(int i, int num) {
int counter = 1;
String s = "";
while(counter < num) {
s += ", " + array[i+counter];
counter++;
}
return s;
}
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.