I need to sort an array. I write code, i use insertion sort, but for big n this code work so slow. How optimize my code. May be there is another algorithm.
public void insertionSort(ArrayList<Integer> arrayList) {
int n = arrayList.size();
int in, out;
for(out = 1; out < n; out++)
{
int temp = arrayList.get(out);
in = out;
while (in > 0 && arrayList.get(in-1) > temp)
{
arrayList.set(in, arrayList.get(in-1));
in--;
}
arrayList.set(in,temp);
}
print(arrayList);
}
You can use counting sort instead of insertion sort. Because counting sort takes a linear time, but insertion sort at worst takes О(n^2)
Here is example of using counting sort:
import java.util.Arrays;
import java.util.Random;
import java.util.Scanner;
public class Main {
public static void print(int []a){
System.out.println(Arrays.toString(a));
}
public static void countingSort(int []a, int []b, int n, int k){
int []c = new int [k];
for(int i=0; i<k; i++)
c[i] = 0;
for(int j=0; j<n; j++){
c[a[j]] = c[a[j]]+1;
}
for(int i=1; i<k; i++){
c[i] = c[i]+c[i-1];
}
for(int j=n-1; j>=0; j--){
c[a[j]] = c[a[j]]-1;
b[c[a[j]]] = a[j];
}
for(int i=0; i<n; i++)
a[i] = b[i];
}
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
Random ran = new Random();
int n = Integer.parseInt(in.nextLine());
int []a = new int[n];
int []b = new int[n];
int k = 5; // max value on the array
for(int i=0; i<n; i++)
a[i] = ran.nextInt(k);
print(a);
countingSort(a,b,n,k);
print(a);
}
}
You should look into QuickSort or MergeSort if you want faster sorting algorithms. Unlike InsertionSort (and SelectionSort), they are recursive, but still fairly easy to implement. You can find many examples if you look around on the internet.
As Anna stated above, counting sort can be a really good algorithm, considering you don't have a really large data set and the data is not sparse.
For example, an array of size 10k with 100 elements duplicated will have much better space efficiency than an array of size 10k with all unique elements and spread in a sparse fashion.
For example, the following array -> [5,5,4,...,2,2,1,1,5,6,7,8] will need a space of an array of size 8 (1 being the minimum and 8 being the maximum) while,
This array -> [5,100,6004,3248,45890,2384,128,8659,...,3892,128] will need a space of an array at least of size 45886 (5 being the minimum and 45890 being the maximum).
So, I'll suggest you use this algorithm when you know that the data set you have is evenly distributed within an acceptable range which won't make your program run out of memory. Otherwise you can go with something like quicksort or mergesort. That gets the work done just fine.
That being said, Anna's implementation of counting sort seemed a little over coded to me personally, so here's me sharing my implementation.
public int[] countSort(int[] nums) {
int min = nums[0], max = nums[0], counterLength, start = 0;
int[] counter;
// To dynamically allocate size to the counter.
// Also an essential step if there are negative elements in the input array.
// You can actively avoid this step if you know:
// 1. That the elements are not going to be negative.
// 2. The upper bound of the elements in the array.
for (int i : nums) {
if (i > max)
max = i;
else if (i < min)
min = i;
}
counterLength = max - min + 1;
counter = new int[counterLength];
for (int i : nums)
counter[i - min]++;
for (int i = 0; i < counterLength; i++) {
if (counter[i] > 0) {
int end = start + counter[i];
Arrays.fill(nums, start, end, i + min);
start = end;
}
}
return nums;
}
Related
Hello all please check the problemHackerRank Problem Statement
This is my solution for the above problem(link)
static int migratoryBirds(List<Integer> arr) {
int ar[]=new int[arr.size()];
for(int i=0;i<arr.size();i++){
ar[i] = Collections.frequency(arr,arr.get(i));
// ar[i] = obj.occuranceOfElement(arr,arr.get(i));
}
int maxAt = 0;
for (int i = 0; i < ar.length; i++) {
maxAt = ar[i] > ar[maxAt] ? i : maxAt;
}
return arr.get(maxAt);
}
my code is unable to handle when the array size is bigger,example 17623 elements in array.
Terminated due to timeout
The problem is in the second for loop which iterates over the array and gives me the index of the largest number in the array.Is there any other way that I could increase the performance.
Your problem is in this part:
for(int i = 0; i < arr.size(); i++)
ar[i] = Collections.frequency(arr, arr.get(i));
This is O(N²): Collections.frequency() iterates over whole list to calculate frequency for only one element. Manually, you can iterate over the list to calculate frequencey for all elements.
Moreover, ther're only 5 birds, so you need only 5 length array.
static int migratoryBirds(int[] arr) {
int max = 1;
int[] freq = new int[6];
for (int val : arr)
freq[val]++;
for (int i = 2; i < freq.length; i++)
max = freq[i] > freq[max] ? i : max;
return max;
}
Your problem is the call to Colletions.frequency, which is an O(N) operation. When you call it from inside a loop it becomes O(N²) and that consumes all your time.
Also, are you sure which implmentation of List you receive? You call list.get(i) which might also be O(N) if the implementation is a LinkedList.
The target of this exercise is to calculate the frequency of each value in one pass over the input. You need a place where you store and increase the number of occurrences for each value and you need to store the largest value of the input.
You have also skipped over a crucial part of the specification. The input has limits which makes solving the problem easier than you now think.
Here's another one:
static int migratoryBirds(List<Integer> arr) {
int freq[]=new int[6];
for(int i=0;i<arr.size();i++){
++freq[arr.get(i)];
}
int maxAt = 1;
for (int i = 2; i < freq.length; i++) {
if (freq[i] > freq[maxAt]) {
maxAt = i;
}
}
return maxAt;
}
We can determine the type number of the most common bird in one loop. This has the time complexity O(n).
static int migratoryBirds(int[] arr) {
int highestFrequency = 0;
int highestFrequencyBirdType = 0;
int[] frequencies = new int[5]; // there are 5 bird types
for (int birdType : arr) {
int frequency = ++frequencies[birdType - 1];
if (frequency > highestFrequency) {
highestFrequency = frequency;
highestFrequencyBirdType = birdType;
} else if (frequency == highestFrequency && birdType < highestFrequencyBirdType) {
highestFrequencyBirdType = birdType;
}
}
return highestFrequencyBirdType;
}
For each element in the array arr we update the overall highestFrequency and are storing the corresponding value representing the highestFrequencyBirdType . If two different bird types have the highest frequency the lower type (with the smallest ID number) is set.
I am very new to Java and I was trying to solve this problem on Hackerrank:
Here's the task:
https://www.hackerrank.com/challenges/cut-the-sticks
You are given N sticks, where the length of each stick is a positive
integer. A cut operation is performed on the sticks such that all of
them are reduced by the length of the smallest stick.
Suppose we have six sticks of the following lengths:
5 4 4 2 2 8
Then, in one cut operation we make a cut of length 2 from each of the six
sticks. For the next cut operation four sticks are left (of non-zero length), > whose lengths are the following:
3 2 2 6
The above step is repeated until no sticks are left.
Given the length of N sticks, print the number of sticks that are left before > each subsequent cut operations.
Note: For each cut operation, you have to recalcuate the length of smallest
sticks (excluding zero-length sticks).
Here is my attempt at it, but it doesnt seem to be working. The output gets stuck in while loop (4 gets printed out infinitely)
import java.io.*;
import java.util.*;
public class Solution {
private static int findMin (int[] A)
{
int min = A[0];
for (int i =0; i<A.length; i++)
{
if (A[i] < min)
{
min = A[i];
}
}
return min;
}
private static int countNonZeros (int[] A)
{
int zeros = 0;
for (int i =0; i<A.length; i++)
{
if (A[i] == 0)
{
zeros++;
}
}
int nonZeros = A.length - zeros;
return nonZeros;
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
int[] A = new int[n];
for (int i=0; i<n; i++)
{
A[i] = scanner.nextInt();
}
int nums = countNonZeros(A);
while (nums > 0)
{
int mins = findMin(A);
for (int j = 0; j<A.length; j++)
{
A[j]=A[j]-mins;
}
nums = countNonZeros(A);
System.out.println(nums);
}
}
}
Any help is appreciated
(PS I know I can just look the solution up somewhere, but I want to know why my code isn't working)
The problem that you have is that your findMin is not excluding zero-length elements, so once you have a zero that will be the min, and as a result an iteration of the while loop will be the same as the previous iteration, having subtracted 0 from each of the elements of A.
I tried to find the smallest element in an integer array using what i understood about divide and conquor algorithm.
I am getting correct results.
But i am not sure if it is a conventional way of using divide and conquor algorithm.
If there is any other smarter way of implementing divide and conquor algorithm than what i have tried then please let me know it.
public static int smallest(int[] array){
int i = 0;
int array1[] = new int[array.length/2];
int array2[] = new int[array.length - (array.length/2)];
for(int index = 0; index < array.length/2 ; index++){
array1[index] = array[index];
}
for(int index = array.length/2; index < array.length; index++){
array2[i] = array[index];
i++;
}
if(array.length > 1){
if(smallest(array1) < smallest(array2)){
return smallest(array1);
}else{
return smallest(array2);
}
}
return array[0];
}
Your code is correct, but You can write less code using existing functions like Arrays.copyOfRange and Math.min
public static int smallest(int[] array) {
if (array.length == 1) {
return array[0];
}
int array1[] = Arrays.copyOfRange(array, 0, array.length / 2);
int array2[] = Arrays.copyOfRange(array, array.length / 2, array.length);
return Math.min(smallest(array1), smallest(array2));
}
Another point. Testing for the length == 1 at the beginning is more readable version. Functionally it is identical. From a performance point of view it creates less arrays, exiting as soon as possible from the smallest function.
It is also possible to use a different form of recursion where it is not necessary to create new arrays.
private static int smallest(int[] array, int from, int to) {
if (from == to) {
return array[from];
}
int middle = from + (to - from) / 2;
return Math.min(smallest(array, from, middle), smallest(array, middle + 1, to));
}
public static int smallest(int[] array){
return smallest(array, 0, array.length - 1);
}
This second version is more efficient because it doesn't creates new arrays.
I don't find any use in using a divide and conquer in this paticular program.
Anyhow you search for the whole array from 1 to N, but in two steps
1. 1 to N / 2
2. N / 2 + 1 to N
This is equivalent to 1 to N.
Also you program check for few additional checks after the loops which aren't actually required when you do it directly.
int min = a[0];
for(int i = 1; i < arr.length; i++)
if(min < a[i])
a[i] = min;
This is considered most efficient in finding out the minimum value.
When do I use divide and conquer
A divide and conquer algorithm works by recursively breaking down a problem into two or more sub-problems, until these become simple enough to be solved directly.
Consider the Merge Sort Algorithm.
Here, we divide the problem step by step untill we get smaller problem and then we combine them to sort them. In this case this is considered optimal. The normal runs in a O(n * n) and this runs in O(n log n).
But in finding the minimum the original has O(n). So this is good.
Divide And Conquer
The book
Data Structures and Algorithm Analysis in Java, 2nd edtition, Mark Allen Weiss
Says that a D&C algorithm should have two disjoint recursive calls. I.e like QuickSort. The above algorithm does not have this, even if it can be implemented recursively.
What you did here with code is correct. But there are more efficient ways of solving this code, of which i'm sure you're aware of.
Although divide and conquer algorithm can be applied to this problem, but it is more suited for complex data problem or to understand a difficult data problem by dividing it into smaller fragments. One prime example would be 'Tower of Hanoi'.
As far as your code is concerned, it is correct. Here's another copy of same code-
public class SmallestInteger {
public static void main(String[] args) {
int small ;
int array[] = {4,-2,8,3,56,34,67,84} ;
small = smallest(array) ;
System.out.println("The smallest integers is = " + small) ;
}
public static int smallest(int[] array) {
int array1[] = new int[array.length/2];
int array2[] = new int[array.length - (array.length/2)];
for (int index = 0; index < array.length/2 ; index++) {
array1[index] = array[index];
}
for (int index = array.length/2; index < array.length; index++) {
array2[index - array.length/2] = array[index] ;
}
if (array.length > 1) {
if(smallest(array1) < smallest(array2)) {
return smallest(array1) ;
}
else {
return smallest(array2) ;
}
}
return array[0] ;
}
}
Result came out to be-
The smallest integers is = -2
Preface: This isn't for homework, but it is for a "coding challenge", it's not worth any points in my course but i would like a fuller understanding of arrays and loops so i want this to work before i move on in the course.
So here's my problem. I'm trying to design a method that reverse sorts an array and places the numbers from highest to lowest. The code i have now is :
public static void selectionReverseSort (int[] array)
{
int startScan, index, maxIndex, maxValue;
for (startScan = 0; startScan < (array.length - 1); startScan++)
{
maxIndex = startScan;
maxValue = array[startScan];
for(index = startScan + 1; index < array.length; index++)
//index is 1
{
if (array[index] > maxValue)
{
maxValue = array[index];
//maxValue now becomes the second array number
maxIndex = index;
//maxIndex becomes the current index number.
}
array[maxIndex] = array[startScan];
array[startScan] = maxValue;
}
}
}
The problem with this code, is that it seems to only reverse sort the arrays if they were in ascending order to start with, otherwise it just repeats the highest number for the first few array slots. Anyone wanna help me understand what's going on here and what i could do to fix this?
Your algorithm is correct. But you are swapping unnecessarily even if the you have a small number. I updated you logic.
import java.io.*;
public class Hey{
public static void main(String args[])throws IOException{
int []ar = {1,2,5,4,6,8,7,9,10};
selectionReverseSort(ar);
}
public static void selectionReverseSort (int[] array){
int startScan, index, maxIndex, maxValue;
for (startScan = 0; startScan < (array.length - 1); startScan++){
maxIndex = startScan;
maxValue = array[startScan];
for(index = startScan + 1; index < array.length; index++){
//index is 1
if (array[index] > maxValue){
maxValue = array[index];
//maxValue now becomes the second array number
maxIndex = index;
//maxIndex becomes the current index number.
//swap only if the condition is true
array[maxIndex] = array[startScan];
array[startScan] = maxValue;
}
}
}
}
for(int i = 0; i < array.length; i++ )
System.out.println(array[i]+"");
}
}
And I suggest you to use any other better sorting algorithm than Insertion sort.
It appears that the algorithm you've chosen is to find the largest value in the array, then use a swap to move the largest value to the first position in the array. Then you do the same for the subarray starting with the second element, then with the subarray starting with the third, and so on.
This will work, but your code does the swap too early. You need to wait until your inner loop is done finding the largest element before you do the swap. I haven't tested it, but I think all you need to do is move these two statements:
array[maxIndex] = array[startScan];
array[startScan] = maxValue;
outside of the inner loop.
This is just a one-line solution by using java API:
public static void selectionReverseSort (int[] array){
Collections.sort(Arrays.asList(array),Collections.reverseOrder());
}
Keep it for future purpose :).
So the problem I'm working on solving involves an array list of array list of integers
. What is known: The number of elements in each ArrayList of integers. What is NOT known: How many ArrayList of Integers there actually are. I need suggestions for an algorithm that would sum the (ordered) elements of these arrays in every combination possible OF the arrays. In order to clarify what I mean by this let me give an example:
AoA = [[1,0,1,0],[0,1,0,1],[1,1,1,1],[0,0,0,0]];
Sum the elements of AoA[0] + AoA[1]; AoA[0]+AoA[2]; AoA[0]+AoA[3]; AoA[1]+AoA[2]; AoA[1]+AoA[3]; AoA[2]+AoA[3];
(4 choose 2)
So if anyone could code this simple version I'd be grateful as I'm struggling to do it. If anyone could code the more complex example where there's an unknown number of arrays in the AoA (so N choose 2), you'd be my hero.
TL;DR/edit
I need an algorithm to take n-choose-2 arrays from an array of arrays; sum the arrays (e.g. [1,2,3] + [1,2,3] = [2,4,6]); put the add the new summed array into an array of arrays.
If the 2 is fixed then the easiest thing I can think about is just generating the new array with N*(N-1)/2 rows, one for each sum and then using two variables to iterate through the original array with something like:s
int c = 0;
for (int i = 0; i < N; i++) {
for (int j = i + 1; j < N; j++) {
for (int k = 0; k < M; k++) {
sums[c][k] = AoA[i][k] + AoA[j][k];
}
c++;
}
}
Here's what I've got, took me a while but this will do what I was looking for:
it takes each combination of the arrays (t1, t2, t3, t4) and adds their elements and returns whatever combinatorial you choose for n, (in this example i left it as 3).
If there's any more optimizations you can see please feel free to add it. I'm a perl guy so making this work at all in Java was a real task.
import java.util.ArrayList;
public class testnCk {
public static void main(String[] args) {
ArrayList<int[]> sums = new ArrayList<int[]>();
int [] t1 = {1,1,0,0};
int [] t2 = {1,0,0,1};
int [] t3 = {0,0,0,0};
int [] t4 = {0,0,1,1};
ArrayList<int[]> testing = new ArrayList<int[]>();
testing.add(t1);
testing.add(t2);
testing.add(t3);
testing.add(t4);
int n = 3;
int i = -1;
int[] array = new int[4];
ArrayList<int[]> whatever = nCk(testing, sums, array, i, n);
for (int[] test1 : whatever)
{
for (int j = 0; j < test1.length; j++) {
System.out.print(test1[j]);
}
System.out.println();
}
}
public static ArrayList<int[]> nCk (ArrayList<int[]> arrayOfDiffPatterns, ArrayList<int[]> solutions, int[] tempsums, int i, int n)
{
n--;
for (int j=i+1; j<arrayOfDiffPatterns.size(); j++){
int[] array = tempsums.clone();
for (int k=0; k<arrayOfDiffPatterns.get(0).length; k++){
array[k] += arrayOfDiffPatterns.get(j)[k];
}
if(n>0){
nCk(arrayOfDiffPatterns, solutions, array, j, n);
}
else{
solutions.add(array);
}
}
return solutions;
}
}