How to find if any values in array add up to n - java

I have an array of random values, and a target value.
#!/bin/bash
objective='50'
declare -a values=(1 2 2 6 8 14.5 15 28.7 .. 42)
I need to find a way to extract any combination of numbers in the array 'values' that add up to 50
The array has duplicates, and floating point integers.
A solution set might look like:
50 = 42 + 8
50 = 42 + 6 + 2
Initially I started in bash with some nested for loops, however I'm quickly realizing that this will grow exponentially with my array length.
I took a couple of java classes in college, but I'm still inexperienced in programming. I'm starting to think this may require recursion.
Can anyone with more programming experience point me in the right direction?
Besides nested for loops, how else could you approach this problem?

Here is an algorithm that has time complexity O(M*N) whereas M is Target and N is total size of set. Use analogy with knapsack problem as follows :-
Knapsack capacity = Target
Items are elements in the set with weight & value same as itself
Calculate maximum profit using dynamic programming
maxprofit = Target then there is/are subset which sum up to target.
Retrace the solution.
Java Solution for the same :-
public class SubSetSum {
static int[][] costs;
public static void calSets(int target,int[] arr) {
costs = new int[arr.length][target+1];
for(int j=0;j<=target;j++) {
if(arr[0]<=j) {
costs[0][j] = arr[0];
}
}
for(int i=1;i<arr.length;i++) {
for(int j=0;j<=target;j++) {
costs[i][j] = costs[i-1][j];
if(arr[i]<=j) {
costs[i][j] = Math.max(costs[i][j],costs[i-1][j-arr[i]]+arr[i]);
}
}
}
System.out.println(costs[arr.length-1][target]);
if(costs[arr.length-1][target]==target) {
System.out.println("Sets :");
printSets(arr,arr.length-1,target,"");
}
else System.out.println("No such Set found");
}
public static void printSets(int[] arr,int n,int w,String result) {
if(w==0) {
System.out.println(result);
return;
}
if(n==0) {
System.out.println(result+","+arr[0]);
return;
}
if(costs[n-1][w]==costs[n][w]) {
printSets(arr,n-1,w,new String(result));
}
if(arr[n]<=w&&(costs[n-1][w-arr[n]]+arr[n])==costs[n][w]) {
printSets(arr,n-1,w-arr[n],result+","+arr[n]);
}
}
public static void main(String[] args) {
int[] arr = {1,2,3,8,9,7};
calSets(10,arr);
}
}

I would do it like this:
1.some init
const int N=array size;
int val[N]; // input data
bool flag[N]; // is val used ?
for (int i=0;i<N;i++) flag[i]=false;
sort val[] descending
2.create function bool find_sum(int s);
if it found solution returns true else false
set flag to true for all used values
{
for (int i=0;i<N;i++) // find first usable big number (could be faster with binary search or with tailing last used i index into recursion)
if ((val[i]<=s)&&(!flag[i]))
{
flag[i]=true; // flag it as used
if (val[i]==s) return true; // try to find reminder
if (find_sum(s-val[i])) return true; // if found return true
flag[i]=false; // else unflag val[i] and continue winth next number
}
return false; // if sum not found then return false
}
3.after find_sum(s) your sum consists of all val[i] where flag[i]!=false
[edit1] functional source tested even for your case [6,5,5] and sum=10 it is OK
//---------------------------------------------------------------------------
int find_sum(int *val,int *use,int N,int sum,bool init=true)
{
int i;
if (init)
{
for (i=0;i<N;i++) use[i]=0; // nothibg used yet
for (int e=1;e;) // bubble sort
for (e=0,i=1;i<N;i++)
if (val[i-1]<val[i])
{ e=val[i-1]; val[i-1]=val[i]; val[i]=e; e=1; }
}
for (i=0;i<N;i++) // find first usable big number (could be faster with binary search or with tailing last used i index into recursion)
if ((val[i]<=sum)&&(!use[i]))
{
use[i]=1; // val[i] is used
if (val[i]==sum) return 1; // try to find reminder
if (find_sum(val,use,N,sum-val[i],false)) return 1; // if found return true
use[i]=0; // else val[i] is unused and continue winth next number
}
return 0; // if sum not found then return false
}
//---------------------------------------------------------------------------
void main()
{
int in[]={6,5,5}; // input data
const int N=sizeof(in)/sizeof(int);
int ret,out[N];
if (find_sum(in,out,N,10))
for (int i=0;i<N;i++)
if (out[i])
{
cout << in[i] << " ";
}
}
//---------------------------------------------------------------------------
PS. in your question in the input array are also floating point values
so you have to change int val[],sum to float/double
and add some accuracy for sum comparison to work with floats
if (val[i]==sum) return 1;
change to
if (fabs(val[i]-sum)<1e-10) return 1;
or use any other accuracy instead of 1e-10

