Looking for efficient way of splitting array into k-arrays - java

I am trying to create a program that takes an integer array in increasing order and split it into k non-empty arrays in increasing order which when combined into a single array produce the original array - the first array cannot contain any but the first or more digits (k1=[1,2,3] is valid but k1=[2,3,4] is not)
So far I have tried given a array[4,7,11,21,31] and k=3 hard-coding two for-loops that act as pointers on where to copy the items and copying part of the original array into the respected variables
int[] array = {1,2,3,4,5};
int k = 3;
int n = 5;
for(int i = 0; i <= n - k; i++){
for(int j = i+1; j < n-1; j++){
int[] k1 = Arrays.copyOfRange(array , 0, i+1);
int[] k2 = Arrays.copyOfRange(array , i+1, j+1);
int[] k3 = Arrays.copyOfRange(array , j+1, n);
}
}
The above code works for k=3 but the problem is that I do not know how to efficiently make it work for any k and efficiently store the arrays
The end goal is to generate all possible combinations

This recursive brute-force approach doesn't really split an array of numbers, it just returns the indices of the array entries where the splits have to happen.
It takes two arguments:
n the length of the array
k the number of parts wanted
It will return an ArrayList<int[]> that contains all possible combinations of splits (each of those as an array of indices with k-1 elements in ascending order).
I have tried some cases and it seems to work. As expected, it always seems to return the binomial coefficient (n-1) over (k-1) amount of combinations. This is because in any array with length n there are n-1 places where it could be split into two. We only want to split it k-1 times, though (to end up with k parts). So this is basically selecting k-1 from n-1, thus the binomial coefficient.
public static ArrayList<int[]> getSplits(int n, int k) {
if (k == 1) {
return new ArrayList<int[]>();
}
ArrayList<int[]> newSplits = new ArrayList<int[]>();
for (int s = 1; s < n-(k-1)+1; s++) {
if (k == 2) {
newSplits.add(new int[] {s});
} else {
ArrayList<int[]> splits = getSplits(n-s, k-1);
for (int[] split : splits) {
int[] newSplit = new int[split.length + 1];
newSplit[0] = s;
for (int i = 0; i < split.length; i++) {
newSplit[i+1] = split[i] + s;
}
newSplits.add(newSplit);
}
}
}
return newSplits;
}
Used in the context of your question:
To get your array parts from this, you can use this function. It outputs them separated by pipe symbols (|).
public static void main(String args[]) {
int[] array = new int[] {1, 2, 3, 4};
int n = array.length;
int k = 3;
ArrayList<int[]> splits = getSplits(n, k);
for (int[] split : splits) {
int j = 0;
for (int i = 0; i < split.length; i++) {
for (; j < split[i]; j++) {
System.out.print(array[j] + " ");
}
System.out.print("| ");
}
for (; j < n; j++) {
System.out.print(array[j] + " ");
}
System.out.println();
}
}
This prints the following (all possibilites to split 4 items into 3 non-empty groups):
1 | 2 | 3 4
1 | 2 3 | 4
1 2 | 3 | 4

Related

LeetCode 1365 - looking for a better solution than O(n^2)

