Print Array Combination - java

I have the following input
int combinationCount = 3;
int arr[] = {1, 1, 2, 2, 3};
combinationCount is {1,2,3}, combinationCount defines the number of sequence of number. For Eg: combinationCount = 3 means {1,2,3} and combinationCount = 2 means {1,2}
Array is always sorted, I want to print the output as the number of combinations as follow
[1,2,3], [1,2,3], [1,2,3], [1,2,3] //I have to iterate the whole array as it is just logic for a problem
Output Explanation (I want to print values, not index):
This is just an explanation of output which shows the index position of the value printed.
Index position of each value
[0, 2, 4], [0, 3, 4], [1, 2, 4], [1, 3, 4]
Example 2
int combinationCount = 2; // means combination is {1,2}
int arr[] = {1, 2, 2};
Print: [1,2], [1,2]
Example 3
int combinationCount = 3; // means combination is {1,2,3}
int arr[] = {1, 1, 3};
Print nothing
The program which I written is as follow:
int combinationCount = 3;
int arr[] = {1, 1, 2, 2, 3};
List<Integer> list = new ArrayList<>();
int prev = 0;
for (int i = 0; i < arr.length; i++) {
if (arr[i] == 1) {
prev = 1;
list = new ArrayList<>();
list.add(1);
for (int j = i + 1; j < arr.length; j++) {
if (arr[j] == prev + 1) {
prev = arr[j];
list.add(arr[j]);
} else if (arr[j] > (prev + 1)) {
break;
}
}
if (list.size() == combinationCount) {
System.out.print(list + ",");
}
} else {
break;
}
}
Output coming as
[1,2,3],[1,2,3]
which is not correct
Somewhere I am missing loop and how optimized code we can write? Any suggestions pls. Kindly let me know for any concern.

You can use Cartesian Product. I have used this answer as reference.
public class Test {
public static List<List<Integer>> product(List<List<Integer>> lists) {
List<List<Integer>> result = new ArrayList<>();
int solutions = lists.stream().mapToInt(List::size).reduce(1, (a, b) -> a * b);
for (int i = 0; i < solutions; i++) {
int j = 1;
List<Integer> tempList = new ArrayList<>();
for (List list : lists) {
tempList.add((Integer) list.get((i / j) % list.size()));
j *= list.size();
}
result.add(tempList);
}
return result;
}
public static void main(String[] args) {
int combinationCount = 2, count = 0;
int arr[] = {1, 1, 3};
Map<Integer, List<Integer>> map = new HashMap<>();
List<List<Integer>> combinations = new ArrayList<>();
for (Integer idx = 0; idx < arr.length; idx++) {
map.computeIfAbsent(arr[idx], k -> new ArrayList<>()).add(idx);
}
for (int i = 1; i <= combinationCount; i++) {
if (map.getOrDefault(i, null) != null)
count += 1;
}
if (count == combinationCount) {
List result = product(new ArrayList(map.values()));
System.out.println(result);
} else {
System.out.println("No combination found");
}
}
}
Output:
No combination found

Related

Rank values of an Array

I have this input of array: int[] input = {1,3,2,2,33,1}; I need to make score for it like this output: {1,3,2,2,4,1} so the smallest number gets 1 and if there is smaller it gets 2 an so on.
another example: for input {1,10,3,44,5,2,5} -outputs-> {1,5,3,6,4,2,4}
This is my try but it does not work as expected.
public static int[] getRanksArray(int[] array) {
int[] result = new int[array.length];
for (int i = 0; i < array.length; i++) {
int count = 0;
for (int j = 0; j < array.length; j++) {
if (array[j] != array[i]) {
count++;
}
}
result[i] = count + 1;
}
return result;
}
Edit: Updated to handle double rather than int input array.
First sort an array representing indices of the input array. Then walk through this array incrementing a rank counter whenever you encounter successive elements that are not equal (ideone)
public static int[] rank(double[] nums)
{
Integer[] idx = new Integer[nums.length];
for(int i=0; i<idx.length; i++) idx[i] = i;
Arrays.sort(idx, (a, b) -> (Double.compare(nums[a], nums[b])));
// Or use this for descending rank
// Arrays.sort(idx, (a, b) -> (Double.compare(nums[b], nums[a])));
int[] rank = new int[nums.length];
for(int i=0, j=1; i<idx.length; i++)
{
rank[idx[i]] = j;
if(i < idx.length - 1 && nums[idx[i]] != nums[idx[i+1]]) j++;
}
return rank;
}
Test:
System.out.println(Arrays.toString(rank(new double[] {1,3,2,2,33,1})));
System.out.println(Arrays.toString(rank(new double[] {1,10,3,44,5,2,5})));
Output:
[1, 3, 2, 2, 4, 1]
[1, 5, 3, 6, 4, 2, 4]
This can be solved using a sorted map storing lists/sets of indexes mapped by the values of the input array.
Then you can iterate over this map and fill the rank array with incrementing indexes.
Implementation:
public static int[] rank(int[] arr) {
TreeMap<Integer, List<Integer>> map = new TreeMap<>();
for (int i = 0; i < arr.length; i++) {
List<Integer> indexes = map.compute(arr[i], (k, v) -> v == null ? new ArrayList<>() : v);
indexes.add(i);
map.putIfAbsent(arr[i], indexes);
}
int[] rank = new int[arr.length];
int id = 1;
for (Map.Entry<Integer, List<Integer>> entry : map.entrySet()) {
for(Integer i : entry.getValue()) {
rank[i] = id;
}
id++;
}
return rank;
}
Test:
int[][] d = {
{1,3,2,2,33,1},
{1,10,3,44,5,2,5}
};
for (int[] input : d) {
System.out.println(Arrays.toString(rank(input)));
}
output:
[1, 3, 2, 2, 4, 1]
[1, 5, 3, 6, 4, 2, 4]