You can use recursion yes, you can break the array into sub-parts (I use List).
Start from 0th index of the Parent list and a blank list
Iterate over to subList your Parent from i+1 to the end and thereby increasing your working list from 0 to i
Check for the sum (calculated) equals your objective
Code:
static Integer[] array = { 1, 2, 2, 6, 8, 14, 15, 28, 30, 32, 12, 48, 6, 42 };
static int objective = 50;
public static void main(String args[]) {
add(new ArrayList<Integer>(Arrays.asList(array)),
new ArrayList<Integer>());
}
public static void add(List<Integer> digits, List<Integer> workingList) {
for (int i = 0; i < digits.size(); i++) {
// New sublist to store values from 0 to i
List<Integer> list = new ArrayList<Integer>(workingList);
list.add(digits.get(i));
// Here you call this recursively with your Parent list from i+1
// index and working list from 0 to i
add(digits.subList(i + 1, digits.size()), list);
}
int sum = 0;
for (int element : workingList) {
sum += element;
}
if (sum == objective) {
System.out.println(objective + " = "
+ Arrays.toString(workingList.toArray()));
}
}
Output:
50 = [1, 2, 2, 15, 30]
50 = [1, 2, 6, 8, 15, 12, 6]
50 = [1, 2, 6, 14, 15, 12]
50 = [1, 2, 14, 15, 12, 6]
50 = [1, 2, 15, 32]
50 = [1, 2, 6, 8, 15, 12, 6]
...

Related

Calculate the sum of dices based on target accurately