I am working leetcode problem number 1365. Here is the problem below in italicized characters:
Given the array nums, for each nums[i] find out how many numbers in the array are smaller than it. That is, for each nums[i] you have to count the number of valid j's such that j != i and nums[j] < nums[i].
Return the answer in an array.
Example 1: Input: nums = [8,1,2,2,3] Output: [4,0,1,1,3] Explanation: For nums[0]=8 there exist four smaller numbers than it (1, 2, 2 and 3). For nums[1]=1 does not exist any smaller number than it. For nums[2]=2 there exist one smaller number than it (1). For nums[3]=2 there exist one smaller number than it (1). For nums[4]=3 there exist three smaller numbers than it (1, 2 and 2).
https://leetcode.com/problems/how-many-numbers-are-smaller-than-the-current-number/
I am able to complete the task using brute force which gives an O(n^2) time. Is there a faster way to code this problem?
public static void main(String[] args) {
int[] nums = new int[] {8,1,2,2,3};
System.out.println(Arrays.toString(smallerNumbersThanCurrent(nums)));
}
public static int[] smallerNumbersThanCurrent(int[] nums) {
int[] result = new int[nums.length];
for (int x = 0; x < nums.length; x++) {
int ctr = 0;
for (int y = 0; y < nums.length; y++) {
if (nums[y] < nums[x]) {
ctr++;
}
result[x] = ctr;
}
}
return result;
}
A simple O(nlgn) solution with an O(n) space would be:
Copy the array into a temp array, O(n)
Sort the new array O(ngln)
Iterate over the original array
For every element, do a binary search over the sorted array and get the first index of the element.
The index would be the count you are after.
There is a slightly better O(n^2) approach, where you only compare each pair of indices once and updating the counts accordingly:
public static int[] smallerNumbersThanCurrent(int[] nums)
{
int[] result = new int[nums.length];
for (int x = 0; x < nums.length; x++)
{
for (int y = x + 1; y < nums.length; y++)
{
if (nums[y] < nums[x])
result[x]++;
else if (nums[y] > nums[x])
result[y]++;
}
}
return result;
}
However, at the cost of an additional array we can do it in O(ngln) by sorting the indices of the original array and then iterating through these sorted indices, updating the count accordingly. The only complication is in dealing with repeated numbers, e.g. the 2s in your example.
public static int[] smallerNumbersThanCurrent(int[] nums)
{
Integer[] idx = new Integer[nums.length];
for(int i=0; i<idx.length; i++) idx[i] = i;
Arrays.sort(idx, (a, b) -> (nums[a]-nums[b]));
int[] res = new int[nums.length];
for(int i=1; i<idx.length; i++)
{
if(nums[idx[i]] == nums[idx[i-1]])
res[idx[i]] = res[idx[i-1]];
else
res[idx[i]] = i;
}
return res;
}
Test:
int[] nums = new int[] {8,1,2,2,3};
System.out.println(Arrays.toString(smallerNumbersThanCurrent(nums)));
Output:
[4, 0, 1, 1, 3]

Algorithm to generate an array with n length and k number of inversions in O(n log n) time?

