I'm trying to write a function that returns an array of unique numbers. The array must be sorted. The function works fine when there are more than just one element, but it doesn't work for when there is just one element in the array. The function should return the only element found in that array, but instead, it is returning an empty array.
Why is this happening?
Array must be sorted for numUnique and removeDuplicates
public static int numUnique (double[] list){
int uniques = 1;
int i = 1;
if(list.length == 0) return 0;
while(i<list.length){
if(list[i] != list[i - 1])
uniques++;
i++;
}
return uniques;
}
public static double[] removeDuplicates(double[] list){
double[] arrayOfUniques = new double[numUnique(list)];
if(list.length == 0) return arrayOfUniques;
int uniques = 1;
int i = 1;
arrayOfUniques[0] = list[0];
while(i < list.length){
if(list[i] != list[i - 1])
arrayOfUniques[uniques++] = list[i];
i++;
}
return arrayOfUniques;
}
Array:
double[] a = {11,11,21,31,41,41,51,61,61,61,71,71,81,91,91,100,100};
Output:
Unique numbers: 9
Array of uniques:
[11.0, 21.0, 31.0, 41.0, 51.0, 61.0, 71.0, 81.0, 91.0]
But it doesn't work when the array just has one element:
double[] a = {11};
Output:
Unique numbers: 0
Array of uniques:[]
Try this.. Convert your array to list & convert list to set
Set not have duplicate values.. simple
List<String> myList= Arrays.asList(a);//convert array to List
Set<Double> uniqueSet = new HashSet<Double>(myList);//you get unique values
If you want to Set to Array try this https://stackoverflow.com/a/5982478/3879847
public List<Double> removeDuplicates (List<Double> list){
// add elements to al, including duplicates
Set<Double> hs = new HashSet<Double>();
hs.addAll(list);
list.clear();
list.addAll(hs);
return list;
}
Actually, it doesn't work for arrrays having only one unique element either (e.g. it returns empty array for new double[]{11.0,11.0, 11.0}). I would recommed a simpler approach using Java 8's stream:
public static double[] removeDuplicates(double[] list){
LinkedHashSet<Double> uniqueElements = Arrays.stream(list)
.boxed()
.collect(Collectors.toCollection(LinkedHashSet::new));
return uniqueElements.stream().mapToDouble(d -> d).toArray();
}
With Java 8 we get Stream, so how to use it in this case :
public static void main (String[] args) {
double[] a = {11,11,21,31,41,41,51,61,61,61,71,71,81,91,91,100,100};
//Way 1 just to print the unique element
DoubleStream.of(removeDuplicate(a)).forEach(System.out::println);
//Way 2 to save the update the array with only the unique element
a = removeDuplicate(a);
}
private static double[] removeDuplicate(double[] a) {
return DoubleStream.of(a).distinct().sorted().toArray();
}
In the main, we're just calling the method, and then read the result and print the values
In the removeDuplicate method : we create Stream of the values, then we keep only the different elements, then we sort them, and them we come back to an array (to follow your wishes)
If you're not sure to HAVE to use array, better use List every time ;)
Related
I have a given array with unique values say [1,4,3,2] and another desired array [1,2,4,3]
I want to cut this input array into a minimum number of pieces so I can convert that to the desired array by just re-arranging the cut pieces.
So for the input array [1,4,3,2] I can cut into pieces (1), (4,3), (2) and re-arrange like (1),(2),(4,3) to get the desired array [1,2,4,3]
Constraints:
Array values are unique.
The size of both arrays is the same and can be up to 1000.
Values in arrays are integers
So the answer is 3 pieces for this example.
Here is what I have tried:
public int process(int[] inp, int[] desired) {
int ans = 0;
for (int i = 0; i < inp.length; i++) {
if (inp[i] != desired[i]) ans++;
}
return ans;
}
My approach is not a correct one, as I am finding elements at each index to count the mismatches. What is the correct approach for solving this problem?
Since all elements in the given arrays are unique, we can store index the positions of elements in one of these arrays by generating a map of type Map<Integer,Integer> associating an array element (Key) with its index (Value).
Then iterate over the second array, searching for identical chunks.
For that, we need to maintain a variable prevIndex that would store the index occupied by the previous element in the first array. While iterating, we would need to check each next index in the first array (corresponding to the next element in the first array). If the next index differs from the previous only by one - the next element is proved to be a part of a chunk with identical order, and we're just incrementing prevIndex. Otherwise, increment the count of chunks.
public static int process(int[] arr1, int[] arr2) {
Map<Integer, Integer> indexByValue = mapIndices(arr2);
int count = 1;
int prevIndex = indexByValue.get(arr1[0]);
for (int i = 1; i < arr1.length; i++) {
int nextIndex = indexByValue.get(arr1[i]);
if (nextIndex == prevIndex + 1) {
prevIndex++;
} else {
prevIndex = nextIndex;
count++;
}
}
return count;
}
public static Map<Integer, Integer> mapIndices(int[] arr) {
return IntStream.range(0, arr.length)
.boxed()
.collect(Collectors.toMap(
i -> arr[i],
Function.identity()
));
}
main()
public static void main(String[] args) {
System.out.println(process(new int[]{1, 4, 3, 2}, new int[]{1, 2, 4, 3}));
}
Output:
3
Given an integer array, I want to return the first unique element in the array. I used A List .contains() method to check if Integer array contains the element, the method is correct but not efficient(time complexity O(N**2)) since List.contain() loops entire list comparing each element.
List<Integer> list = new ArrayList<Integer>();
int num = 0;
for(int a: A){
if(list.contains((Integer)a)){
list.remove((Integer)a);
}else{
list.add(a);
}
}
num = !list.isEmpty()? (int) set.get(0): 0;
return list.size()<1?-1:num;
}
//example input/output
int[] a = {1,2,6,1,6}
//I get the correct answer 2
Done my research and found that HashSet has Contains which is more efficient
Problem is Once i use a HashSet(I also tried Set) I dont get same result. The function should return the first unique element in the int[]
import java.util.*;
HashSet<Integer> set = new HashSet<Integer>();
int num = 0;
for(int a: A){
if(set.contains(a)){
set.remove((Integer)a);
}else{
set.add(a);
}
}
num = !set.isEmpty()? (int) set.iterator.next(): 0;
return set.isEmpty()?-1:num;
}
//example input/output
int[] a = {1,2,6,1,6}
// Should return 2 but get the wrong answer 1
LinkedHashSet which maintains insertion order should be used to track the first unique number
Another Set is needed to keep the duplicated values in the input array which can be detected using the fact that Set::add returns false when the element has not been actually added to the set. Then the duplicates array has to be removed from the set of input and the first remaining element is returned.
Also, it may be better to return null / Integer value instead of -1 which is more appropriate for returning an index in the input array/list when a requested value is not found.
That being said a solution may look as follows:
public static Integer firstUnique(int ... arr) {
Set<Integer> input = new LinkedHashSet<>();
Set<Integer> duplicates = new HashSet<>();
for (int x : arr) {
if (!input.add(x)) {
duplicates.add(x);
}
}
input.removeAll(duplicates);
return input.isEmpty() ? null : input.iterator().next();
}
Test:
System.out.println(firstUnique(1, 2, 6, 1, 4, 6)); // 2
System.out.println(firstUnique(1, 2, 6, 6, 1, 2)); // null
public static void main(String[] args) {
int[] HwArray = new int[10];
for (int i = 0; i < HwArray.length; i++) {
HwArray[i] = i;
}
int count = 0;
for (int i = 0; i < HwArray.length; i++){
HwArray[i] = (int) (100 + Math.random() * 100);
System.out.print("HwArray[i]=" + HwArray[i]);
}
}
{
int[] reverse(int[] HwArray); {
int[] reversed = new int[HwArray.length];
for (int i=0; i<HwArray.length; i++) {
reversed[i] = HwArray[HwArray.length - 1 - i];
}
return reverse;
}
}
}
Sorry, I'm still learning. I'm trying to reverse the order of all the elements, but I keep receiving an error. Am I doing something wrong?
To be honest, you're actually not that far off. The reverse function actually seems to work okay but you have all kinds of weird syntax errors and you're not even calling the reverse method. Try doing this:
Move the reverse method inside the class where main is defined. If you want to call it directly from main you'll have to make it an static method.
Get rid of the extra curly braces on lines 17 and 25.
Remove the semicolon on line 18 when declaring reverse. It shouldn't be there.
The reverse method is trying to return a variable called reverse. That's the name of the method, you can't do that. I think you meant to return reversed.
Actually call the reverse method after you have initialized the array with random numbers. Then print the array out again to verify that it worked.
Notice that you're not actually printing out the values of the array on line 11. That should be System.out.println("HwArray[" + i + "]=" + HwArray[i]);
I think the conceptually easiest way to reverse the order of elements in an array is to swap each ith element in the first half of the array of size N with the N-ith element in the second half:
int[] reversed = new int[10];
for (int i=0; i < HwArray.length/2; ++i) {
reversed[i] = HwArray[HwArray.length-1-i];
reversed[HwArray.length-1-i] = HwArray[i];
}
Demo here:
IDEOne
There are many errors:
First of all, it should be return reversed instead of return reverse.
Then, you cannot define any method inside a method(here, method reverse is defined inside the main method)
Then, you can do one thing, remove the following two braces:
1: The opening brace just before int[] reverse(int[] HwArray)
2: The closing brace in the last line
Last, it should be int[] reverse(int[] HwArray) { instead of int[] reverse(int[] HwArray); {
Comparator<Integer> comparator = new Comparator<Integer>() {
#Override
public int compare(Integer o1, Integer o2) {
return o2.compareTo(o1);
}
};
// option 1
Integer[] array = new Integer[] { 11, 44, 4, 3, 123 };
Arrays.sort(array, comparator);
// option 2
int[] array2 = new int[] {11, 44, 4, 3, 123};
List<Integer>list = Ints.asList(array2);
Collections.sort(list, comparator);
array2 = Ints.toArray(list);
// option 3
List<Integer> integersList = Ints.asList(arr);
Collections.sort(integersList, Collections.reverseOrder());
I would like to write a function insertAndSort() that will take as parameter an Integer "num" and a List of integers "list". Let's assume the List lust is already sorted.
The algorithm is supposed to work this way :
Add "num" to L and keep the List sorted after "num" has been added.
Return the sorted List.
WARNING : We do not know whether the list is sorted ASC or DESC. And that is precisely my problem !
Example :
if "num" = 4 and L = {1, 3, 5, 7}, then the final sorted List is {1, 3, 4, 5, 7}
if "num" = 4 and L = {7, 5, 3, 1}, then the final sorted List is {7, 5, 4, 3, 1}
I can not use sorting API such as Collections.sort or Collections.reverseOrder etc...
So far, I've produced this code :
public static void main(String[] args) {
int num = 4;
List<Integer> myList = Arrays.asList(1, 3, 5, 7);
List<Integer> newList = new ArrayList<Integer>();
newList = insertAndSort(myList, num);
System.out.println(newList);
}
public static List<Integer> insertAndSort(List<Integer> list, int num) {
List<Integer> listSecond = new ArrayList<Integer>(list.size()+1);
for(int i = 0; i <= list.size() ; i++) {
if(num < list.get(i)) {
if(!listSecond.contains(num)){
listSecond.add(num);
} else {
listSecond.add(list.get(i-1));
listSecond.add(list.get(i));
break;
}
} else {
listSecond.add(list.get(i));
}
}
return listSecond;
}
The problem is that this seems to be working with a single type of List: the ascending one.
When I take a sorted descending List, it does not work anymore.
Do you have any idea to make this work with both type of List ?
Thanks and Regards.
First, you need to detect the sort order in the existing list.
If the list is empty, you don’t need to care, just add your element, you cannot break any existing sort order.
If the list contains one element, I cannot tell you what to do. Options include tossing a coin and throwing an exception, but there are more.
If the list contains two or more elements, iterate through them except for the last element, each time comparing the current element with the element in the next higher index. As soon as you encounter a pair of elements that are not equal, you know the sort order. If you only encounter equal elements, all the elements in the list are equal, and again I cannot tell you what to do.
Once you’ve detected a sort order, I suggest a big if-else statement to handle the two cases separately.
You already have the code for the ascending case. Except it doesn’t always work. If I try to insert 4 into { 1, 3, 5 }, I get an ArrayIndexOutOfBoundsException. If I try with { 1, 3, 5, 7, 9 }, the 9 is lost. You should probably find a fix for that.
You should be able to handle the descending case similarly to the ascending case. Only use num > list.get(i) instead of num < list.get(i).
First, you need to check whether the list is sorted in ASC or DESC. That's easy: compare the 1st two elements look for two consecutive non-identical elements and see whether the first one is greater or the second one (thanks tom for correcting the mistake).
Now, for a list sorted in ascending order, convert list to an ArrayList. Then, add num to the ArrayList and convert it to a TreeSet, since TreeSets sort their elements in ascending order. Finally, reassign the ArrayList to hold the contents of the TreeSet and return it.
For a list sorted in descending order, first, convert the TreeSet to an ArrayList, then iterate over this ArrayList in reverse order and add the elements to a new ArrayList. Return the second ArrayList.
public List<Integer> insertAndSort(List<Integer> list, int num){
ArrayList<Integer> a = new ArrayList<Integer>(list);
a.add(new Integer(num));
TreeSet t = new TreeSet(a);
a = new ArrayList<Integer>(t);
int l = list.size();
for(int i=1; i<l; i++){
if(list.get(i) != list.get(i-1))
break;
}
if(list.get(i) > list.get(i-1)) //ASC
return a;
else{ //DESC
ArrayList<Integer> a2 = new ArrayList<Integer>();
for(int i = a.size() - 1; i >= 0; i--)
a2.add(a.get(i));
return a2;
}
}
I would proceed with something like the code below. A few remarks :
it is possible to decide sort order if and only if there is at least 1 element AND first and last elements have different values.
the line int oo = list.get(p2) - list.get(p1); compute the
difference between the last and first element (negative = DESC,
positive = ASC)
the variable ox is positive if and only if the
added element is after the element pointed by the variable p3
whatever the order.
the position is found by a binary search algorithm by choosing p3 between p1 and p2 and deciding if the element is before or after p3.
This is not fully tested bu works with the examples you gave :
// static List<Integer> list = new ArrayList<>(Arrays.asList(7, 5, 3, 1));
static List<Integer> list = new ArrayList<>(Arrays.asList(1, 3, 5, 7));
static void add(int x)
{
// fixed code below (see Ole V.V. comment)
}
static public void main(String [ ] args)
{
add(4);
for(int x: list)
System.out.println(x);
}
EDIT: to be complete (see Ole V.V. comments)
When the new element is to be inserted before the first or after the last, two simple O(1) tests may be performed ; the general case has O(log N) complexity, this is more efficient than traversing the entire list which is O(N).
Be carefull too when comparing elements to deduce sort order, there may be several equal values ; the best is to compare the first and the last elements, this is O(1) - again better than O(N).
Algorithmic complexity is an important matter (to me) and was the primary aim of my post. The code of the add function becomes :
static void add(int x)
{
int p1 = 0;
int p2 = list.size() - 1;
if(list.size() == 0 || list.get(p1) == list.get(p2))
throw new IllegalStateException("Unable to decide sort order");
int oo = list.get(p2) - list.get(p1);
if(oo * (x - list.get(p1)) <= 0) // new element is before first
list.add(0, x);
else if(oo * (x - list.get(p2)) >= 0) // new element is after last
list.add(x);
else
{
while (p1 + 1 < p2)
{
int p3 = (p1 + p2) / 2;
int ox = (x - list.get(p3)) * oo;
if(ox >= 0) // new element is after p3
p1 = p3;
if(ox <= 0) // new element is before p3
p2 = p3;
}
list.add(p2, x);
}
}
Note : there may be still some undealed side effects. If the asker is interested, I am ready to give further help - just ask.
Your code and what you say is two different things.
Based on code you made, I see that List can't contain more than one instance of same value.
If thats the case, main method should look like this:
public static void main(String[] args){
int num = 4;
List<Integer> myList = Arrays.asList(1, 3, 4, 5, 7);
List<Integer> newList;
if (!myList.contains(num)) {
newList = insertAndSort(myList, num);
} else {
newList = copyList(myList);
}
System.out.println(newList);
}
if thats not the case:
public static void main(String[] args){
int num = 4;
List<Integer> myList = Arrays.asList(1, 3, 4, 5, 7);
List<Integer> newList;
newList = insertAndSort(myList, num);
System.out.println(newList);
}
Methods that main method use:
Assuming we can only know how list is sorted by values in list, we have to decide default sort method when there is only 1 value or all values are same. I picked ASC as default. If elements can be of same value and we are certain list is sorted its best to compare lowest value in list with the highest one. With this approach we have to compare 2 elements only once.
So method to see if list is sorted DESC would look like this:
private static boolean isDesc(List<Integer> list) {
return list.get(0) > list.get(list.size() - 1);
}
If method returns true its sorted DESC. With returning false its ASC. If we want to change default value, when values don't tell us how its sorted and we want it to be DESC we would replace '>' sign with '>='
private static boolean isDesc(List<Integer> list) {
return list.get(0) >= list.get(list.size() - 1);
}
Code for as you called it insertAndSort:
public static List<Integer> insertAndSort(List<Integer> list, int num) {
List<Integer> listSecond = new ArrayList<Integer>(list.size() + 1);
boolean isDescSortOrder = isDesc(list);
if (isDescSortOrder) {
int i = 0;
while ((i < list.size()) && (list.get(i) > num)) {
listSecond.add(list.get(i));
i++;
}
listSecond.add(num);
while (i < list.size()) {
listSecond.add(list.get(i));
i++;
}
} else { // is asc sort order
int i = 0;
while ((i < list.size()) && (list.get(i) < num)) {
listSecond.add(list.get(i));
i++;
}
listSecond.add(num);
while (i < list.size()) {
listSecond.add(list.get(i));
i++;
}
}
return listSecond;
}
Depending on how its sorted code got devided into 2 blocks. As we don't know on each iteration will be right place to insert our num value its better to use while loop. Using for loop and checking everytime if num value already exists in list is counterproductive. On top of that I dunno if your application should allow same values in the list. If I assume it should, you can't add num value if it already existed in the list with for loop and checking with contains every iteration.
And just to copy the table when list already has the element and we don't want to add elements that are already incuded:
public static List<Integer> copyList(List<Integer> list) {
List<Integer> listSecond = new ArrayList<Integer>(list.size());
for (int i = 0; i < list.size(); i++) {
listSecond.add(list.get(i));
}
return listSecond;
}
Also based on good programming practices I'd recommend to name methods based on what they do.
Calling method insertAndSort is asking for trouble. If I seen it, I'd say it alters list we are giving in parameter. Then it sorts it.
So putting unsorted list in it would give us unwanted outcome.
And I'd still ask myself why does it return a List when we are inserting an item to already existing list? I'd rather name it:
public static List<Integer> copySortedWithNewValue(List<Integer> sortedList, int newValue)
Try to use PriorityQueue. This collection contains a sorted sequence of elements which could be duplicated.
Let's say I have an array in the length of n, and the only values that can appear in it are 0-9. I want to create a recursive function that returns the number of different values in the array.
For example, for the following array: int[] arr = {0,1,1,2,1,0,1} --> the function will return 3 because the only values appearing in this array are 0, 1 and 2.
The function receives an int array and returns int
something like this:
int numOfValues(int[] arr)
If you are using Java 8, you can do this with a simple one-liner:
private static int numOfValues(int[] arr) {
return (int) Arrays.stream(arr).distinct().count();
}
Arrays.stream(array) returns an IntStream consisting of the elements of the array. Then, distinct() returns an IntStream containing only the distinct elements of this stream. Finally, count() returns the number of elements in this stream.
Note that count() returns a long so we need to cast it to an int in your case.
If you really want a recursive solution, you may consider the following algorithm:
If the input array is of length 1 then the element is distinct so the answer is 1.
Otherwise, let's drop the first element and calculate the number of distinct elements on this new array (by a recursive call). Then, if the first element is contained in this new array, we do not count it again, otherwise we do and we add 1.
This should give you enough insight to implement this in code.
Try like this:
public int myFunc(int[] array) {
Set<Integer> set = new HashSet<Integer>(array.length);
for (int i : array) {
set.add(i);
}
return set.size();
}
i.e, add the elements of array inside Set and then you can return the size of Set.
public int f(int[] array) {
int[] counts = new int[10];
int distinct = 0;
for(int i = 0; i< array.length; i++) counts[array[i]]++;
for(int i = 0; i< counts.length; i++) if(counts[array[i]]!=0) distinct++;
return distinct;
}
You can even change the code to get the occurrences of each value.
You can try following code snippet,
Integer[] arr = {0,1,1,2,1,0,1};
Set<Integer> s = new HashSet<Integer>(Arrays.asList(arr));
Output: [0, 1, 2]
As you asked for a recursive implementation, this is one bad way to do that. I say bad because recursion is not the best way to solve this problem. There are other easier way. You usually use recursion when you want to evaluate the next item based on the previously generated items from that function. Like Fibonacci series.
Ofcourse you will have to clone the array before you use this function otherwise your original array would be changed (call it using countDistinct(arr.clone(), 0);)
public static int countDistinct(int[] arr, final int index) {
boolean contains = false;
if (arr == null || index == arr.length) {
return 0;
} else if (arr.length == 1) {
return 1;
} else if (arr[index] != -1) {
contains = true;
for (int i = index + 1; i < arr.length; i++) {
if (arr[index] == arr[i]) {
arr[i] = -1;
}
}
}
return countDistinct(arr, index + 1) + (contains ? 1 : 0);
}
int numOfValues(int[] arr) {
boolean[] c = new boolean[10];
int count = 0;
for(int i =0; i < arr.length; i++) {
if(!c[arr[i]]) {
c[arr[i]] = true;
count++;
}
}
return count;
}