I am trying, to sum up score for a little dice game I made. The dice has the following values: 1-6, the player can select target, LOW = n < 4, 1,2,3. The rest of the targets, 4, 5, 6, 7, 8, 9, 10, 11 and 12.
When a throw is done, sum up the total sum of the dices, based on target value. What this means, is, if LOW is select, then everything below 4, is summed up. Otherwise, the process, must sum each dice till it reaches the target sum, and continue.
If, a throw is done, and I selected 6 as target, and get the following set: {1, 1, 4, 2, 5, 6}. We have a 6, 5+1=6, and 4+2=6, we are left with 1 which is not counted.
Constraints:
1-6 dice values.
Everything (Target) below 4, is summed up.
Everything (Target) selecting between 4, 5, 6, 7, 8, 9, 10, 11, & 12, is processed differently.
6 dices, can produces any number between 1-6. This means, [6,6,6,6,6,6], or [1,1,3,5,4,2], or some other set.
The only thing important, is the sum that is calculated and nothing else, as long as it matches the input of dices.
For example:
If the target is 12 and a list of numbers is [6, 6, 6, 6, 6, 6] then return value should be 36.
If we receive a list of numbers [1, 3, 4, 5, 6, 6] and a target is should be 12 (5+1+6=12 and also 5+4+3=12, however, numbers can only be used once and not reused, therefore only one of the combinations can contribute the result).
Below is a method, which gives the occurrences of a dice.
public static TreeMap<Integer, Integer> countOccurrences(List<Integer> numbers){
TreeMap<Integer, Integer> map = new TreeMap<Integer, Integer>();
int i = 0;
for(int n: numbers) {
if(map.containsKey(n)) {
i = map.get(n);
map.put(n, ++i);
}
else
map.put(n, 1);
}
return map;
}
Results:
Occurrences: {1=2, 2=1, 4=1, 5=1, 6=1}
Sample code
public static void main(String[] args) {
System.out.println(sum(combinationSum(List.of(1, 2, 4, 6, 6, 6), 12)));
System.out.println(combinationSum(List.of(1, 3, 3, 6, 5, 6), 12));
System.out.println(combinationSum(List.of(1, 2, 1, 4, 5, 6), 6));
}
public static int sum(List<List<Integer>> numbers)
{
int sum = 0;
int n = 0;
while(n < numbers.size()){
sum += numbers.get(n).stream().mapToInt(Integer::intValue).sum();
++n;
}
return sum;
}
public static List<List<Integer>> combinationSum(List<Integer> candidates, int target) {
List<List<Integer>> res = new ArrayList<>();
List<Integer> ds = new ArrayList<Integer>();
findCombinations(res, ds, target, candidates, 0);
return res;
}
private static void findCombinations(List<List<Integer>> res, List<Integer> ds, int target, List<Integer> arr, int index ){
if(target == 0){res.add(new ArrayList<>(ds)); return;}
for(int i= index ; i<arr.size(); i++){
if(i>index && arr.get(i) == arr.get(i-1)) continue;
if(arr.get(i) > target) break;
ds.add(arr.get(i));
findCombinations( res, ds, target-arr.get(i) , arr, i+1);
ds.remove(ds.size()-1 );
}
}
Produces:
24
[[1, 6, 5], [1, 5, 6], [3, 3, 6], [3, 3, 6], [6, 6]]
[[1, 1, 4], [1, 5], [2, 4], [1, 5], [6]]
Live running: https://www.jdoodle.com/ia/sHY
Update
In order to find the maximum possible score of the list, we maximize the number of non-overlapping combinations that we can construct from it.
For we need to take the following steps:
Find all the possible combinations which produce the target sum. We can not reject any combinations on the fly, because we can't know in advance which of them can be used in the optimal solution. For instance, if target is 6 and a list of number is [3,3,2,2,1,1], there will be the following combinations: [3,3], [2,2,1,1] and [3,2,1] appear two times. If we pick [3,3], which is the shortest combination, we will not be able to construct any combinations and resulting score will be wrong (6). Instead, we need to choose two combinations [3,2,1] which well give the result 12. That proves that we can't rely on the combination size, we need to explore all the combinations and then choose the optimal set of combinations.
Generate all possible groups of combinations that fit to the given list of numbers and find a group having the maximum number of combinations in it.
In the code below both steps are implemented recursively.
A link to Online Demo
Expalanation:
The enty point, this method that kicks in the process.
public static int sumRecursively(List<Integer> numbers, int target) {
Deque<List<Integer>> combinations = new ArrayDeque<>();
generateCombinations(numbers, combinations, new ArrayList<>(), target);
return processCombinations(combinations, numbers, target);
}
Step 1. Generating all the combinations.
Recursive method responsible for generating the set of combinations (implemented as void to avoid wrapping a combination with an additional collection and then throwing this wrapper away):
private static void generateCombinations(List<Integer> numbers,
Queue<List<Integer>> combinations,
List<Integer> combination,
int currentSum) {
if (currentSum == 0) { // base case - a combination has been found
combinations.add(combination);
return;
}
// recursive case
for (Integer next : numbers) { // loop is need only to discard the elements that exceed the currentSum - pay attention to the condition below and break clause at the end of the loop (we will bread out of the loop after the first encountered element that fits to the current sum)
if (next > currentSum) continue;
List<Integer> newNumbers = new ArrayList<>(numbers);
newNumbers.remove(next);
// there two opportunities for each number: use it, or ignore it
// add next number
List<Integer> newCombination = new ArrayList<>(combination);
newCombination.add(next);
getCombinations(newNumbers, combinations, newCombination, currentSum - next);
// ignore next number
getCombinations(newNumbers, combinations, new ArrayList<>(combination), currentSum);
break;
}
}
Step 2. Generating the groups of combinations.
Method below is responsible choosing the group that fits to the given list (i.e. we can construct all the combinations in the group from list elements) and has the maximum number of combinations in it.
All the functionality related to the procissing the the group of combinations (which represents a List<List<Integer>>) is incapsulated in a class CombinationGroup to make the code cleaner.
public static int processCombinations(Deque<List<Integer>> combinations,
List<Integer> numbers,
int target) {
List<CombinationGroup> combinationGroups = new ArrayList<>();
generateGroups(combinationGroups, combinations, new CombinationGroup(numbers.size()));
return combinationGroups.stream()
.filter(group -> group.canConstruct(numbers))
.mapToInt(group -> group.getCombCount() * target)
.max()
.orElse(0);
}
The following method is responsible for creating the all possible groups of previosly descovered combinations. There's also a small optimization: total number of elements in each group should not exceed the number of elements in the source list:
public static void generateGroups(List<CombinationGroup> groups,
Deque<List<Integer>> combinations,
CombinationGroup group) {
if (combinations.isEmpty()) {
groups.add(group);
return;
}
Deque<List<Integer>> combinationsCopy = new ArrayDeque<>(combinations);
List<Integer> comb = null;
while (!combinationsCopy.isEmpty() && (comb == null || !group.canAdd(comb))) {
comb = combinationsCopy.removeLast();
}
// adding the combination
if (comb != null) {
CombinationGroup groupWithNewComb = group.copy();
groupWithNewComb.addCombination(comb);
generateGroups(groups, combinationsCopy, groupWithNewComb);
}
// ignoring the combination
generateGroups(groups, combinationsCopy, group);
}
Class CombinationGroup used in the methods above:
public class CombinationGroup {
private List<List<Integer>> combinations = new ArrayList<>();
private int combCount; // number of combinations
private int size; // total number of elements in the list of combinations
private int sizeLimit;
public CombinationGroup(int sizeLimit) {
this.sizeLimit = sizeLimit;
}
public boolean canAdd(List<Integer> combination) {
return size + combination.size() <= sizeLimit;
}
public boolean addCombination(List<Integer> combination) {
if (!canAdd(combination)) return false;
combinations.add(combination);
size += combination.size();
combCount++;
return true;
}
public CombinationGroup copy() {
CombinationGroup copy = new CombinationGroup(this.sizeLimit);
for (List<Integer> comb : combinations) {
copy.addCombination(comb);
}
return copy;
}
public boolean canConstruct(List<Integer> numbers) {
if (numbers.size() < size) return false;
Map<Integer, Long> frequencyByValueNumb = getFrequencies(numbers.stream());
Map<Integer, Long> frequencyByValueComb = getFrequencies();
return frequencyByValueNumb.keySet().stream() // each element that prent this CombinationGroup appears in the given list of numbers appears at least the same number of times - that means we construct all these combinations from the given list
.allMatch(key -> frequencyByValueNumb.get(key) >= frequencyByValueComb.getOrDefault(key, 0L));
}
public Map<Integer, Long> getFrequencies() {
return getFrequencies(combinations.stream().flatMap(List::stream));
}
public Map<Integer, Long> getFrequencies(Stream<Integer> stream) {
return stream.collect(Collectors.groupingBy(
Function.identity(),
Collectors.counting()
));
}
public int getCombCount() {
return combCount;
}
#Override
public String toString() {
return "CombinationGroup{" +
"combinations=" + combinations +
'}';
}
}
main()
public static void main(String[] args) {
System.out.println(sumRecursively(List.of(1, 3, 4, 5, 6, 6), 12));
System.out.println(sumRecursively(List.of(1, 3, 3, 6, 5), 12));
System.out.println(sumRecursively(List.of(1, 2, 1, 4, 5, 6), 6));
}
Output:
24
12
18
Simplified algorithm
(doesn't maximizes the number of combinations)
In order to ensure that all the elements in each combination are unique, we to track indices that have been already used. I.e. each time we find a combination which sums up to the target number, we should prohibit the usage of elements that have been used in this combination, but not earlier (because there can be many combinations which are not able to produce the target, and therefore any element should eligible to be used until we didn't construct a complete combination that gives the target using this element).
To track the elements that are taken, we need an object that would be visible in every recursive branch. And we are already passing a list of numbers while making every recursive call, what if we would modify it each time we found a combination that produces the target number by removing the elements that have been use in this combination? If we took this road after the first combination, thing would become complicated because we will not be able to rely on the indices (because they can change in an unpredictable way) while constructing a single combination - it's crucial to ensure that each element that belongs to a particular combination is used only once withing a combination. Since values of elements might be identical, we should use the iteration order to construct each combination properly, but each removal of elements would create a mess. So, is there a better way?
We can maintain an array of boolean values, each element is this array would indicate whether a number at a particular index already belongs to a combination that gives the target or not.
Instead of clattering the recursive method with the code that manipulates with this boolean array, I've encapsulated it within a class with simple and self-explanatory methods, and sumRecursively() makes use of an instance of this class.
public class CombinationTracker {
private boolean[] isUsed;
public CombinationTracker(int size) {
this.isUsed = new boolean[size];
}
public boolean indexIsUsed(int ind) {
return isUsed[ind];
}
public boolean allNotUsed(List<Integer> indices) {
// return indices.stream().noneMatch(i -> isUsed[i]); // this line does the same as the loop below
boolean result = true;
for (int idx: indices) {
if (isUsed[idx]) {
result = false;
break;
}
}
return result;
}
public void setIsUsed(List<Integer> indices) {
for (int ind: indices)
setIsUsed(ind);
}
public void setIsUsed(int ind) {
isUsed[ind] = true;
}
}
Using this approach, we are able to construct combinations from numbers that are not used yet, and iterate over the list of numbers starting from a particular position by passing the index while making a recursive call. We can be sure that any of the elements that reside prier to the current position would not be added to the current combination.
Now, a quick recap on recursion.
Every recursive implementation consists of two parts:
Base case - that represents an edge-case (or a set of edge-cases) for which the outcome is known in advance. For this problem, there are two edge-cases:
we've managed to find a combination that gives the target number, i.e. currentSum == target, and the result would be equal to target;
the end of the list is reached (and the combination doesn't result to the target), the result would be 0 (this edge-case resolves automatically by termination condition of the for loop in the recursive case, and therefore no need to treat it separately).
Recursive case - a part of a solution where recursive calls are made and where the main logic resides. In the recursive case we're iterating over the list of numbers and at each iteration step (if the index is not yet used) we are making one or two recursive calls depending on a value of the current element (depending whether we exceed the target or not). In the general, we have two opportunities: either take the current element, or ignore it. The results of these recursive calls would be added together and produce the return value of the recursive case.
Since we need a couple of additional parameters, it's a good practice to create an auxiliary overloaded method (that will be used in the client code) which expects only a list of numbers and a target value and delegates the actual work to the recursive method.
That's how it might look like.
public static int sumRecursively(List<Integer> numbers, int target) {
return sumRecursively(new ArrayList<>(numbers),
new ArrayList<>(),
new CombinationTracker(numbers.size()),
0, 0, target);
}
The actual recursive method:
private static int sumRecursively(List<Integer> numbers,
List<Integer> combination,
CombinationTracker tracker,
int currentIndex,
int currentSum, int target) {
if (currentSum == target && tracker.allNotUsed(combination)) { // base case - a combination has been found
tracker.setIsUsed(combination);
return target;
}
// recursive case
int result = 0;
for (int i = currentIndex; i < numbers.size(); i++) {
int next = numbers.get(i);
if (tracker.indexIsUsed(i)) continue;
if (currentSum + next > target) continue;
// there are two opportunities for each number: either use next number, or ignore it
// add next number
if (next + currentSum <= target) {
List<Integer> newCombination = new ArrayList<>(combination);
newCombination.add(i);
result += sumRecursively(numbers, newCombination, tracker, i + 1, currentSum + next, target);
}
// ignore next number
result += sumRecursively(numbers, new ArrayList<>(combination), tracker, i + 1, currentSum, target);
}
return result;
}
main()
public static void main(String[] args) {
System.out.println(sumRecursively(List.of(1, 3, 4, 5, 6, 6), 12));
System.out.println(sumRecursively(List.of(6, 6, 6, 6, 6, 6), 12));
}
Output:
12
36
UPD.
Got a comment that code "sucks" due to performance issues...
First of all, I do believe you have missed a point the SO community is not a kind of service which solves code interview puzzles, generally speaking, if you came here with a puzzle you already failed, so, such comments are unacceptable.
At second, yes, the code suffers from performance issues just because it is a naive bruteforce solution - I had spent on it about 15 minutes (for example, figuring out all possible combinations with target sum has O(2^N) complexity, if it does not match performance expectations that means any code based on such idea has poor performance). BTW, if you had expectations about the performance you was need to:
provide correct input constraints (saying there is 6 numbers is not correct)
provide good testcases instead of saying code does not work - that allows us to eliminate bad ideas about algorithm.
Some idea:
it seems that we do not need to compute all possible combinations with target sum, because singletons are always preferable over N-lets, pairs are either the same or do not influence on the result or interchangeable with N-lets (e.g. in case of [2,2,8,10,10] we would prefer to eliminate pairs first), but whether it is true for higher N's completely unclear - it is better to have some testcases.
Not sure I properly understand the problem, but I believe the solution is following:
public class TargetNumber {
public static void main(String[] args) {
System.out.println(score(new int[]{1, 2, 1, 4, 5, 6}, 6));
}
public static int score(int[] candidates, int target) {
List<List<Integer>> combinations = getUniqueCombinations(candidates, target);
Map<Integer, Integer> freqs = new HashMap<>();
for (int n : candidates) {
freqs.merge(n, 1, Integer::sum);
}
return score(0, combinations, freqs, target);
}
public static int score(int offset, List<List<Integer>> combinations, Map<Integer, Integer> freqs, int target) {
if (offset == combinations.size()) {
return 0;
}
int result = 0;
List<Integer> comb = combinations.get(offset);
Map<Integer, Integer> nfreq = reduce(freqs, comb);
if (nfreq != null) {
result = Math.max(result, target + score(offset, combinations, nfreq, target));
}
result = Math.max(result, score(offset + 1, combinations, freqs, target));
return result;
}
public static Map<Integer, Integer> reduce(Map<Integer, Integer> freqs, List<Integer> comb) {
Map<Integer, Integer> result = new HashMap<>(freqs);
for (int n : comb) {
if (result.merge(n, -1, Integer::sum) < 0) {
return null;
}
}
return result;
}
public static List<List<Integer>> getUniqueCombinations(int[] candidates, int target) {
List<List<Integer>> result = new ArrayList<>();
Arrays.sort(candidates);
getUniqueCombinations(candidates, target, 0, new ArrayList<>(), result);
return result;
}
public static void getUniqueCombinations(int[] candidates, int target, int index, List<Integer> solution, List<List<Integer>> result) {
for (int i = index, n = candidates.length; i < n; ) {
int num = candidates[i];
if (num > target) {
break;
}
solution.add(num);
if (num == target) {
result.add(new ArrayList<>(solution));
}
getUniqueCombinations(candidates, target - num, i + 1, solution, result);
solution.remove(solution.size() - 1);
while (i < n && num == candidates[i]) {
i++;
}
}
}
}

Best Time Complexity for Sorted 2D Array Search in Java

So I have the following code to search a sorted 2D array for a target number, but I am not sure if this is the best time complexity as in terms of Big-Oh, I read that there is a way to do in O(N), but I am not sure if my algorithm is efficient enough.
public class Search2DArray {
public static int search(int[][] arrayA, int number, int target) {
int i = 0;
int j = number - 1;
while (i < number && j >= 0) {
if (arrayA[i][j] == target) {
System.out.printf("\n Found at %d, %d", i, j);
return 1;
}
if (arrayA[i][j] > target) {
j--;
} else {
i++;
}
}
System.out.printf("\n Element not found");
return 0;
}
public static void main(String[] args) {
int arrayA[][] = {{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12}};
search(arrayA, 3, 11);
}
}
well if your 2D array is sorted you can simply reduce the rows to select and run binary search on the rows that you think that contains the target number this may reduce the complexity even better may be something in order of LOG

How can I make an array without one number of the other array?

I am trying to make a code with two arrays. The second array has the same values of the first except for the smallest number. I have already made a code where z is the smallest number. Now I just want to make a new array without z, any feedback would be appreciated.
public static int Second_Tiny() {
int[] ar = {19, 1, 17, 17, -2};
int i;
int z = ar[0];
for (i = 1; i < ar.length; i++) {
if (z >ar[i]) {
z=ar[i];
}
}
}
Java 8 streams have built in functionality that can achieve what you're wanting.
public static void main(String[] args) throws Exception {
int[] ar = {19, 1, 17, 17, -2, -2, -2, -2, 5};
// Find the smallest number
int min = Arrays.stream(ar)
.min()
.getAsInt();
// Make a new array without the smallest number
int[] newAr = Arrays
.stream(ar)
.filter(a -> a > min)
.toArray();
// Display the new array
System.out.println(Arrays.toString(newAr));
}
Results:
[19, 1, 17, 17, 5]
Otherwise, you'd be looking at something like:
public static void main(String[] args) throws Exception {
int[] ar = {19, 1, 17, 17, -2, -2, -2, -2, 5};
// Find the smallest number
// Count how many times the min number appears
int min = ar[0];
int minCount = 0;
for (int a : ar) {
if (minCount == 0 || a < min) {
min = a;
minCount = 1;
} else if (a == min) {
minCount++;
}
}
// Make a new array without the smallest number
int[] newAr = new int[ar.length - minCount];
int newIndex = 0;
for (int a : ar) {
if (a != min) {
newAr[newIndex] = a;
newIndex++;
}
}
// Display the new array
System.out.println(Arrays.toString(newAr));
}
Results:
[19, 1, 17, 17, 5]
I think the OP is on wrong track seeing his this comment:
"I am trying to find out the second smallest integer in array ar[]. I
should get an output of 1 once I am done. The way I want to achieve
that is by making a new array called newar[] and make it include all
the indexes of ar[], except without -2."
This is a very inefficient way to approach this problem. You'll have to do 3 passes, Once to find to smallest indexed element, another pass to remove the element (this is an array so removing an element will require a full pass), and another one to find smallest one again.
You should just do a single pass algorithm and keep track of the smallest two integers,
or even better use a tree for efficiency. Here are the best answers of this problem:
Find the 2nd largest element in an array with minimum number of comparisons
Algorithm: Find index of 2nd smallest element from an unknown array
UPDATE: Here is the algorithm with OP's requirements,
3 passes, and no external libraries:
public static int Second_Tiny() {
int[] ar = {19, 1, 17, 17, -2};
//1st pass - find the smallest item on original array
int i;
int z = ar[0];
for (i = 1; i < ar.length; i++) {
if (z >ar[i]){
z=ar[i];
}
}
//2nd pass copy all items except smallest one to 2nd array
int[] ar2 = new int[ar.length-1];
int curIndex = 0;
for (i=0; i<ar.length; i++) {
if (ar[i]==z)
continue;
ar2[curIndex++] = ar[i];
}
//3rd pass - find the smallest item again
z = ar2[0];
for (i = 1; i < ar2.length; i++) {
if (z >ar2[i]){
z=ar2[i];
}
}
return z;
}
This grabs the index of the element specified in variable z and then sets a second array to the first array minus that one element.
Essentially this gives ar2 = ar1 minus element z
public static int Second_Tiny() {
int[] ar = {19, 1, 17, 17, -2};
int[] ar2;
int i;
int z = ar[0];
int x = 0;
for (i = 1; i < ar.length; i++) {
if (z >ar[i]){
z=ar[i];
x=i;
}
}
ar2 = ArrayUtils.remove(ar, x);
return(z);
}

Removing duplicates from array without using Util classes

Please read the question before marking it as duplicate
I have written following code to remove duplicates from array without using Util classes but now I am stuck
public class RemoveDups{
public static void main(String[] args) {
int[] a = { 1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6, 3, 1, 4, 52, 1, 45, };
int temp;
for (int i : a) {
for (int j = 0; j < a.length - 1; j++) {
if (a[j] > a[j + 1]) {
temp = a[j];
a[j] = a[j + 1];
a[j + 1] = temp;
}
}
}
a = removeDups(a);
for (int i : a) {
System.out.println(i);
}
}
private static int[] removeDups(int[] a) {
int[] result = new int[a.length];
int j = 0;
for (int i : a) {
if (!isExist(result, i)) {
result[j++] = i;
}
}
return result;
}
private static boolean isExist(int[] result, int i) {
for (int j : result) {
if (j == i) {
return true;
}
}
return false;
}
}
and now the output is
1
2
3
4
5
6
45
52
0
0
0
0
0
0
0
0
0
0
Here my problem is
My code is not working in case of 0s
I am not able to understand how sorting an array can reduce time of execution
Is there any way to remove elements from array without using Util classes I know one way to remove convert array into list and then remove but for that also we need Util classes is there any way to implement by myself.
Since the numbers you deal with are limited to a small range you can remove duplicates by a simple "counting sort": mark the numbers you have found in a set-like data structure and then go over the data structure. An array of boolean works just fine, for less memory usage you could create a basic bitset or hash table. If n is the number of elements in the array and m is the size of the range, this algorithm will have O(n+m) complexity.
private static int[] removeDups(int[] a, int maxA) {
boolean[] present = new boolean[maxA+1];
int countUnique = 0;
for (int i : a) {
if (!present[i]) {
countUnique++;
present[i] = true;
}
}
int[] result = new int[countUnique];
int j = 0;
for (int i=0; i<present.length; i++) {
if (present[i]) result[j++] = i;
}
return result;
}
I am not able to understand how sorting an array can reduce time of execution
In a sorted array you can detect duplicates in a single scan, taking O(n) time. Since sorting is faster than checking each pair - O(n log n) compared to O(n²) time complexity - it would be faster to sort the array instead of using the naive algorithm.
As you are making the result array of the same length as array a
so even if you put only unique items in it, rest of the blank items will have the duplicate values in them which is 0 for int array.
Sorting will not help you much, as you code is searching the whole array again and again for the duplicates. You need to change your logic for it.
You can put some negative value like -1 for all the array items first in result array and then you can easily create a new result array say finalResult array from it by removing all the negative values from it, It will also help you to remove all the zeroes.
In java , arrays are of fixed length. Once created, their size can't be changed.
So you created an array of size18.
Then after you applied your logic , some elements got deleted. But array size won't change. So even though there are only 8 elements after the duplicate removal, the rest 10 elements will be auto-filled with 0 to keep the size at 18.
Solution ?
Store the new list in another array whose size is 8 ( or whatever, calculate how big the new array should be)
Keep a new variable to point to the end of the last valid element, in this case the index of 52. Mind you the array will still have the 0 values, you just won't use them.
I am not able to understand how sorting an array can reduce time of execution
What ? You sort an array if you need it to be sorted. Nothing else. Some algorithm may require the array to be sorted or may work better if the array is sorted. Depends on where you are using the array. In your case, the sorting will not help.
As for your final question , you can definitely implement your own duplicate removal by searching if an element exists more than once and then deleting all the duplicates.
My code is not working in case of 0
There were no zeroes to begin with in your array. But because its an int[], after the duplicates are removed the remaining of the indexes are filled with 0. That's why you can see a lot of zeroes in your array. To get rid of those 0s, you need to create another array with a lesser size(size should be equal to the no. of unique numbers you've in your array, excluding 0).
If you can sort your array(I see that its already sorted), then you could either bring all the zeroes to the front or push them to the last. Based on that, you can iterate the array and get the index from where the actual values start in the array. And, then you could use Arrays.copyOfRange(array, from, to) to create a copy of the array only with the required elements.
try this
package naveed.workingfiles;
public class RemoveDups {
public static void main(String[] args) {
int[] a = { 1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6, 3, 1, 4, 52, 1, 45, };
removeDups(a);
}
private static void removeDups(int[] a) {
int[] result = new int[a.length];
int j = 0;
int count = 0;
for (int i : a) {
if (!isExist(result, i)) {
result[j++] = i;
count++;
}
}
System.out.println(count + "_____________");
for (int i=0;i<count;i++) {
System.out.println(result[i]);
}
// return result;
}
private static boolean isExist(int[] result, int i) {
for (int j : result) {
if (j == i) {
return true;
}
}
return false;
}
}
public class RemoveDups {
public static void main(String[] args) {
int[] a = { 1, 2, 0, 3, 1,0, 3, 6, 2};
removeDups(a);
}
private static void removeDups(int[] a) {
int[] result = new int[a.length];
int j = 0;
int count = 0;
boolean zeroExist = false;
for (int i : a) {
if(i==0 && !zeroExist){
result[j++] = i;
zeroExist = true;
count++;
}
if (!isExist(result, i)) {
result[j++] = i;
count++;
}
}
System.out.println(count + "_____________");
for (int i=0;i<count;i++) {
System.out.println(result[i]);
}
// return result;
}
private static boolean isExist(int[] result, int i) {
for (int j : result) {
if (j == i) {
return true;
}
}
return false;
}
}
// It works even Array contains 'Zero'
class Lab2 {
public static void main(String[] args) {
int[] a = { 1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6, 3, 1, 4, 52, 1, 45 };
removeDups(a);
}
private static void removeDups(int[] a) {
int[] result = new int[a.length];
int j = 0;
int count = 0;
for (int i : a) {
if (!isExist(result, i)) {
result[j++] = i;
count++;
}
}
System.out.println(count + "_____________");
for (int i = 0; i < count; i++) {
System.out.println(result[i]);
}
}
private static boolean isExist(int[] result, int i) {
for (int j : result) {
if (j == i) {
return true;
}
}
return false;
}
}

HeapSort theory?

I am not using HeapSort to sort an array that is already filled, but am using HeapSort as the array is filled.
For a heap where the smallest values are at the top, my understanding was that when you insert a new value to the heap you checked the parent node to see if the new child is larger. If it is you do nothing, if it isn't you check and swap as need up the tree?
Is this not right because my implementation of it is not working at all:
public class HeapSort{
static int[] numbers = new int[] { 0, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 };
static int[] array = new int[16];
public static void main(String[] args) {
for (int i = 1; i < 15; i++) {
array[i] = numbers[i];
if (i > 1)
sort(i);
}
for (int i = 1; i < 15; i++) {
System.out.println(array[i]);
}
}
public static void sort(int i) {
int parentLocation = i / 2;
int childLocation = i;
int parentValue = array[parentLocation];
int childValue = array[childLocation];
if(parentValue > childValue){
array[parentLocation] = childValue;
array[childLocation] = parentValue;
}
if(parentLocation != 1){
sort(parentLocation);
}
}
}
TIA
If its anyhelp this is the output when I give it 1-15 backwards:
2
6
3
9
7
5
4
15
12
13
8
14
10
11
But you all seem as stumped as I am!
It looks like your not sorting the entire array. Say that you have 10 fields correctly sorted and you insert number. So you have
-, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11 and insert 10 (should go second last and the - is cause you never put anything there)
Now your algorithm compares parentLocation 5 (11/2) and childLocation 11 right? Well, 5 is smaller than 11 so nothing is swapped. Then you continue to sort again with input 5.
This time you compare parentLocation 2 (5/2) and childLocation 5. 2 is smaller than 5, still not change.
Until done. But you never test to see if 10 and 11 is in the correct order at all, you start half way down.
Easiest fix is to change your two iterations to
for (int i = 1; i < numbers.length; i++) {...}
...
for (int i = 1; i < array.length; i++) {...}
As your missing the end positions in your current code.
Then change the first line in sort() to
int parentLocation = i - 1;
That way your recursive check checks the entire array.
But this is regular sorting, nothing heapy about it :)
Added complete new solution :)
I'm sure this is not the optimal solution but it's easy to follow. I've replaced the target heap with an ArrayList to be able to shrink it easy.
package se.wederbrand.stackoverflow;
import java.util.ArrayList;
public class HeapSort {
static int[] numbers = new int[]{0, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1};
static ArrayList<Integer> heap = new ArrayList<Integer>();
public static void main(String[] args) {
// add 0 at the first position
heap.add(0);
for (int i = 1; i < numbers.length; i++) {
heap.add(numbers[i]);
if (i > 1) {
reheapifyBottomUp(i);
}
}
while (heap.size() > 1) {
System.out.println(removeFirstFromHeap());
}
}
private static int removeFirstFromHeap() {
// the value at index 1 should be returned
int returnValue = heap.get(1);
// the last node is replacing the removed one
if (heap.size() > 2) {
heap.set(1, heap.remove(heap.size() - 1));
reheapifyTopDown(1);
}
else {
heap.remove(1);
}
return returnValue;
}
public static void reheapifyBottomUp(int childLocation) {
int parentLocation = childLocation / 2;
int parentValue = heap.get(parentLocation);
int childValue = heap.get(childLocation);
if (parentValue > childValue) {
heap.set(parentLocation, childValue);
heap.set(childLocation, parentValue);
}
if (parentLocation != 1) {
reheapifyBottomUp(parentLocation);
}
}
public static void reheapifyTopDown(int parentLocation) {
int childLocation1 = parentLocation * 2;
int childLocation2 = childLocation1 + 1;
int parentValue = heap.get(parentLocation);
int childValue1 = Integer.MAX_VALUE;
if (heap.size() > childLocation1) {
childValue1 = heap.get(childLocation1);
}
int childValue2 = Integer.MAX_VALUE;
if (heap.size() > childLocation2) {
childValue2 = heap.get(childLocation2);
}
if (childValue1 <= childValue2 && parentValue > childValue1) {
// swap them and continue down
heap.set(parentLocation, childValue1);
heap.set(childLocation1, parentValue);
reheapifyTopDown(childLocation1);
}
else if (childValue2 < childValue1 && parentValue > childValue2) {
// swap them and continue down
heap.set(parentLocation, childValue2);
heap.set(childLocation2, parentValue);
reheapifyTopDown(childLocation2);
}
}
}
All you have done here is add a bunch of numbers to a heap (which looks correct at first glance). The array contains values in a heap -- not a sorted list. To get the sorted list out, in heap sort, you need to keep popping the smallest element and re-heaping. You're missing this step; you're just printing out the final heap before you start that process.
Your sort method should be renamed as heapify(). Your current sort() method is just re-arranging the heap.
A min/max heap is never sorted, and hence you can never traverse it the way you can traverse Binary Search Tree. You will have to implement something like removeMin() which will remove the topmost element from the heap and the sort the remaining heap.

Categories