Here I have a Java case switch where I compare 2 randomly generated 7 number integer arrays, lottery1 array is generated earlier depending on the user input. The problem I am having is, I need to compare the two arrays and count the number of matching numbers and then print the matching numbers and how many numbers were the same.
I'm trying to put the matching numbers into the array called similar, now it's just comparing the first number of lottery1 to all of the lottery2's numbers. There's plenty of tutorials on how to compare arrays that return a bool but I need the matching numbers, please help!
public class Main {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
Random rnd = new Random();
int[] lottery1 = new int[7];
for (int i = 0; i < lottery1.length; i++) {
lottery1[i] = rnd.nextInt(52);
}
Arrays.sort(lottery1);
System.out.printf("Lottery array is: %s", Arrays.toString(lottery1));
System.out.print("\nDo you want to generate an array(y/n): ");
char answer = scan.next().charAt(0);
switch (answer) {
case 'n' -> System.out.print("Goodbye!");
case 'y' -> {
int[] lottery2 = new int[7];
for (int i = 0; i < lottery2.length; i++) {
int rndNum = rnd.nextInt(52);
lottery2[i] = rndNum; //Here i fill the lottery2 with random
} numbers
Arrays.sort(lottery2);
System.out.printf("Program created an array of: %s", Arrays.toString(lottery2));
int j = 0;
int[] similar = new int[7]; //I'm trying to put the matching numbers into this new array
for (int i = 0; i < 7; i++)
{
if (lottery2[i] == lottery1[j])
{
lottery1[i] = similar[j];
i++;
j++;
}
}
System.out.printf("\nThis is how many numbers are matching: ");
System.out.printf("\nThese numbers are matching ones: ");
}
I get that you are trying to compare all numbers in 2 list and get the ones with same values I wrote this code I think it answers your question:
int[] matching = new int[7];
int[] lottery1 = new int[7];
int[] lottery2 = new int[7];
// Generate random numbers
for (int i = 0; i < 7; i++) {
lottery1[i] = (int) (Math.random() * 52.0);
lottery2[i] = (int) (Math.random() * 52.0);
}
// Compare and store matching numbers in matching array;
// The nested loop below will compare the every element of the both lists
// together and store the
// results in matching array
int matchingCount = 0;
for (int i = 0; i < 7; i++) {
for (int j = 0; j < 7; j++) {
if (lottery1[i] == lottery2[j]) {
matching[matchingCount++] = lottery1[i];
}
}
}
System.out.print("Matching Count: " + matchingCount + "\nMatch Numbers: [ ");
for (int i = 0; i < matchingCount; i++)
System.out.print(matching[i] + " ");
System.out.println("]");
int[] similar = new int[7]; //I'm trying to put the matching numbers into this new array
lottery1[i] = similar[j];
similar is an array of size 7, filled with seven 0 values (because arrays start out zeroed out). You never write anything into similar. You overwrite lottery1 with what's in similar. In other words, this code is an obtuse way to accomplish:
lottery1[i] = 0;
which surely isn't what you wanted. You also initialize similar to have size 7 but this is incorrect: Who knows how many similar numbers even exist?
You have 4 options:
Use a List<Integer> list = new ArrayList<Integer>(); - unlike arrays, arraylists don't need to be pre-sized, you can just call list.add(), and the list will take care of it. It's variable size.
Loop twice; once to determine how many matches, then you can make your similar array with the right size, and then a second time to fill it.
Make the similar array at 7, also count how many similar numbers exist, then when done copy the data over to a new array at the proper size.
Make the similar array at size 7 and use a special sentinel value (such as -1) to indicate that this one should not be shown/printed.
Also, your code is buggy: If you have replications, you overcount. Imagine lottery1 is [1,2,3,4,5,6,1] and lottery2 is [1,2,2,3,4,1,6], your algorithm would say that there are 6 matches, which doesn't sound right (the first '1' matches twice, the second '1' matches twice, and the 2 matches 2. You're going to have to think about how you want to tackle this issue.
Think about this, and write down some sample inputs + the sample output you desire, and then think about how to write code that does this. Don't just dive in.
This seems to be a good task to learn decomposition of the bigger tasks into subtasks.
The first subtask is definitely to generate an array of size K of random integer values in the given range, let's assume that for lottery the range is from 1 to N inclusive.
Then two arrays are generated, and the second subtask is to find a match between these two.
An example implementation using Stream API could be as follows:
Generate array of random integers:
static int[] getRandomArray() {
return getRandomArray(7, 52);
}
static int[] getRandomArray(int k, int n) {
int[] result = new SecureRandom().ints(1, n + 1) // n + 1 to ensure N can be included
.distinct() // make sure all elements are different
.limit(k) // pick K numbers
// .sorted() // sort the array if needed
.toArray();
System.out.println("Random array: " + Arrays.toString(result));
return result;
}
Match the results with the help of Set:
static int[] findMatch(int[] lotteryPick, int[] lotteryGuess) {
Set<Integer> set = Arrays.stream(lotteryPick).boxed().collect(Collectors.toSet());
int[] match = Arrays.stream(lotteryGuess).filter(x -> set.contains(x)).toArray();
if (match.length == 0) {
System.out.println("No matched numbers found");
} else {
String num = match.length == 1 ? " number" : " numbers";
System.out.println("Matched: " + match.length + num + ", the match: " + Arrays.toString(match));
}
System.out.println("-------------------------------");
return match;
}
Then the tests would look as simple as:
int t = 5;
while (t--> 0) {
findMatch(getRandomArray(), getRandomArray());
}
Possible output:
Random array: [26, 33, 29, 23, 49, 1, 14]
Random array: [37, 3, 27, 29, 34, 24, 36]
Matched: 1 number, the match: [29]
-------------------------------
Random array: [9, 4, 32, 27, 29, 18, 35]
Random array: [34, 2, 23, 29, 27, 6, 30]
Matched: 2 numbers, the match: [29, 27]
-------------------------------
Random array: [35, 18, 4, 42, 19, 6, 13]
Random array: [30, 8, 4, 37, 31, 9, 46]
Matched: 1 number, the match: [4]
-------------------------------
Random array: [52, 7, 47, 22, 12, 9, 26]
Random array: [46, 13, 20, 17, 1, 4, 34]
No matched numbers found
-------------------------------
Random array: [31, 40, 9, 3, 2, 49, 44]
Random array: [2, 15, 13, 36, 10, 43, 12]
Matched: 1 number, the match: [2]
-------------------------------
Related
I'm working on the following task.
Given an array of n integers and two integer numbers m and k.
You can add any positive integer to any element of the array such that
the total value does not exceed k.
The task is to maximize the
multiples of m in the resultant array.
Consider the following example.
Input:
n = 5, m = 2, k = 2, arr[] = [1, 2, 3, 4, 5]
Let's add 1 to the element arr[0] and 1 to arr[2] then the final array would be:
[2, 2, 4, 4, 5]
Now there are four (4) elements which are multiples of m (2).
I am not getting correct output.
My code:
public class Main {
public static void main(String[] args) {
int n = 5;
int m = 4;
int k = 3;
int count = 0;
int[] arr = {17, 8, 9, 1, 4};
for (int i = 0; i < n; i++) {
for (int j = 0; j <= k; j++) {
// check initial
if (arr[i] % m == 0) {
break;
}
// add
arr[i] = arr[i] + j;
// check again
if (arr[i] % m == 0) {
count++;
break;
}
}
}
System.out.println("Final Array : " + Arrays.toString(arr));
System.out.println("Count : " + count);
}
}
This task boils down to a well-known Dynamic programming algorithm called Knapsack problem after a couple of simple manipulations with the given array.
This approach doesn't require sorting and would be advantages when k is much smaller n.
We can address the problem in the following steps:
Iterate over the given array and count all the numbers that are already divisible by m (this number is stored in the variable count in the code below).
While iterating, for every element of the array calculate the difference between m and remainder from the division of this element by m. Which would be equal to m - currentElement % m. If the difference is smaller or equal to k (it can cave this difference) it should be added to the list (differences in the code below) and also accumulated in a variable which is meant to store the total difference (totalDiff). All the elements which produce difference that exceeds k would be omitted.
If the total difference is less than or equal to k - we are done, the return value would be equal to the number of elements divisible by m plus the size of the list of differences.
Otherwise, we need to apply the logic of the Knapsack problem to the list of differences.
The idea behind the method getBestCount() (which is an implementation Knapsack problem) boils down to generating the "2D" array (a nested array of length equal to the size of the list of differences +1, in which every inner array having the length of k+1) and populating it with maximum values that could be achieved for various states of the Knapsack.
Each element of this array would represent the maximum total number of elements which can be adjusted to make them divisible by m for the various sizes of the Knapsack, i.e. number of items available from the list of differences, and different number of k (in the range from 0 to k inclusive).
The best way to understand how the algorithm works is to draw a table on a piece of paper and fill it with numbers manually (follow the comments in the code, some intermediate variables were introduced only for the purpose of making it easier to grasp, and also see the Wiki article linked above).
For instance, if the given array is [1, 8, 3, 9, 5], k=3 and m=3. We can see 2 elements divisible by m - 3 and 9. Numbers 1, 8, 5 would give the following list of differences [2, 1, 1]. Applying the logic of the Knapsack algorithm, we should get the following table:
[0, 0, 0, 0]
[0, 0, 1, 1]
[0, 1, 1, 2]
[0, 1, 2, 2]
We are interested in the value right most column of the last row, which is 2 plus 2 (number of elements divisible by 3) would give us 4.
Note: that code provided below can dial only with positive numbers. I don't want to shift the focus from the algorithm to such minor details. If OP or reader of the post are interested in making the code capable to work with negative number as well, I'm living the task of adjusting the code for them as an exercise. Hint: only a small change in the countMultiplesOfM() required for that purpose.
That how it might be implemented:
public static int countMultiplesOfM(int[] arr, int k, int m) {
List<Integer> differences = new ArrayList<>();
int count = 0;
long totalDiff = 0; // counter for the early kill - case when `k >= totalDiff`
for (int next : arr) {
if (next % m == 0)
count++; // number is already divisible by `m` we can increment the count and from that moment we are no longer interested in it
else if (m - next % m <= k) {
differences.add(m - next % m);
totalDiff += m - next % m;
}
}
if (totalDiff <= k) { // early kill - `k` is large enough to adjust all numbers in the `differences` list
return count + differences.size();
}
return count + getBestCount(differences, k); // fire the rest logic
}
// Knapsack Algorithm implementation
public static int getBestCount(List<Integer> differences, int knapsackSize) {
int[][] tab = new int[differences.size() + 1][knapsackSize + 1];
for (int numItemAvailable = 1; numItemAvailable < tab.length; numItemAvailable++) {
int next = differences.get(numItemAvailable - 1); // next available item which we're trying to place to knapsack to Maximize the current total
for (int size = 1; size < tab[numItemAvailable].length; size++) {
int prevColMax = tab[numItemAvailable][size - 1]; // maximum result for the current size - 1 in the current row of the table
int prevRowMax = tab[numItemAvailable - 1][size]; // previous maximum result for the current knapsack's size
if (next <= size) { // if it's possible to fit the next item in the knapsack
int prevRowMaxWithRoomForNewItem = tab[numItemAvailable - 1][size - next] + 1; // maximum result from the previous row for the size = `current size - next` (i.e. the closest knapsack size which guarantees that there would be a space for the new item)
tab[numItemAvailable][size] = Math.max(prevColMax, prevRowMaxWithRoomForNewItem);
} else {
tab[numItemAvailable][size] = Math.max(prevRowMax, prevColMax); // either a value in the previous row or a value in the previous column of the current row
}
}
}
return tab[differences.size()][knapsackSize];
}
main()
public static void main(String[] args) {
System.out.println(countMultiplesOfM(new int[]{17, 8, 9, 1, 4}, 3, 4));
System.out.println(countMultiplesOfM(new int[]{1, 2, 3, 4, 5}, 2, 2));
System.out.println(countMultiplesOfM(new int[]{1, 8, 3, 9, 5}, 3, 3));
}
Output:
3 // input array [17, 8, 9, 1, 4], m = 4, k = 3
4 // input array [1, 2, 3, 4, 5], m = 2, k = 2
4 // input array [1, 8, 3, 9, 5], m = 3, k = 3
A link to Online Demo
You must change 2 line in your code :
if(arr[i]%m==0)
{
count++; // add this line
break;
}
// add
arr[i]=arr[i]+1; // change j to 1
// check again
if(arr[i]%m==0)
{
count++;
break;
}
The first is because the number itself is divisible.
and The second is because you add a number to it each time.That is wrong.
for example chenge your arr to :
int[] arr ={17,8,10,2,4};
your output is :
Final Array : [20, 8, 16, 8, 4]
and That is wrong because 16-10=6 and is bigger than k=3.
I believe the problem is that you aren't processing the values in ascending order of the amount by which to adjust.
To solve this I started by using a stream to preprocess the array. This could be done using other methods.
map the values to the amount to make each one, when added, divisible by m.
filter out those that equal to m' (already divisible by m`)
sort in ascending order.
Once that is done. Intialize max to the difference between the original array length and the processed length. This is the number already divisible by m.
As the list is iterated
check to see if k > amount needed. If so, subtract from k and increment max
otherwise break out of the loop (because of the sort, no value remaining can be less than k)
public static int maxDivisors(int m, int k, int[] arr) {
int[] need = Arrays.stream(arr).map(v -> m - v % m)
.filter(v -> v != m).sorted().toArray();
int max = arr.length - need.length;
for (int val : need) {
if (k >= val) {
k -= val;
max++;
} else {
break;
}
}
return max;
}
int m = 4;
int k = 3;
int[] arr ={17,8,9,1,4};
int count = maxDivisors(m, k, arr);
System.out.println(count);
prints
3
I'm having an issue with a method that creates an array of consecutive digits (i.e. if you input 1 and 10 as an argument, the array will include every number from 1-10), and then compares each number to another digit (e.g. 4) - if the numbers match (e.g. 4 == 4), then it removes that number from the array. Finally it returns that array.
I've implemented the method below which works sometimes, but not all the time and I'm not sure why?
For example, if I created a new array and printed each array:
ArrayList<Integer> omittedDigitArray = new ArrayList<Integer>(Omit.allIntegersWithout(20, 45, 3));
System.out.println("Array - Numbers with Omitted Digit:");
for (int n : omittedDigitArray) {
System.out.print(n + ", ");
}
The number 29 is omitted from the array? Could anyone tell me why please? Thanks!
// Creates the ArrayList
ArrayList<Integer> numberList = new ArrayList<Integer>();
// Loop creates an array of numbers starting at "from" ending at "to"
for (int i = from; i < to + 1; i++) {
numberList.add(i);
}
// Check the array to see whether number contains digit
// Code checks whether x contains 5, n == one digit
// IMPORTANT: Doesn't work on the first half of numbers i.e / will remove 3 but not 30
for (int j = 0; j < numberList.size(); j++) {
int number = (int) numberList.get(j); // This can be any integer
int thisNumber = number >= 0 ? number: -number; // if statement in case argument is negative
int thisDigit;
while (thisNumber != 0) {
thisDigit = thisNumber % 10; // Always equal to the last digit of thisNumber
thisNumber = thisNumber / 10; // Always equal to thisNumber with the last digit chopped off, or 0 if thisNumber is less than 10
if (thisDigit == omittedDigit) {
numberList.remove(j);
j--;
}
}
}
// Return the completed Array list
return numberList;
}
}
Your inner loop has a problem. Once you remove an element from the list, you should break from that loop. Otherwise you might remove unrelated additional numbers (if the omitted digit appears several times in the same number).
while (thisNumber != 0) {
thisDigit = thisNumber % 10; // Always equal to the last digit of thisNumber
thisNumber = thisNumber / 10; // Always equal to thisNumber with the last digit chopped off, or 0 if thisNumber is less than 10
if (thisDigit == omittedDigit) {
numberList.remove(j);
j--;
break; // add this
}
}
I ran your code (+ my suggested fix) with a range of 1 to 50 and omitted digit 4 and got :
[1, 2, 3, 5, 6, 7, 8, 9, 10, 11, 12, 13, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 28, 29, 30, 31, 32, 33, 35, 36, 37, 38, 39, 50]
The problem in your code occurs when 44 is being processed - after you remove it (due to the first 4, you continue the while loop, find another 4 and remove another number, which happens to be 39, since the numbers 40 to 43 were already removed).
My suggested solution:
ArrayList<Integer> numberList = new ArrayList<Integer>();
// Loop creates an array of numbers starting at "from" ending at "to"
for (int i = from; i < to + 1; i++) {
numberList.add(i);
}
//removing all numbers that contain the digit
numberList.removeIf(j->containsDigit(j,thisDigit));
return numberList;
}
boolean containsDigit(int number,int thisDigit){
//making sure thisDigit is positive
thisDigit=Math.abs(thisDigit)
//if thisDigit is not a digit result is false
if(thisDigit>=10) return false;
//breaking the number into its digits
List<Integer> digits=new ArrayList<Integer>();
while(number>0){
digits.add(number%10);
number=(int) number/10;
}
return digits.contains(thisDigit);
}
I have to write a program that finds all the lucky numbers from 0 to any number n.
Here's what a lucky number is:
Consider the sequence of natural numbers.
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25 ………………………………….
Removing every second number produces the sequence
1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23 ………………………….
Removing every third number produces the sequence
1, 3, 7, 9, 13, 15, 19, 21, 25 ………………………….
This process continues indefinitely by removing the fourth, fifth…and so on, till after a fixed number of steps, certain natural numbers remain indefinitely. These are known as Lucky Numbers.
I decided to try using ArrayList for this. But I can't seem to figure this small bit out. I've been trying for days now.
Here's the code:
import java.util.*;
class luckyy
{
public static void main(String args[])
{
Scanner scan = new Scanner(System.in);
System.out.println("Enter n: ");
int i, n, index;
n = scan.nextInt();
ArrayList <Integer> ele = new ArrayList <Integer> (n);
//storing in a list
for(i = 1;i<=n;i++)
{
ele.add(i);
}
System.out.println(ele);
int count = 2;
index = 1;
System.out.println("Size: "+ele.size());
while(count<ele.size())
{
for(i = 0;i<ele.size();i++)
{
int chk = ele.get(i);
if(chk%count == 0)
{
ele.remove(i);
}
}
count++;
}
System.out.print(ele);
}
}
This gives the output:
[1, 5, 7]
When the desired output is:
[1, 3, 7]
So, sorry if this code is so bad that it's offensive haha...
But I would really appreciate any help. I am just starting out as a programmer, and have a lot to learn, and would love any advice. Thanks to anyone who tries to help me!
First of all it seems to me that your assumption of the expected output is not correct. According to the task you described, the out should be something like this:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25]
[1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25] // every 2nd number removed
[1, 3, 7, 9, 13, 15, 19, 21, 25] // every 3rd number removed
[1, 3, 7, 13, 15, 19, 25] // every 4th number removed
[1, 3, 7, 13, 19, 25] // every 5th number removed
[1, 3, 7, 13, 19] // 6th number removed = final output
Beside that, I see two mistakes.
You want to remove "every n-th number", so you don't want to test the values, but their position/index in the list.
Whenever you remove an element from an ArrayList, the index of the following elements and the size of the list is reduced by 1. Means if you start with removing the "2", the next number to remove will be the "5", not the "4" as desired (assuming you are testing the index, not the value). One solution for that would be to test the indexes starting at the end of the list. In that case it wouldn't matter that higher indexes change after removing elements, because you already passed them.
Edit
Answer edited in regard to request of #Kedar Mhaswade to provide some code in order to test how removing elements from the end of the list perfoms.
This is my first approach:
List<Integer> removeBackward(List<Integer> numbers) {
int count, sPos;
count = 2;
while(count<=numbers.size())
{
for(sPos = numbers.size(); sPos >= numbers.size()-count; sPos--)
{
if(0 == sPos%count) {
break;
}
}
for(int pos = sPos; pos > 0; pos=pos-count)
{
numbers.remove(pos-1);
}
count++;
}
return numbers;
}
I did some tests (see below) with the result that it performs quite well for small sets of numbers (< 12000). On larger sets the second approach of #Kedar Mhaswade (maintaining an extra list for the elements to retain) outperforms this approach.
Therefore I tried a second approach:
The idea was, that there is no need to maintain a second list for retained elements when at first step half of the elements will be removed and the number of elements to retain decreases step by step.
So I simply moved the elements to retain to the end of the same list and maintain additional pointers in order to know the range of the retained elements. At the end of the process the final result only needs to be extracted from the end of the list.
List<Integer> retainedAtEnd(List<Integer> numbers) {
int removeX, baseQty, retainedQty, basePos, retainedPos;
removeX = 1;
baseQty = numbers.size();
while(removeX <= baseQty)
{
removeX++;
basePos = numbers.size();
retainedPos = basePos;
retainedQty = 0;
for(int checkPos = baseQty; checkPos >= 1; checkPos--)
{
if(0 != checkPos%removeX)
{
basePos = numbers.size()-baseQty+checkPos;
numbers.set(retainedPos-1, numbers.get(basePos-1));
retainedPos--;
retainedQty++;
}
}
baseQty = retainedQty;
}
return numbers.subList(numbers.size()-baseQty, numbers.size());
// return new ArrayList(numbers.subList(numbers.size()-baseQty, numbers.size()));
}
According to my test unforunately this approach doesn't perform to good on small sets (<12000). It can not compete with the first or #Kedar Mhaswade's second approach, but on larger sets, it outperforms both.
Here is how I tested:
public void test() {
int n = 1000;
long start;
System.out.println("Testing with " + n + " numbers ...");
System.out.println("Test removing elements backwards:");
List<Integer> numbers1 = Stream.iterate(1, k -> k + 1).limit(n).collect(Collectors.toList());
start = System.nanoTime();
List<Integer> out1 = this.removeBackward(numbers1);
System.out.println("Time taken:" + (System.nanoTime() - start));
// System.out.println(out1);
System.out.println("Test maintaining extra list for retained elements:");
List<Integer> numbers2 = Stream.iterate(1, k -> k + 1).limit(n).collect(Collectors.toList());
start = System.nanoTime();
List<Integer> out2 = this.extraRetainedList(numbers2);
System.out.println("Time taken:" + (System.nanoTime() - start));
// System.out.println(out2);
System.out.println("Test collecting retained elements at end of list:");
List<Integer> numbers3 = Stream.iterate(1, k -> k + 1).limit(n).collect(Collectors.toList());
start = System.nanoTime();
List<Integer> out3 = this.retainedAtEnd(numbers3);
System.out.println("Time taken:" + (System.nanoTime() - start));
// System.out.println(out3);
System.out.println("Test maintaining extra list for elements to remove:");
List<Integer> numbers4 = Stream.iterate(1, k -> k + 1).limit(n).collect(Collectors.toList());
start = System.nanoTime();
List<Integer> out4 = this.extraDeletedList(numbers4);
System.out.println("Time taken:" + (System.nanoTime() - start));
// System.out.println(out4);
}
This is a tricky problem! I went about it in a slightly different fashion and used another list to store the deleted elements. This is required because of the data structure that I chose. Since I wanted to use integers only and I was using an ArrayList, every time I remove an element, the list gets immediately adjusted. What we really need to do is mark the element for deletion. There are more than one way to do this, but I chose to maintain another list of deleted elements (since all the elements are unique, it is fine to use this idea).
Here is my first attempt then:
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/** <p>
* Find the lucky numbers amongst natural numbers from 1 to n.
* Here's how you find Lucky numbers.
* </p>
* Created by kmhaswade on 2/27/16.
*/
public class Lucky {
public static void main(String[] args) {
printLucky1(Integer.valueOf(args[0]));
}
private static void printLucky1(int n) {
List<Integer> numbers = Stream.iterate(1, k -> k + 1).limit(n).collect(Collectors.toList());
System.out.println(numbers);
int delIndex = 1; // index of the element to be removed, we start with 2nd element
while (delIndex < numbers.size()) {
List<Integer> deleted = new ArrayList<>();
for (int i = delIndex; i < numbers.size(); i += (delIndex + 1)) {
deleted.add(numbers.get(i));
}
numbers.removeAll(deleted); // expensive operation!
System.out.println(numbers);
delIndex += 1;
}
System.out.println("number of lucky numbers:" + numbers.size());
System.out.println(numbers);
}
}
This works! But for really long lists, this is very slow, because of the expensive operation: numbers.removeAll(deleted) -- we are removing bunch of elements from an ArrayList that has to move all affected elements on every deletion!
For instance, with the first 100_000 natural numbers, it takes about 10 seconds on my computer. Clearly, I looked for an alternative. What if we devise another list and collect the elements that we want to retain, and then in the next iteration, this list of retained elements becomes our list to operate on? It looked like that will work better because there is no deletion of elements involved. You will still need to have another ArrayList to collect the elements. In analysis terms, this is an O(n) additional space (or c.n where c ~ 0.5).
Here's my second attempt then:
private static void printLucky2(int n) {
List<Integer> numbers = Stream.iterate(1, k -> k + 1).limit(n).collect(Collectors.toList());
System.out.println(numbers);
int delIndex = 1; // index of the element to be removed, we start with 2nd element
while (delIndex < numbers.size()) {
List<Integer> retained = new ArrayList<>();
for (int i = 0; i < numbers.size(); i += 1)
if ((i+1) % (delIndex + 1) != 0)
retained.add(numbers.get(i));
numbers = retained;
System.out.println(numbers);
delIndex += 1;
}
System.out.println("number of lucky numbers:" + numbers.size());
System.out.println(numbers);
}
There may be more improvements possible because for really large inputs the time taken by this algorithm may still be unacceptable (will work on that improvement). But I already see two orders of magnitude improvement!
Here's the complete code. I made sure that both the methods return lists that are same (list1.equals(list2) returns true) and here is the output on my computer (with first 100_000 numbers):
[1, 3, 7, ...]
number of lucky numbers: 357
time taken: 6297
number of lucky numbers: 357
[1, 3, ...]
time taken: 57
for anyone still interested, I found another way to do this.
It isn't revolutionary or anything, and it uses a lot of the stuff the people on this thread told me, but it sort of summarizes all the advice I guess.
I felt it only fair to post my answer.
So, it involves iterating through every element, storing all the elements you need to remove in each round of counting, and then using the removeAll function to remove them before the count increases.
Here's the complete code for anyone interested. Any comments would also be welcome.
import java.util.*;
class luckyy
{
public static void main(String args[])
{
Scanner scan = new Scanner(System.in);
System.out.println("Enter n: ");
int i, n, index;
n = scan.nextInt();
ArrayList <Integer> ele = new ArrayList <Integer> (n);
ArrayList <Integer> toRemove = new ArrayList <Integer> (n);
//storing in a list
for(i = 1;i<=n;i++)
{
ele.add(i);
}
System.out.println(ele);
int count = 2;
System.out.println("Size: "+ele.size());
while(count<=ele.size())
{
for(i = 0;i<ele.size();i++)
{
if((i+1)%count == 0)
{
toRemove.add(ele.get(i));
}
}
ele.removeAll(toRemove);
toRemove.clear();
count++;
}
System.out.println(ele);
}
}
There it is! It works, and boy am I glad! If anyone has any further advice, or anything else for me to learn or checkout, you are totally welcome to comment.
Thanks again everyone!
Here is the program task:
Write a method called collapse that accepts an array of integers as a parameter and returns a new array containing the result of replacing each pair of integers with the sum of that pair.
For example, if an array called list stores the values
{7, 2, 8, 9, 4, 13, 7, 1, 9, 10}
then the call of collapse(list) should return a new array containing:
{9, 17, 17, 8, 19}.
The first pair from the original list is collapsed into 9 (7 + 2), the second pair is collapsed into 17 (8 + 9), and so on. If the list stores an odd number of elements, the final element is not collapsed.
For example, if the list had been {1, 2, 3, 4, 5}, then the call would return {3, 7, 5}. Your method should not change the array that is passed as a parameter.
Here is my currently-written program:
public static int[] collapse(int[] a1) {
int newArrayLength = a1.length / 2;
int[] collapsed = new int[newArrayLength];
int firstTwoSums = 0;
for (int i = 0; i < a1.length-1; i++) {
firstTwoSums = a1[i] + a1[i+1];
collapsed[collapsed.length-1] = firstTwoSums;
}
return collapsed;
}
I pass in an array of {7, 2, 8, 9, 4, 13, 7, 1, 9, 10} and I want to replace this array with {9, 17, 17, 8, 19}.
Note:{9, 17, 17, 8, 19} will be obtained through the for-loop that I have written.
Currently, I am having trouble with adding the integers I obtained to my "collapsed" array. It'd be a great help if you could help me or at least give me some guidance on how to do this.
Thanks in advance!
First you have to understand what is going on.
You have an array of certain size where size can either be even or odd. This is important because you are using a1.length/2 to set the size for new array, so you will also have to check for odd and even values to set the size right else it won't work for odd sized arrays. Try a few cases for better understanding.
Here's a way of doing it.
public static int[] collapseThis(int[] array) {
int size = 0;
if(isEven(array.length))
size = array.length/2;
else
size = array.length/2+1;
int[] collapsedArray = new int[size];
for(int i=0, j=0; j<=size-1; i++, j++) {
if(j==size-1 && !isEven(array.length)) {
collapsedArray[j] = array[2*i];
}
else {
collapsedArray[j] = array[2*i]+array[2*i+1];
}
}
return collapsedArray;
}
private static boolean isEven(int num) {
return (num % 2 == 0);
}
Using
collapsed[collapsed.length-1] = firstTwoSums;
The sum of your numbers will be always be put in the same index of the collapsed array, because collapsed.length - 1 is a constant value.
Try creating a new variable starting at zero, that can be incremented each time you add a sum to collapsed. For instance,
int j = 0;
for(...) {
...
collapsed[j++] = firstTwoSums;
}
I think this is a convenient answer.
public static void main(String[] args){
int[] numbers = {1,2,3,4,5};
int[] newList = collapse(numbers);
System.out.println(Arrays.toString(newList));
}
public static int[] collapse(int[] data){
int[] newList = new int[(data.length + 1)/2];
int count = 0;
for (int i = 0; i < (data.length / 2); i++){
newList[i] = data[count] + data[count + 1];
System.out.println(newList[i]);
count = count + 2;
}
if (data.length % 2 == 1){
newList[(data.length / 2)] = data[data.length - 1];
}
return newList;
}
i would combine the cases for the array with either odd or even elements together as below:
public static int[] collapse(int[] a1) {
int[] res = new int[a1.length/2 + a1.length % 2];
for (int i = 0; i < a1.length; i++)
res[i/2] += a1[i];
return res;
}
public static int[] collapse(int[] a1) {
int newArrayLength = a1.length / 2;
int[] collapsed;
if(a1.length%2 == 0)
{
collapsed = new int[newArrayLength];
}
else
{
collapsed = new int[newArrayLength+1];
collapsed[newArrayLength] = a1[a1.length-1];
}
int firstTwoSums = 0;
for (int i = 0; i < newArrayLength; i++) {
firstTwoSums = a1[i*2] + a1[i*2+1];
collapsed[i] = firstTwoSums;
}
return collapsed;
}
I modified your code and you may try it first.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Find a pair of elements from an array whose sum equals a given number
I was recently presented with the following Java interview question.
The target is to complete the method task with only a single pass over the input array.
I claimed it is not possible to complete this task on a single pass over the array but I was met with the usual silence, pause and then the interviewer proclaimed the interview was at an end without giving me the answer.
public class SortedArrayOps {
public SortedArrayOps() {
}
// Print at the system out the first two ints found in the sorted array: sortedInts[] whose sum is equal to Sum in a single pass over the array sortedInts[] with no 0 value allowed.
// i.e. sortedInts[i] + sortedInts[?] = Sum where ? is the target index to be found to complete the task.
static void PrintIntSumValues(int Sum, int sortedInts[]) {
// need to test to see if the Sum value is contained in the array sortedInts. And, if not do nothing.
for(int i=0; i<sortedInts.length; i++) {
// ... do some work: algebra and logic ...
// System.out.println sortedInts[i]+sortedInts[?] sums to Sum.
}
}
public static void main(String[] args) {
final int[] sortedArray = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50};
PrintIntSumValues(48, sortedArray);
}
}
I am not sure which values in the array you are looking for (what does "first two" ints mean? Minimum sum of their indices? One is smallest? Any two that happen to pop out first?), but this solution is O(n), takes one pass, uses no additional data structures, and only uses one extra int. It does not always find the two indices closest together, nor does it always find the "first", whatever that might mean. I believe that it will always find the two whose sum is smallest (until you guys find a counter example).
Let me know if you guys find any bugs with it:
class Test {
public static void main(String[] args) {
int[] sortedArray = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
PrintIntSumValues(6, sortedArray);
sortedArray = new int[] {1, 2,3, 12, 23423};
PrintIntSumValues(15, sortedArray);
sortedArray = new int[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
PrintIntSumValues(100, sortedArray);
sortedArray = new int[] {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50};
PrintIntSumValues(48, sortedArray);
}
// Print at the system out the first two ints found in the sorted array: sortedInts[] whose sum is equal to Sum in a single pass over the array sortedInts[] with no 0 value allowed.
// i.e. sortedInts[i] + sortedInts[?] = Sum where ? is the target index to be found to complete the task.
static void PrintIntSumValues(int Sum, int sortedInts[]) {
// need to test to see if the Sum value is contained in the array sortedInts. And, if not do nothing.
int offset = sortedInts.length-1;
for(int i=0; i<sortedInts.length; i++) {
// ... do some work: algebra and logic ...
if ((sortedInts[i] + sortedInts[offset]) == Sum){
System.out.println("sortedInts[" + i + "]+sortedInts[" + offset + "] sums to " + Sum + ".");
return;
} else {
int remaining = Sum - sortedInts[i];
if (remaining < sortedInts[i] ){
// We need something before i
if (remaining < sortedInts[offset]) {
// Even before offset
offset = 0 + (offset - 0)/2;
} else {
// Between offset and i
offset = offset + (i - offset)/2;
}
} else {
// We need something after i
if (remaining < sortedInts[offset]) {
// But before offset
offset = i + (offset - i)/2;
} else {
// Even after offset
offset = offset + (sortedInts.length - offset)/2;
}
}
}
}
System.out.println("There was no sum :(");
}
}
You can view the output here.
import java.util.HashMap;
public class SortedArrayOps {
public SortedArrayOps() {
}
// Print at the system out the first two ints found in the sorted array: sortedInts[] whose sum is equal to Sum in a single pass over the array sortedInts[] with no 0 value allowed.
// i.e. sortedInts[i] + sortedInts[?] = Sum where ? is the target index to be found to complete the task.
static void PrintIntSumValues(int Sum, int sortedInts[]) {
HashMap<Integer, Boolean> pool= new HashMap<Integer, Boolean> ();
for(int i=0; i<sortedInts.length; i++) {
int current = sortedInts[i];
int target = Sum - current;
if (pool.containsKey(target)) {
System.out.println(String.format("%d and %d sum to %d", current, target, Sum));
break;
}
else {
pool.put(current, Boolean.TRUE);
}
}
}
public static void main(String[] args) {
final int[] sortedArray = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50};
PrintIntSumValues(48, sortedArray);
}
}
Here is a complete solution using a HashMap:
import java.util.HashMap;
public class Test
{
public static void main(String[] args)
{
final int[] sortedArray = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int sum = 6;
printSum(sum, sortedArray);
}
private static void printSum(int sum, int[] sortedArray)
{
HashMap<Integer, Integer> map = new HashMap<Integer, Integer>();
for (int index = 0; index < sortedArray.length; index++)
{
int currentNumber = sortedArray[index];
int remainder = sum - currentNumber;
if (map.containsKey(remainder))
{
System.out.println(String.format("%d + %d = %d", currentNumber, remainder, sum));
break;
}
else
{
map.put(currentNumber, index);
}
}
}
}
This should work. You have two pointers, and make only a single pass through the data.
j = sortedInts.length - 1;
for(int i=0; i<sortedInts.length && j>=i; i++) {
sx = sortedInts[i];
while (sx + sortedInts[j] > Sum)
j++;
if (sx + sortedInts[j] == Sum)
...
}
Because the array of values is specific, the solution can be simplified as this,
public class SortedArrayOps {
public SortedArrayOps() {
}
// Print at the system out the first two ints found in the sorted array:
// sortedInts[] whose sum is equal to Sum in a single pass over the array
// sortedInts[] with no 0 value allowed.
// i.e. sortedInts[i] + sortedInts[?] = Sum where ? is the target index to
// be found to complete the task.
static void PrintIntSumValues(int Sum, int sortedInts[]) {
// need to test to see if the Sum value is contained in the array
// sortedInts. And, if not do nothing.
for (int i = 0; i < sortedInts.length; i++) {
// ... do some work: algebra and logic ...
// System.out.println sortedInts[i]+sortedInts[?] sums to Sum.
int remainder = Sum - sortedInts[i];
if( remainder <= sortedInts.length && remainder>0 && remainder!=sortedInts[i]) {
System.out.print(String.format("%d + %d = %d", sortedInts[i], sortedInts[remainder-1], Sum));
break;
}
}
}
public static void main(String[] args) {
final int[] sortedArray = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45,
46, 47, 48, 49, 50 };
PrintIntSumValues(48, sortedArray);
}
}