I'm writing an algorithm that will return an array with determined length and number of inversions (number pairs, where the left side number is larger than the right side number). I.e. array [3, 1, 4, 2] contains three inversions (3, 1), (3, 2) and (4, 2). So in practice, when given the length of n=3 and number of inversions k=3, the algorithm should generate an array [3, 1, 4, 2] (or another array that fulfills these requirements).
Since the number of inversions is also the number of swaps that has to be made for the array to be sorted in ascending order, I approached this problem by creating an array from 1 to n - 1 and using an insertion sort algorithm in reverse to make k swaps.
This approach works just fine for smaller inputs, but the algorithm should be able to efficiently generate arrays up to n=10^6 and k=n(n-1)/2 and anything in between, so the algorithm should be working in O(n log n) time instead of O(n^2). Below is the code:
import java.util.*;
public class Inversions {
public int[] generate(int n, long k) {
// Don't mind these special cases
if (n == 1) {
int[] arr = {1};
return arr;
}
if (k == 0) {
int[] arr = new int[n];
for (int i = 0; i < n; i++) {
arr[i] = 1;
}
return arr;
}
int[] arr = new int[n];
for (int i = 0; i < n; i++) {
arr[i] = i + 1;
}
int inversions = 0;
int i = 0;
while (inversions < k && i < n) {
int j = i - 1;
while (j >= 0 && arr[j] < arr[j + 1] && inversions < k) {
int helper = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = helper;
inversions++;
j--;
}
i++;
}
return arr;
}
}
And the main class for testing with different input arrays:
public class Main {
public static void main(String[] args) {
Inversions in = new Inversions();
int[] arr1 = in.generate(4,3);
int[] arr2 = in.generate(4,0);
int[] arr3 = in.generate(4,6);
System.out.println(Arrays.toString(arr1)); // [3,1,4,2]
System.out.println(Arrays.toString(arr2)); // [1,1,1,1]
System.out.println(Arrays.toString(arr3)); // [4,3,2,1]
}
}
The algorithm does not return exactly the same arrays as the sample results, but passes all the tests, except the ones where the input size is very large. I have also tried different variations with merge sort, since it's working in O(n log n time) but with no avail.
It would be great if you guys have some ideas. If you are not familiar with Java, doesn't matter, pseudocode or any other kinds of suggestions are more than welcome!
If you reverse the initial m elements in the array, you create m(m-1)/2 inversions.
If you reverse the initial m+1 elements, you create m(m+1)/2 inversions.
The difference between these is only m.
So:
Generate a sorted array
Find the largest m such that m(m-1)/2 <= k
Reverse the first m elements in the array to create m(m-1)/2 inversions
Shift the next element forward k - m(m-1)/2 positions to create the remaining required inversions.
This takes O(n) time, which is better than you require.
Another O(n) algorithm: Start with a sorted array. When you swap the first and last elements, you get x = 2 * (n-2) + 1 inversions. Consider these two elements fixed and work on the remaining array only. If x is too large, consider a smaller array. Repeat this as long as needed.
Untested code:
for (int first=0, last = n-1; remainingInversions>0; ) {
int x = 2 * (last-first-1) + 1;
if (x <= remainingInversion) {
first++;
last--;
remainingInversion -= x;
} else {
last--; // consider a smaller array
}
}
If k >= n - 1, put element n - 1 first in the array, so that it is inverted with n - 1 elements; otherwise put it last in the array, so that it is inverted with 0 elements. Continue this greedy approach to determine where the rest of the elements go.
Here's a solution that implements generate() to run in linear time with a little bit of math.
public class Inversions {
public static int[] generate(int n, long k) {
int[] array = new int[n];
// locate k in various sums of (n-1), (n-2), ..., 1
int a = (int) Math.sqrt((n * (n - 1) - 2 * k)); // between the sum of [(n-1)+...+(n-a)] and the sum of [(n-1)+...+(n-a-1)]
int b = n - 1 - a; // counts of (n-1), (n-2), ..., (n-a)
int c = (int) (k - n * b + (b * b + b) / 2); // spillover = k - [(n-1)+(n-b)]*b/2;
// put elements in the array
for (int i = 0; i < b; i++) {
array[i] = n - 1 - i;
}
for (int i = b; i < n - 1 - c; i++) {
array[i] = i - b;
}
array[n - 1 - c] = n - 1 - b;
for (int i = n - c; i < n; i++) {
array[i] = i - b - 1;
}
return array;
}
public static void main(String[] args) {
int n = Integer.parseInt(args[0]);
long k = Long.parseLong(args[1]);
for (int i = 0; i < n; i++) {
StdOut.print(generate(n, k)[i] + " ");
}
}
}
In fact, every time you exchange the last element with the one before it, the number of inversions increments. Here is a java solution:
public static int[] generate(int n, long k) {
int[] arr = new int[n];
for(int i = 0; i < n; i++) {
arr[i] = i;
}
long inversions = 0;
int j = (n-1);
int s = 0;
while(inversions < k) {
int temp = arr[j];
arr[j] = arr[j-1];
arr[j-1] = temp;
inversions++;
j--;
if(j == s) {
j = (n-1);
s++;
}
}
return arr;
}
I got an implementation in Python with O(n) complexity.
It is based on two rules.
Reversing an array of size m gives m*(m-1)/2 inversions.
Shifting an element by m positions, creates m inversions.
def get_m(k):
m=0
while m*(m-1)/2<=k:
m+=1
else:
m-=1
return m
def generate(l, k):
"""
Generate array of length l with k inversions.
"""
# Generate a sorted array of length l
arr = list(range(0,l))
# If no inversions are needed, return sorted array.
if k==0:
return arr
# Find largest m such that m*(m-1)/2 <= k
m=get_m(k)
# Reverse first m elements in the array which will give m*(m-1)/2 inversions
arr = arr[m-1::-1]+arr[m:]
# Calculate for any remaining inversions
remaining_k = k-(m*(m-1)/2)
# For remaining inversions, move the last element to its left by remaining_k
if remaining_k>0:
arr.insert(int(len(arr)-remaining_k - 1), arr[-1])
arr = arr[:-1]
return arr
if __name__ == '__main__':
l = int(sys.argv[1])
k = int(sys.argv[2])
arr = generate(l, k)
print(arr)
There's a very easy way to create n inversions...
That is to move the last element to the front.
It's not exactly efficient due to the additional memory used, but I would do something like this:
Create an array that is twice the length n.
Fill it from the start to the middle with a sentinel (i.e. null) if we use an Integer[] instead of int[].
Fill it from the middle, ascending.
Then do something like the below...
I'm sure I have off by one errors and other bugs but the general idea is captured in the below code.
int start = 0;
int mid = arr.length / 2;
int end = arr.length - 1;
while (v > 0)
{
if (v < (end - mid))
{
arr[start++] = arr[mid + v];
arr[mid + v] = null;
}
else
{
arr[start++] = arr[end];
v -= (end - mid);
end--;
}
}
So we have an array filled with the starting values, a bunch of nulls, then the original incremental values, with one that may have become null, and an "end" pointer that points to the middle of the original zone.
So the final step is to copy from 0 -> endPos, ignoring the nulls, to the final array.
The logic is not much difficult. For example, we have 10 numbers [0,1,2,3,4,5,6,7,8,9] say, to generate like 18 inversions. Firstly, insert 9 before 0, --->[9,0,1,2,3,4,5,6,7,8], which generates 9 inversions. Still 9 inversions left, so we insert 8 before 0, ---->[9,8,0,1,2,3,4,5,6,7], so we get additional 8 inversions. Finally, 1 inversions left, we insert 7 before 6----->[9,8,0,1,2,3,4,5,7,6]. I only use arrays in this case. This program works in O(n) complexity. The following code only considering n numbers (0,1,2.....n-1) and their inversions.
public static int[] generate(int n, long k) {
int[] a = new int[n];
int[] b = new int[n];
for (int i = 1; i < n; i++) {
a[i] = 1 + a[i - 1];
}
if (n == 0 || k == 0) return a;
else {
int i = 0;
while (k > 0) {
if (k > n - i - 1) {
b[i] = a[n - 1 - i];
}
else {
//auxilary array c to store value
int[] c = new int[(int) (k + 1)];
for (int j = i; j < n - 1 - k; j++) {
b[j] = j - i;
}
for (int j = (int) (n - 1 - k); j < n; j++) {
c[j - (int) (n - 1 - k)] = j - i;
}
b[(int) (n - 1 - k)] = c[(int) k];
for (int j = (int) (n - k); j < n; j++) {
b[j] = c[j - (int) (n - k)];
}
break;
}
k = k - (n - 1 - i);
i++;
}
return b;
}
}
#zhong yang: It works nicely in the expected range 0 <= k <= n(n-1)/2 but it should be better to throw either an exception or null if k is out of this range instead of returning some array!