How to get all possible combinations of elements of one (int) array?

I've been writing code to get all combinations of elements from array, but I couldn't figure out how to do it. Can you guys give me some advice?
This is what I'm trying to do...
int[] num = {1, 2, 3, 4, 5};
int n = num.length;
int length = (n * (n - 1)) / 2;
int[] list = new int[length];
for (int j = 0; j < n - 1; j++) {
for (int p = 4;p < n; p--) {
for (int i = 0; (I < length); i++) {
list[i] = Math.abs(num[j] - num[j + p]);
}
p++;
}
}
My result list would look like this..
list = {1, 2, 3, 4, 1, 2, 3, 1, 2, 1};
Thank you in advance.
edit: I'm really sorry that I didn't post my question clearly. What I was trying to do is get the absolute value of subtracting each values from array.
ex) 1-2 , 1-3, 1-4, 1-5, 2-3, 2-4, 2-5, 3-4, 3-5, 4,5
for (int v : list) {
System.out.println(v);
}
output:
1
2
3
4
1
2
...
Do it as follows:
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
int[] num = { 1, 2, 3, 4, 5 };
int n = num.length;
int length = (n * (n - 1)) / 2;
int[] list = new int[length];
// Index counter for list[]
int c = 0;
for (int i = n - 1; i >= 0; i--) {
for (int j = 0; j < i; j++) {
list[c++] = num[j];
}
}
// Display
System.out.println(Arrays.toString(list));
}
}
Output:
[1, 2, 3, 4, 1, 2, 3, 1, 2, 1]
For any value n the following should work. The key is to base the termination point of the inner loop on the outer loop's termination point.
System.out.println(string);
int n = 5;
int[] num = {1, 2, 3, 4, 5};
int length = (n * (n - 1)) / 2;
int m = 0;
int[] list = new int[length];
for (int i = 1; i<n ; i++) {
for (int k = 1; k <= n-i; k++) {
list[m++] = num[k-1];
}
}
System.out.println(Arrays.toString(list));
Prints
1 2 3 4 1 2 3 1 2 1

Getting the Elements that has duplicates in an int array Java

