I am having trouble removing the duplicates from two arrays that have been merged into one. I have written the following code that merges the arrays, yet I'm not sure how to remove the duplicates from the final array. Assume the arrays are already sorted.
public static int[] merge(int[] list1, int[] list2) {
int[] result = new int[list1.length + list2.length];
int i = 0;
int j = 0;
for (int k = 0; k < (list1.length + list2.length); k++) {
if (i >= list1.length) {
result[k] = list2[j];
j++;
}
else if (j >= list2.length) {
result[k] = list1[i];
i++;
}
else {
if (list1[i] < list2[j]) {
result[k] = list1[i];
i++;
} else {
result[k] = list2[j];
j++;
}
}
}
return result;
}
Ok, someone hated all the answers. Here's another attempt that combines two stackoverflow q's, combining arrays and removing dupes.
This one runs a good deal faster than my earlier attempt on two lists of a million ints.
public int[] mergeArrays2(int[] arr1, int[] arr2){
int[] merged = new int[arr1.length + arr2.length];
System.arraycopy(arr1, 0, merged, 0, arr1.length);
System.arraycopy(arr2, 0, merged, arr1.length, arr2.length);
Set<Integer> nodupes = new HashSet<Integer>();
for(int i=0;i<merged.length;i++){
nodupes.add(merged[i]);
}
int[] nodupesarray = new int[nodupes.size()];
int i = 0;
Iterator<Integer> it = nodupes.iterator();
while(it.hasNext()){
nodupesarray[i] = it.next();
i++;
}
return nodupesarray;
}
console output:
INFO [main] (TestMergeArray.java:40) - creating two lists of a million ints
DEBUG [main] (TestMergeArray.java:41) - list 1 size : 1000000
DEBUG [main] (TestMergeArray.java:42) - list 2 size : 1000000
INFO [main] (TestMergeArray.java:56) - now merging
INFO [main] (TestMergeArray.java:59) - done, final list size is 864975
this clearer lambda solution is slightly slower because of the (un)boxing
requires Java 8 or above
public static int[] mergedistinct( int[] array1, int[] array2 ) {
Stream<Integer> s1 = IntStream.of( array1 ).boxed();
Stream<Integer> s2 = IntStream.of( array2 ).boxed();
return( Stream.concat( s1, s2 ).distinct().mapToInt( i -> i ).toArray() );
}
[1, 2, 3, 5, 4, 7, 8]
if you need the array sorted:
…
return( Stream.concat( s1, s2 ).distinct().sorted().mapToInt( i -> i ).toArray() );
Here's a technique that iterates the arrays just once and does not use a hash to detect duplicates.
import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;
public class SortedMerge {
public static int[] merge(int[] array1, int[] array2) {
int[] a;
int[] b;
List<Integer> c = new ArrayList<Integer>();
int i = 0;
int j = 0;
// b is longer than a
if (array1.length > array2.length) {
a = array2;
b = array1;
} else {
a = array1;
b = array2;
}
while (j < b.length) {
int bb = b[j];
if (i < a.length) {
int aa = a[i];
if (aa > bb) {
c.add(bb);
j++;
} else {
c.add(aa);
i++;
if (aa == bb) {
j++;
}
}
} else {
c.add(bb);
j++;
}
}
// java 8 List<Integer> to int[]
return c.stream().mapToInt(Integer::intValue).toArray();
}
public static void main(String[] args) throws Exception {
int[] array1 = new int[]{3, 5, 8, 11, 14};
int[] array2 = new int[]{1, 2, 3, 4, 6, 8, 14, 15, 17};
int[] c = merge(array1, array2);
for (int i = 0; i < c.length; i++) {
System.out.format("%d,", c[i]);
}
System.out.println();
// output> 1,2,3,4,5,6,8,11,14,15,17,
}
}
Can you use ArrayLists? ArrayLists would make this very easy to do.
//Consider n1 to be some global or instance variable.
import java.util.ArrayList;
public void Add(ArrayList<Integer> n2) {
for(int i = 0; i < n2.size(); i++) {
if(!n1.contains(i))
n1.add(n2.get(i));
}
}
Call your merge method and do the followings. I tested it. It works fine.
int[] result = merge(count, count1);
Set<Integer> set = new HashSet<Integer>();
try {
for (int i = 0; i < result.length; i++) {
set.add(result[i]);
}
System.out.println(set);
} catch (Exception e) { }
import java.util.ArrayList;
import java.util.List;
public class MergeListAndRemoveDuplicate {
public static void main(String[] args) {
int a[] = {1, 1, 2, 1, 3, 4, 1, 2, 5};
int b[] = {1, 2, 3, 1, 3, 2, 4, 5, 6, 7};
boolean flag = true;
List<Integer> list = new ArrayList<Integer>();
for (int i = 0; i < a.length; i++) {
for (int j = 0; j < b.length; j++) {
if (a[i] == b[j]) {
flag = false;
}
if (i == j && !list.contains(b[j])) {
list.add(b[j]);
}
}
if (flag == true) {
list.add(a[i]);
}
}
System.out.println(list);
}
}
package com.string.merge;
import java.util.ArrayList;
public class MergeArrayAndRemoveDuplicate {
public static void main(String[] args) {
int[] a = {1, 2, 2, 3, 1, 5, 3};
int[] b = {4, 3, 1, 5, 7, 8, 4, 2};
ArrayList<Integer> l = new ArrayList<>();
for (int i = 0; i < (a.length > b.length ? a.length : b.length); i++) {
if (i < a.length) {
int c = 0;
while (c <= l.size()) {
if (l.contains(a[i]) == false) {
l.add(a[i]);
}
c++;
}
}
if (i < b.length) {
int c = 0;
while (c <= l.size()) {
if (l.contains(b[i]) == false) {
l.add(b[i]);
}
c++;
}
}
}
System.out.println(l);
}
}
o/p-[1, 4, 2, 3, 5, 7, 8]
Related
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
I have found out the duplicate numbers in the array "a" but could not store the duplicate ones in another array "b". Any help much appreciated!
Here is my code:
public static void main(String[] args) {
int[] a = {1,2,3,3,5,6,1,7,7};
int[] b={};
for (int i = 0; i < a.length; i++) {
for (int j = i+1; j < a.length; j++) {
if(a[i]==(a[j])){
System.out.println(a[j]);
}
}
}
Because the length of result is not know, I would like to use a ArrayList instead of an array :
int[] a = {1, 2, 3, 3, 5, 6, 1, 7, 7};
List<Integer> b = new ArrayList<>();
for (int i = 0; i < a.length; i++) {
for (int j = i + 1; j < a.length; j++) {
if (a[i] == a[j] && !b.contains(a[j])) {
b.add(a[j]);
System.out.println(a[j]);
}
}
}
System.out.println(b);//result : [1, 3, 7]
You can try finding duplicates in an array using collections framework too:
import java.util.Set;
import java.util.HashSet;
import java.util.List;
import java.util.ArrayList;
public class MyClass {
public static void main(String args[]) {
int[] a = {1,2,3,3,5,6,1,7,7};
Set<Integer> set=new HashSet<Integer>();
List<Integer> list=new ArrayList<Integer>();
for(int i:a) {
if(!set.add(i)) {
list.add(i);
}
}
int[] b=new int[list.size()];
for (int i=0;i<list.size();i++) {
b[i] =list.get(i);
}
}
}
Here I have used the fact that sets do not allow duplicate and if set.add returns false, that means that element is already available in the set
We cannot change the size of Array once it is initialized. Here we do not know how many duplicates item will be in the Array.
EDIT -- This might be a better solution, my earlier solution was throwing ArrayIndexOutOfBoundException as indicated by #YCF_L --
import java.util.Arrays;
public class T {
public static void main(String[] args) {
//int[] a = {1, 2, 3, 3, 5, 6, 1, 7, 7}; //Set-1, provided by #YCF_L
int[] a = {1,1,3,3,5,6,1,7,7}; //Set-2, provided by OP
int[] b = {};
for (int i=0, k=0; i < a.length; i++) {
for (int j = i+1; j < a.length; j++) {
if(a[i] == a[j]){
System.out.println(a[j]);
k = k+1;
int[] p = new int[k];
for(int x=0; x < b.length; x++) {
p[x] = b[x];
}
p[k-1] = a[i];
b = p;
}
}
}
System.out.println(Arrays.toString(b));
System.out.println(Arrays.toString(removeDuplicates(b)));
}
public static int[] removeDuplicates(int[] a) {
boolean[] bArr = new boolean[1000];
int j = 0;
for (int i = 0; i < a.length; i++) {
if (!bArr[a[i]]) {
bArr[a[i]] = true;
j++;
}
}
int[] b = new int[j];
int c = 0;
for (int i = 0; i < bArr.length; i++) {
if (bArr[i]) {
b[c++] = i;
}
}
return b;
}
}
Output with Set-1 :
[1, 3, 7]
[1, 3, 7]
Output with Set-2 :
[1, 1, 1, 3, 7]
[1, 3, 7]
The method which takes two integer arrays. The method returns an integer array containing all the elements in array int[]a that are also present in array int[]b in their original sequential order in int[]a.
This is what it should output :
input: {1, 2, 3, 4, 5, 6, 7, 3, 8, 9, 2, 10}, {3, 2, 7, 12, 3, 9, 5, 2}
output: {2, 3, 5, 7, 3, 9, 2}
input: {4, 7, 1, 6, 9, 2, 3, 1}, {8, 5, 2, 1, 9, 4}
output: {4, 1, 9, 2, 1}
I tried something like this just to test it out to get my head around it but I still couldn't.
public static void arraysMatching(int[] s1, int[] s2) {
ArrayList<Integer> storage = new ArrayList<Integer>();
for (int i = 0; i <= s1.length; i++) {
for (int j = 0; j <= s2.length; j++) {
if (s2[j] == s1[i]) {
storage.add(s2[j]);
break;
}
}
break;
}
System.out.println(storage);
}
Test cases:
int [] m1 = {1, 2, 3, 4, 5, 6, 7, 3, 8, 9, 2, 10};
int [] m2 = {3, 2, 7, 12, 3, 9, 5, 2};
System.out.println(Arrays.toString(arraysMatching(m1, m2)));
Should print out [2, 3, 5, 7, 3, 9, 2]
To add to Codors answer, have the method return int[]:
public static int[] arraysMatching(int[] s1, int[] s2) {
ArrayList<Integer> storage = new ArrayList<>();
//for (int i = 0; i <= s1.length; i++) {
//wrong. change <= to < or better:
for (int i : s1) {
//for (int j = 0; j <= s2.length; j++) {
//wrong. change <= to < or better:
for (int j : s2) {
if (j == i) {
storage.add(j);
break;
}
}
}
//if you can use streams do
//return storage.stream().mapToInt(i->(int)i).toArray();
//alternatively
int[] returnArray = new int[storage.size()];
for(int i=0; i< storage.size(); i++) {
returnArray[i]=storage.get(i);
}
return returnArray;
}
So you can use it with System.out.println(Arrays.toString(arraysMatching(m1, m2)));
To my understanding, the second break statement terminates the outer loop too early; furthermore, the indexing goes one step too far in both loop termination conditions. Change the implementation as follows.
public static void arraysMatching(int[] s1, int[] s2) {
ArrayList<Integer> storage = new ArrayList<Integer>();
for (int i = 0; i < s1.length; i++) {
for (int j = 0; j < s2.length; j++) {
if (s2[j] == s1[i]) {
storage.add(s2[j]);
break;
}
}
}
System.out.println(storage);
}
Edit:
If the result is not to be printed but to be returned, the signature and the body have to be changed as follows.
public static ArrayList<Integer> arraysMatching(int[] s1, int[] s2) {
ArrayList<Integer> storage = new ArrayList<Integer>();
for (int i = 0; i < s1.length; i++) {
for (int j = 0; j < s2.length; j++) {
if (s2[j] == s1[i]) {
storage.add(s2[j]);
break;
}
}
}
return storage;
}
Edit:
If the return type is required to be Integer[], the implementation has to be changed as follows.
public static Integer[] arraysMatching(int[] s1, int[] s2) {
ArrayList<Integer> storage = new ArrayList<Integer>();
for (int i = 0; i < s1.length; i++) {
for (int j = 0; j < s2.length; j++) {
if (s2[j] == s1[i]) {
storage.add(s2[j]);
break;
}
}
}
int[] result = new int[storage.size()];
result = storage.toArray(result);
return result;
}
Edit:
If the return type is required to be int[] and no 'fancy stuff' for result conversion is desired, the code has to be changed as follows.
public static int[] arraysMatching(int[] s1, int[] s2) {
ArrayList<int> storage = new ArrayList<int>();
for (int i = 0; i < s1.length; i++) {
for (int j = 0; j < s2.length; j++) {
if (s2[j] == s1[i]) {
storage.add(s2[j]);
break;
}
}
}
int[] result = new int[storage.size()];
for (int k = 0; k < storage.length(); k++) {
result[k] = storage.get(k);
}
return result;
}
I trying to write recursive function in Java.
The function needs to count for me all the diffrents values in array.
i.e
{{1,1,1,1},{4,4,4,4},{3,3,1,1}}
The recursive function returns 3 (1,4,3)
This is the function that i need to write:
int numOfColors(int[][] map)
What I have been tried:
public static int numOfColors(int[][] arr) {
int i=0;
int j=0;
int colors=0;
int contains = arr[i][j];
if (arr== null) {
return 0;
} else if (arr[i][j] != 0&& arr[i][j]!=contains) {
colors ++;
}
return numOfColors(arr) + 1;
}
Exception in thread "main" java.lang.StackOverflowError
How can i fix it?
Thanks!
Below is one way of finding count of unique values using recursion and without using any Set or List -
package test;
public class Main {
public static void main(String[] args) {
int[][] arr = { { 4, 2, 2, 1, 4 }, { 4, 4, 3, 1, 4 }, { 1, 1, 4, 2, 1 }, { 1, 4, 0, 2, 2 }, { 4, 1, 4, 1, 1 } };
System.out.println(numOfColors(arr));
}
public static int numOfColors(int[][] arr) {
int unique = 0;
if (arr.length == 0) {
return unique;
} else {
int[] subArr = arr[arr.length - 1];
outerLoop: for (int i = 0; i < subArr.length; i++) {
int j = i + 1;
for (; j < subArr.length; j++) {
if (subArr[i] == subArr[j]) {
break;
}
}
if (j == subArr.length) {
int k = 0;
for (; k < arr.length - 1; k++) {
for (int l = 0; l < arr[k].length; l++) {
if (subArr[i] == arr[k][l]) {
continue outerLoop;
}
}
}
if (k == arr.length - 1) {
unique++;
}
}
}
int[][] dest = new int[arr.length - 1][];
System.arraycopy(arr, 0, dest, 0, arr.length - 1);
unique += numOfColors(dest);
return unique;
}
}
}
Output
5
Note that this problem can be solved without recursion easily. Also, above code can be make easy using Set
I think you should store unique values in Set and build final result base on it size. Here is one from many solutions:
package com.company;
import java.util.HashSet;
import java.util.Set;
public class Main {
public static void main(String[] args) {
int[][] map = new int[][] {{1,1,1,1},{4,4,4,4},{3,3,1,1}};
System.out.println(numOfColors(map));
}
public static int numOfColors(int[][] map) {
HashSet<Integer> result = new HashSet<Integer>();
numOfColorsImpl(map, 0, result);
return result.size();
}
private static void numOfColorsImpl(int[][] map, int rowIndex, Set<Integer> result) {
if (rowIndex == map.length)
return;
for (int value : map[rowIndex]) {
result.add(value);
}
numOfColorsImpl(map, rowIndex + 1, result);
}
}
You could use a recursive helper function that removes duplicates.
import java.util.*;
public class Main {
public static void main(String[] strg) {
int[][] arr = {{1, 1, 1, 1}, {4, 4, 4, 4}, {3, 3, 1, 1}};
numOfColors(arr);
}
static int numOfColors(int[][] map) {
ArrayList<Integer> intlist = new ArrayList<Integer>();
for (int o = 0; o < map.length; o++) {
for (int n = 0; n < map[o].length; n++) {
intlist.add(map[o][n]);
}
}
intlist = removeDuplicates(intlist, 0);
System.out.println(intlist.size()+" " +intlist);
return intlist.size();
}
static ArrayList<Integer> removeDuplicates(ArrayList<Integer> list, int counter) {
if (list == null) {
throw new NullPointerException();
}
if (counter < list.size()) {
if (list.contains(list.get(counter))) {
if (list.lastIndexOf(list.get(counter)) != counter) {
list.remove(list.lastIndexOf(list.get(counter)));
counter--;
}
}
removeDuplicates(list, ++counter);
}
return list;
}
}
Output
3 [1, 4, 3]
Online demo
I don't think recursion is necessary in this case, so I will explain the way I would go about it. I will refer to arr as array A. First, you create a hash set of numbers that you have seen already, which we will call hash set B. Then, you can loop through array A, processing each element. Check if hash set B contains that element. If it does, continue, if not, add that value to hash set B. After the loop, return the length of hash set B, or the entire set if you want to see what the unique values are.
For example:
import java.util.HashSet;
public class Class {
public static void main(String[] args){
int[][] A = {{1, 1, 1, 1}, {4, 4, 4, 4}, {3, 3, 1, 1}};
System.out.println("Number of different values: " + countUniqueVals(A));
}
public static int countUniqueVals(int[][] A){
HashSet<Integer> B = new HashSet<Integer>();
for (int row = 0; row < A.length; row++)
for (int col = 0; col < A[row].length; col++)
B.add(A[row][col]);
return B.size();
}
}
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)