Given two sorted lists (or arrays) and a number k, create an algorithm to fetch the least k numbers of the two lists

Need to find the first 3 smallest number in given two sorted array. I supposed that two array should merge into one first and sort it in order to fetch the first 3 smallest number. Can anyone help me with the merge and sort part or provide some advice, any help will appreciate.
This is where i reached now, I only can get the smallest number ( not first 3, just one).
public class MergeandSort {
public static void main(String[] args) {
int[] set1 = {1,2,6,9,18};
int[] set2 = {2,3,7,10,21,30};
int smallest = set1[0];
int smallests = set2[0];
for(int i=0; i < set1.length; i++){
if(set1[i] < smallest)
smallest = set1[i];
}
for(int k=0; k < set2.length; k++){
if(set2[k] < smallests)
smallests = set2[k];
}
System.out.println("Smallest Number in Set 1 is : " + smallest);
System.out.println("Smallest Number in Set 2 is : " + smallests);
}
}
The arrays are already sorted, so you don't have to iterate over the entire arrays to find the 3 smallest numbers.
You just have to start iterating over both arrays at the same time (i.e. in the same loop).
In each iteration you compare the current two elements of the two arrays (starting at the 2 elements at the 0 index) and take the smaller of them
Then you advance the index of the array from which you took the smallest number.
Once you reach 3 elements (after 3 iterations), you break out of the loop.
Here's some pseudo code to get you started:
int i = 0;
int j = 0;
int c = 0;
int[] lowest3 = new int[3];
while (true) {
find the smaller of set1[i] and set2[j] and put it in lowest3[c]
if set1[i] is smaller, increment i
otherwise increment j
increment c
if (c==3) // you are done
break;
}
the lowest3 array now contains the 3 lowest numbers of both arrays
Of course you can swap 3 with any k. You just have to make sure that i is always smaller than set1.length and j is always smaller than set2.length.
If the arrays are already sorted, just implement the merging technique of merge sort with the limitation in while condition that it should run only k times (in this case 3), but dont forget to check that size of sets are less than k or not!
int k = 0,i = 0,j = 0;
while (k<3 && k<set1.length && k<set2.length )
{
if (set1[i] <= set2[j])
{
final_set[k] = set1[i];
i++;
}
else
{
final_set[k] = set2[j];
j++;
}
k++;
}
while (k<3 && k<set1.length) {
final_set[k]=set1[i];
k++;
i++;
}
while (k<3 && k<set2.length) {
final_set[k]=set1[j];
k++;
j++;
}
public class MergeandSort {
public static void main(String[] args) {
int[] set1 = {1,2,6,9,18};
int[] set2 = {2,3,7,10,21,30};
int[] sorted = new int[k];
int smallest = set1[0];
int smallests = set2[0];
int i = 0, j = 0, c = 0;
while(i < set1.length && j < set2.length && c < k){
if (set1[i] < set2[j])
sorted[c++] = arr1[i++];
else
sorted[c++] = arr2[j++];
while (i < set1.length && c < k)
sorted[c++] = arr1[i++];
while (j < set2.length && c < k)
sorted[c++] = arr2[j++];
System.out.println(sorted);
}
}
where k is the count of sorted numbers you want
That would not work as:
Array1 = {1,3,5}
Array2 = {2,3,4}
Correct solution: {1,2,3}
Output of your solution: {1,3,4}

Getting the most "popular" number from array

I need for homework to get the most "popular" number in an array (the number in the highest frequency), and if there are several numbers with the same number of shows, get some number randomly.
After more then three hours of trying, and either searching the web, this is what I got:
public int getPopularNumber(){
int count = 1, tempCount;
int popular = array[0];
int temp = 0;
for ( int i = 0; i < (array.length - 1); i++ ){
if ( _buses[i] != null )
temp = array[i];
tempCount = 0;
for ( int j = 1; j < _buses.length; j++ ){
if ( array[j] != null && temp == array[j] )
tempCount++;
}
if ( tempCount > count ){
popular = temp;
count = tempCount;
}
}
return popular;
}
This code work, but don't take into account an important case- if there is more than one number with the same count of shows. Then it just get the first one.
for example: int[]a = {1, 2, 3, 4, 4, ,5 ,4 ,5 ,5}; The code will grab 4 since it shown first, and it's not random as it should be.
Another thing- since it's homework I can't use ArrayList/maps and stuff that we still didn't learn.
Any help would be appreciated.
Since they didn't give you any time complexity boundary, you can "brute force" the problem by scanning the the array N^2 times. (disclaimer, this is the most intuitive way of doing it, not the fastest or the most efficient in terms of memory and cpu).
Here is some psuedo-code:
Create another array with the same size as the original array, this will be the "occurrence array"
Zero its elements
For each index i in the original array, iterate the original array, and increment the element in the occurrence array at i each time the scan finds duplicates of the value stored in i in the original array.
Find the maximum in the occurrence array
Return the value stored in that index in the original array
This way you mimic the use of maps with just another array.
If you are not allowed to use collection then you can try below code :
public int getPopularNumber(){
int inputArr[] = {1, 2, 3, 4, 4, 5 ,4 ,5 ,5}; // given input array
int[] tempArr = new int[inputArr.length];
int[] maxValArr = new int[inputArr.length];
// tempArr will have number as index and count as no of occurrence
for( int i = 0 ; i < inputArr.length ; i++){
tempArr[inputArr[i]]++;
}
int maValue = 0;
// find out max count of occurrence (in this case 3 for value 4 and 5)
for( int j = 0 ; j < tempArr.length ; j++){
maValue = Math.max(maValue, tempArr[j]);
}
int l =0;
// maxValArr contains all value having maximum occurrence (in this case 4 and 5)
for( int k = 0 ; k < tempArr.length ; k++){
if(tempArr[k] == maValue){
maxValArr[l] = k;
l++;
}
}
return maxValArr[(int)(Math.random() * getArraySize(maxValArr))];
}
private int getArraySize(int[] arr) {
int size = 0;
for( int i =0; i < arr.length ; i++){
if(arr[i] == 0){
break;
}
size++;
}
return size;
}
that's hard as hell :D
After some trying, I guess I have it (If there will be 2 numbers with same frequency, it will return first found):
int mostPopNumber =0;
int tmpLastCount =0;
for (int i = 0; i < array.length-1; i++) {
int tmpActual = array[i];
int tmpCount=0;
for (int j = 0; j < array.length; j++) {
if(tmpActual == array[j]){
tmpCount++;
}
}
// >= for the last one
if(tmpCount > tmpLastCount){
tmpLastCount = tmpCount;
mostPopNumber = tmpActual;
}
}
return mostPopNumber;
--
Hah your code give me idea- you cant just remember last most popular number, btw I've found it solved there Find the most popular element in int[] array
:)
EDIT- after many, and many years :D, that works well :)
I've used 2D int and Integer array - you can also use just int array, but you will have to make more length array and copy actual values, Integer has default value null, so that's faster
Enjoy
public static void main(String[] args) {
//income array
int[] array= {1,1,1,1,50,10,20,20,2,2,2,2,20,20};
//associated unique numbers with frequency
int[][] uniQFreqArr = getUniqValues(array);
//print uniq numbers with it's frequency
for (int i = 0; i < uniQFreqArr.length; i++) {
System.out.println("Number: " + uniQFreqArr[i][0] + " found : " + uniQFreqArr[i][1]);
}
//get just most frequency founded numbers
int[][] maxFreqArray = getMaxFreqArray(uniQFreqArr);
//print just most frequency founded numbers
System.out.println("Most freq. values");
for (int i = 0; i < maxFreqArray.length; i++) {
System.out.println("Number: " + maxFreqArray[i][0] + " found : " + maxFreqArray[i][1]);
}
//get some of found values and print
int[] result = getRandomResult(maxFreqArray);
System.out.println("Found most frequency number: " + result[0] + " with count: " + result[1]);
}
//get associated array with unique numbers and it's frequency
static int[][] getUniqValues(int[] inArray){
//first time sort array
Arrays.sort(inArray);
//default value is null, not zero as in int (used bellow)
Integer[][] uniqArr = new Integer[inArray.length][2];
//counter and temp variable
int currUniqNumbers=1;
int actualNum = inArray[currUniqNumbers-1];
uniqArr[currUniqNumbers-1][0]=currUniqNumbers;
uniqArr[currUniqNumbers-1][1]=1;
for (int i = 1; i < inArray.length; i++) {
if(actualNum != inArray[i]){
uniqArr[currUniqNumbers][0]=inArray[i];
uniqArr[currUniqNumbers][1]=1;
actualNum = inArray[i];
currUniqNumbers++;
}else{
uniqArr[currUniqNumbers-1][1]++;
}
}
//get correctly lengthed array
int[][] ret = new int[currUniqNumbers][2];
for (int i = 0; i < uniqArr.length; i++) {
if(uniqArr[i][0] != null){
ret[i][0] = uniqArr[i][0];
ret[i][1] = uniqArr[i][1];
}else{
break;
}
}
return ret;
}
//found and return most frequency numbers
static int[][] getMaxFreqArray(int[][] inArray){
int maxFreq =0;
int foundedMaxValues = 0;
//filter- used sorted array, so you can decision about actual and next value from array
for (int i = 0; i < inArray.length; i++) {
if(inArray[i][1] > maxFreq){
maxFreq = inArray[i][1];
foundedMaxValues=1;
}else if(inArray[i][1] == maxFreq){
foundedMaxValues++;
}
}
//and again copy to correctly lengthed array
int[][] mostFreqArr = new int[foundedMaxValues][2];
int inArr= 0;
for (int i = 0; i < inArray.length; i++) {
if(inArray[i][1] == maxFreq){
mostFreqArr[inArr][0] = inArray[i][0];
mostFreqArr[inArr][1] = inArray[i][1];
inArr++;
}
}
return mostFreqArr;
}
//generate number from interval and get result value and it's frequency
static int[] getRandomResult(int[][] inArray){
int[]ret=new int[2];
int random = new Random().nextInt(inArray.length);
ret[0] = inArray[random][0];
ret[1] = inArray[random][1];
return ret;
}