This post - "Java + Count duplicates from int array without using any Collection or another intermediate Array", was also a sample exercise in my book at school, but what I want to do is get the elements that has duplicates without sorting it.
What I did is I removed the duplicates of arrays first, to get only the unique elements and then I compare it to the original array and count how many times the element has been found. But the problem is it doesn't print the correct elements which has duplicates.
int[] num = {7, 2, 6, 1, 4, 7, 4, 5, 4, 7, 7, 3, 1};
the correct output should be: 7, 1, 4
but instead it outputs: 7, 6, 1
This is my codes:
//method for removing duplicates
public static int[] removeDuplicates(int[] n) {
int limit = n.length;
for(int i = 0; i < limit; i++) {
for(int j = i + 1; j < limit; j++) {
if(n[i] == n[j]) {
for(int k = j; k < limit - 1; k++) {
n[k] = n[k + 1];
}
limit--;
j--;
}
}
}
int[] uniqueValues = new int[limit];
for(int i = 0; i < uniqueValues.length; i++) {
uniqueValues[i] = n[i];
}
return uniqueValues;
}
//method for getting elements that has duplicates
public static int[] getDuplicatedElements(int[] n) {
int[] nCopy = n.clone();
int[] u = removeDuplicates(nCopy);
int count = 0;
int limit = u.length;
for(int i = 0; i < u.length; i++) {
for(int j = 0; j < n.length; j++) {
if(u[i] == n[j]) {
count++;
}
}
if(count == 1) {
for(int k = i; k < limit - 1; k++) {
u[k] = u[k + 1];
}
limit--;
}
count = 0;
}
int[] duplicated = new int[limit];
for(int i = 0; i < duplicated.length; i++) {
duplicated[i] = u[i];
}
return duplicated;
}
//main
public static void main(String[] args) {
int[] num = {7, 2, 6, 1, 4, 7, 4, 5, 4, 7, 7, 3, 1};
//printing original values
System.out.print(Arrays.toString(num));
System.out.println();
int[] a = getDuplicatedElements(num);
System.out.print("Elements with Duplicates: " + Arrays.toString(a));
}
What's the error in my codes here? Please help thanks...
You have two issues:
public static int[] getDuplicatedElements(int[] n) {
int[] nCopy = n.clone();
int[] u = removeDuplicates(nCopy);
System.out.println ("unique " + Arrays.toString (u));
int count = 0;
int limit = u.length;
for(int i = 0; i < limit; i++) { // you must use limit instead of u.length
// in order for the loop to terminate
for(int j = 0; j < n.length; j++) {
if(u[i] == n[j]) {
count++;
}
}
if(count == 1) {
for(int k = i; k < limit - 1; k++) {
u[k] = u[k + 1];
}
limit--;
i--; // you must decrement i after you find a unique element in u
// otherwise you'll be skipping elements in the u array
}
count = 0;
}
int[] duplicated = new int[limit];
for(int i = 0; i < duplicated.length; i++) {
duplicated[i] = u[i];
}
return duplicated;
}
With those fixes, you'll get the expected output:
Elements with Duplicates: [7, 1, 4]
It's fairly simple when using a stream
int[] num = {7, 2, 6, 1, 4, 7, 4, 5, 4, 7, 7, 3, 1};
List<Integer> list = Arrays.stream(num).boxed().collect(Collectors.toList());
list.stream().filter(i -> Collections.frequency(list, i) > 1)
.collect(Collectors.toSet()).forEach(System.out::println);

Find a sum pair in array with duplicates in O(n)

Array with duplicates [4,4,1]. Find pairs with sum 5 in O(n).
Expected output (4,1) and (4,1) and count is 2.
Approach#1:
Using HashSet:
public static int twoSum(int[] numbers, int target) {
HashSet<Integer> set = new HashSet<Integer>();
int c = 0;
for(int i:numbers){
if(set.contains(target-i)){
System.out.println(i+"-"+(target-i));
c++;
}
set.add(i);
}
return c;
}
Output is 1.
Approach #2 as stated in this link:
private static final int MAX = 100000;
static int printpairs(int arr[],int sum)
{
int count = 0;
boolean[] binmap = new boolean[MAX];
for (int i=0; i<arr.length; ++i)
{
int temp = sum-arr[i];
if (temp>=0 && binmap[temp])
{
count ++;
}
binmap[arr[i]] = true;
}
return count;
}
Output 1.
However the O(nlog n) solution is using sorting the array:
public static int findPairs(int [] a, int sum){
Arrays.sort(a);
int l = 0;
int r = a.length -1;
int count = 0;
while(l<r){
if((a[l] + a[r]) == sum){
count ++;
System.out.println(a[l] + " "+ a[r]);
r--;
}
else if((a[l] + a[r])>sum ){
r--;
}else{
l++;
}
}
return count;
}
Can we get the solution in O(n)?
You can use your second approach - just change boolean to int:
public static void main(String[] args) {
System.out.println(printPairs(new int[]{3, 3, 3, 3}, 6)); // 6
System.out.println(printPairs(new int[]{4, 4, 1}, 5)); // 2
System.out.println(printPairs(new int[]{1, 2, 3, 4, 5, 6}, 7)); // 3
System.out.println(printPairs(new int[]{3, 3, 3, 3, 1, 1, 5, 5}, 6)); // 10
}
public static int printPairs(int arr[], int sum) {
int count = 0;
int[] quantity = new int[sum];
for (int i = 0; i < arr.length; ++i) {
int supplement = sum - arr[i];
if (supplement >= 0) {
count += quantity[supplement];
}
quantity[arr[i]]++; // You may need to check that arr[i] is in bounds
}
return count;
}
you can try this also
Map<Integer, List> map = new HashMap<>();
int count = 0;
for (int i = 0; i < arr.length; i++) {
if (map.containsKey(k - arr[i])) {
count += map.get(k - arr[i]).size();
}
List<Integer> test = map.getOrDefault(arr[i], new ArrayList<>());
test.add(i);
map.put(arr[i], test);
}
return count;
Here is an O(N) Time & Space approach using HashMap.
class Solution
{
static int getPairsCount(int[] arr, int n, int target)
{
HashMap<Integer,Integer> map = new HashMap<>();
int pairs=0;
for (int i=0; i<n; i++)
{
if (map.containsKey(target - arr[i]))
{
pairs += map.get(target - arr[i]);
for (int j=1; j<=map.get(target - arr[i]); j++)
System.out.print("(" +(target-arr[i])+ "," +arr[i]+ ") ");
}
map.put(arr[i] , map.getOrDefault(arr[i],0)+1);
}
return pairs;
}
public static void main (String [] args)
{
int target = 5;
int [] input = {4, 4, 1};
System.out.println(getPairsCount(input , input.length , target));
target = 10;
input = new int [] {1, 6, 3, 2, 5, 5, 7, 8, 4, 8, 2, 5, 9, 9, 1};
System.out.println(getPairsCount(input , input.length , target));
}
}
Output:
2 (Pairs)
(4,1) (4,1)
13 (Pairs)
(5,5) (3,7) (2,8) (6,4) (2,8) (8,2) (8,2) (5,5) (5,5) (1,9) (1,9) (9,1) (9,1)