how to optimize query on how to count number of array elements that don't have values between them

I want to write a method that when supplied an array of ints will do the following. For each pair of array elements it will combine them and put them into a list of an inner class objects. Then it will compare each element in the array and check if it will fit between each pair values. (i.e. I have an array 0, 2, 4 it will make for example pair (0,4) and then it will check that value 2 is indeed between 0 and 4 and so for pair (4,0). When pair (0, 2) is evaluated it won't find anything and therefore counter will increase (and so for pair (2, 0)). I have constructed the following code to evaluate number of values that indeed will fit in pairs and I hoped then to get the total number of pairs that match my need by extracting it from the total number of pairs. Now I want to optimize this query (in case I have very big arrays with thousands of members and very big or negative integers e.g. 1,000,000,000 or - 2,000,000,000). Please let me know how to do that. Mainly please focus on optimization issues thank you.
import java.util.*;
import java.util.Map;
import java.lang.*;
public class Prac1 {
public int count(int[] A){
int k = 0;
class PTemp{
int first = 0;
int second = 0;
public PTemp(int first, int second){
this.first = first;
this.second = second;
}
}
List<PTemp> r = new ArrayList<PTemp>();
int z = 0;
for (int i = 0; i < A.length; i++) {
for (int j = i+1; j < A.length; j++) {
r.add(new PTemp(A[i], A[j]));
r.add(new PTemp(A[j], A[i]));
z = z + 2;
System.out.println("["+A[i] +","+A[j]+"]");
System.out.println("["+A[j] +","+A[i]+"]");
}
}
Iterator<PTemp> ir = r.iterator();
while (ir.hasNext()){
PTemp p = ir.next();
label1:
for (int i = 0; i < A.length-1; i++){
if (((p.first < A[i]) && (A[i] < p.second)) || ((p.first > A[i]) && (A[i] > p.second))){
k = k + 1;
break label1;
}
}
}
System.out.println(z);
k = z - k;
return k;
}
public int c(int[] A) {
int z = (A.length - 1) * 2;
return z;
}
public static void main(String[] args){
int[] A = {0, 2, 2, 6, 5, 5};
Prac1 pr = new Prac1();
System.out.println(pr.count(A));
System.out.println(pr.c(A));
}
}
Without loss of generality, we can consider the array to be sorted. Assuming all numbers in the array are distinct, the pairs without elements in between are the pairs formed by neighbours. There are (array.length - 1) * 2 such pairs, i.e. you could simply do:
public int count(int[] A) {
return (A.length - 1) * 2;
}
If the array may contain duplicates, you should specify how they are to be counted.
Sort the array. Make a single pass over the array, identifying groups of equal elements. For each such group, multiply the number of elements in the group, the number of smaller elements, and the number of larger elements. Add that to a running count.
public int count(int[] A) {
int i = 0, k = 0, j = 0;
Arrays.sort(A); // you need to import java.util.Arrays
while(i < A.length) {
for(j = i+1; j < A.length && A[j] == A[i]; j++);
k += (j - i) * i * (A.length - j);
i = j;
}
return k;
}

Categories