Sum consecutive even numbers and consecutive odd numbers in an array

I have a code that sums the consecutive even numbers and consecutive odd numbers, then adds them to an arraylist. This process should be repeated until there are no more consecutive odd or even numbers in the list. Then returns the size of the arraylist.
I used nested for loops and the problem is the loops check the same index which doesn't make sense.
Here's my code:
public static int SumGroups(int[] arr) {
ArrayList<Integer> arl = new ArrayList<Integer>();
int even = 0, odd = 0;
for (int i = 0; i < arr.length; i++) {
for (int j = i + 1; j < arr.length; j++) {
if (arr[i] % 2 == 0) {
even += arr[i];
if (arr[j] % 2 == 0) {
even += arr[j];
} else {
arl.add(even);
even = 0;
break;
}
} else {
odd += arr[i];
if (arr[j] % 2 != 0) {
odd += arr[j];
} else {
arl.add(odd);
odd = 0;
break;
}
}
}
}
return arl.size();
}
My Question is:
How to prevent loops from checking the same index ?
in other words, how to make my code sums the consecutive even numbers and consecutive odd numbers ?
Input:
int arr[]={2, 1, 2, 2, 6, 5, 0, 2, 0, 5, 5, 7, 7, 4, 3, 3, 9};
Output:
6 // [2, 1, 10, 5, 30, 15]
I think the following code should solve the problem, if you do not want to output the size simply return `sums` instead of `sums.size()`
public static int sumGroupsRecursively(int[] arr) {
List<Integer> numbersToSum = IntStream.of(arr).boxed().collect(Collectors.toList());
List<Integer> currentSumList = sumSublist(numbersToSum);
List<Integer> nextSumList = sumSublist(currentSumList);
while (currentSumList.size() != nextSumList.size()) {
currentSumList = nextSumList;
nextSumList = sumSublist(currentSumList);
}
return nextSumList.size();
}
public static List<Integer> sumSublist(List<Integer> list) {
int current = list.get(0);
int currentSum = 0;
List<Integer> sums = new ArrayList<>();
for (int i = 0; i < list.size(); i++) {
if (current % 2 == list.get(i) % 2) {
currentSum += list.get(i);
} else {
sums.add(currentSum);
current = list.get(i);
currentSum = current;
}
}
sums.add(currentSum);
return sums;
}
If you need to do this in one function what I would discourage because it is harder to read you could use code like this.
public static Integer sumSublist(int[] arr) {
List<Integer> sums = new ArrayList<>();
sums.add(0);
int i = 0;
while (i < arr.length - 1) {
int current = arr[i];
int currentSum = 0;
while (current % 2 == arr[i] % 2) {
currentSum += arr[i];
if (i >= arr.length - 1) {
break;
}
i++;
}
if (currentSum % 2 == sums.get(sums.size()-1) % 2) {
sums.set(sums.size() - 1, sums.get(sums.size()-1) + currentSum);
} else {
sums.add(currentSum);
}
}
return sums.size();
}
You are entering your first for loop passing in arr. Inside the first for loop you enter a second for loop passing in arr a second time. This means that you enter the second for loop as many times as there are elements in arr and transverse arr in the second for loop every single time.
for example, if arr.length() was 2 you would transverse arr 3 times. Once in your outer for loop and twice (once for each element in arr) in your inner loop.
Second, by adding both the odd and even numbers to your arraylist, you are doing nothing but reconstructing arr but in an arraylist rather than array. Therefor, returning arl.size() is the exact same as returning arr.length() which is already known and much easier to do.
Despite that, here is how I would calculate the sum of the odd and evens. I add both to different arraylists. You'll need to figure out exactly what you need to return though because your description is off.
public void test(){
int[] arr = new int[5];
arr[0] = 1;
arr[1] = 2;
arr[2] = 3;
arr[3] = 4;
arr[4] = 5;
int testOfEven = 6;
int testOfOdd = 9;
int sumOfEven = 0;
int sumOfOdd = 0;
ArrayList evens = new ArrayList<Integer>();
ArrayList odds = new ArrayList<Integer>();
for(int i = 0; i < arr.length; i++)
{
if ((arr[i]%2) == 0)
{
evens.add(arr[i]);
sumOfEven += arr[i];
}
else
{
odds.add(arr[i]);
sumOfOdd += arr[i];
}
}
assertEquals(testOfEven, sumOfEven);
assertEquals(testOfOdd, sumOfOdd);
}
after playing some time, here is my version:
public static int SumGroups(final int[] arr) {
if (arr.length > 0) {
int n, sum, psum;
psum = sum = n = arr[0] & 1; // parity of first number in sequence
int s = 1; // at least one element in array
int f = 0; // discard first parity change
for (int i = 1; i < arr.length; i++) {
if (n == (arr[i] & 1)) {
sum = (sum + n) & 1; // both even or odd, just increase sum
} else {
s += (psum ^ sum) & f; // compare sums parity
psum = sum; // store current sum's parity
sum = n = arr[i] & 1; // new first number in sequence
f = 1; // do not discard sums parity next time
}
}
s += (psum ^ sum) & f; // array ended, check parity of last sum
return s;
}
return 0;
}
I've put comments, but still some additional notes:
basic idea is the same as #PKuhn, just checked for some edge cases (empty array, integer overflow)
we don't need to have array of sums, we need just previous sum and check parity of it with newly calculated one
sum = (sum + n) & 1 - we don't need to calculate whole sum, we need just parity of the sum
s += (psum ^ sum) & f - we need to increase swap counter only if parity changed, xor helps us to get 1 if changed and 0 if not
Here is the list of tests which I've used:
Assert.assertEquals(6, SumGroups(new int[] { 2, 1, 2, 2, 6, 5, 0, 2, 0, 5, 5, 7, 7, 4, 3, 3, 9 }));
Assert.assertEquals(6, SumGroups(new int[] { 0, 0, 0, 0, 2, 1, 2, 2, 6, 5, 0, 2, 0, 5, 5, 7, 7, 4, 3, 3, 9 }));
Assert.assertEquals(1, SumGroups(new int[] { 2, 3, 3 }));
Assert.assertEquals(1, SumGroups(new int[] { 2 }));
Assert.assertEquals(1, SumGroups(new int[] { 2, 2 }));
Assert.assertEquals(1, SumGroups(new int[] { 2, 3, 3, 3, 3, 2 }));
Assert.assertEquals(2, SumGroups(new int[] { 3, 2, 2 }));
Assert.assertEquals(2, SumGroups(new int[] { 1, 3, 3, 2, 2 }));
Assert.assertEquals(2, SumGroups(new int[] { 1, 2, 3, 3, 2, 3, 3, 2 }));
Assert.assertEquals(1, SumGroups(new int[] { 3, 3, 2, 2 }));
Assert.assertEquals(1, SumGroups(new int[] { Integer.MAX_VALUE, Integer.MAX_VALUE }));
Assert.assertEquals(1, SumGroups(new int[] { Integer.MAX_VALUE, Integer.MAX_VALUE, 2 }));
Assert.assertEquals(1, SumGroups(new int[] { Integer.MAX_VALUE, Integer.MAX_VALUE, 3 }));
public void findEvenOdd(int a[]){
Boolean flip = false;
int sum = 0, i, m = 0;
for (i = 0; i < a.length; i++) {
if (flip) {
System.out.print(sum + "\t");
sum = a[i];
flip = !flip;
if (i + 1 < a.length && (a[i] % 2 != a[i + 1] % 2))
flip = !flip;
m++;
} else {
sum += a[i];
if (i + 1 < a.length && (a[i] % 2 != a[i + 1] % 2))
flip = !flip;
m++;
}
}
if(m!=a.length-1)
System.out.print(a[a.length-1] + "\t");
}

Categories

Resources