Algorithm for removing duplicates from ArrayList - java

I have an ArrayList<String> that contains the following:
2#3#1#0
1#0#4#1
9#2#5#0
4#2#3#2
1#1#2#1
Output: 6 different numbers.
I'm trying to write an algorithm that removes duplicates of the highlighted numbers so I can then use a counter to see how many different numbers in total in all of those locations are.
I've tried many things including some of the following: [Java remove duplicates from array using loops][1], [Java - Removing duplicates in an ArrayList][2], the first option in [How to find duplicates in Java array?][3] and many more. I've spent at least 5-10h just trying to figure what I'm doing wrong, but I can not, so I've turned to you.
Most of the time the solutions I find online seem to work on simple stuff, but not in my case. In it, when I try to print the different characters, it always returns the wrong int numbers.
I've also tried, also tried separating each line of numbers into a different int Array[] and then comparing, but it just won't catch all the different values.
In another example where I had 5 different numbers in total, I kept getting "4 different" as a result, so I even tried long n = ArrayList.stream().distinct().count(); just to see if I was doing something wrong, but even this thing returned "4 different" numbers.
I know the easiest way is using Set and Map, but I don't want that. I'd like to have an algorithm.
EDIT:
One of the many things I've tried is the following:
for (int m = 0; m < (size-1); m++){
for (int j = m + 1; j < size; j++){
if (ArrayList.get(j).charAt(0) != ArrayList.get(m).charAt(0)){
continue;
}
current++;
ArrayList.remove(j).charAt(0);
j--;
size--;
}
}
With this one, I'd have to use another one for the ArrayList.get().charAt(4).
EDIT2:
I've found the following code [here][1], but how would it be implemented in this case?
public static <T> ArrayList<T> uniquefy(ArrayList<T> myList) {
ArrayList <T> uniqueArrayList = new ArrayList<T>();
for (int i = 0; i < myList.size(); i++){
if (!uniqueArrayList.contains(myList.get(i))){
uniqueArrayList.add(myList.get(i));
}
}
return uniqueArrayList;
}
EDIT3:
I've found a possible solution, but it gives me an IndexOutOfBoundsException.
I've put the numbers 2, 1, 9, 4, 1 into Array1 and 1, 4, 5, 3, 2 into Array2, but when I try to compare them, I get the mentioned error.
boolean stopSequence = false;
for (int i = 0; i < Array1.length; i++){
for (int a = 0; a < Array2.length && !stopSequence;){
if (Array1[i] != Array2[a]){
Array1[i] = 0;
a++;
}
if (Array1[i] == Array2[a]){
Array1[i] = 0;
stopSequence = true;
}
}
stopSequence = false;
}
[1]: https://stackoverflow.com/questions/26998156/java-remove-duplicates-from-array-using-loops
[2]: https://stackoverflow.com/questions/2435156/java-removing-duplicates-in-an-arraylist
[3]: http://javarevisited.blogspot.com.es/2015/06/3-ways-to-find-duplicate-elements-in-array-java.html
[4]: https://stackoverflo
w.com/questions/203984/how-do-i-remove-repeated-elements-from-arraylist?rq=1

The algorithm is much simpler than what you think it is:
transform every string into a pair of characters
putting all the characters into a collection or stream that removes duplicates
counting the number of characters.
Here is a complete example:
import java.util.Arrays;
import java.util.List;
import java.util.stream.IntStream;
public class Duplicates {
public static void main(String[] args) {
List<String> list = Arrays.asList("2#3#1#0",
"1#0#4#1",
"9#2#5#0",
"4#2#3#2",
"1#1#2#1");
System.out.println(
list.stream()
.flatMapToInt(s -> IntStream.of(s.charAt(0), s.charAt(4)))
.distinct()
.count());
}
}
EDIT: You seem to want to obey absurd restrictions, and thus neither use a Stream nor a Set, where these completely make sense. Here's code only using lists, but doing basically the same thing as above, but in a much less efficient way:
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class Duplicates {
public static void main(String[] args) {
List<String> list = Arrays.asList("2#3#1#0",
"1#0#4#1",
"9#2#5#0",
"4#2#3#2",
"1#1#2#1");
List<Character> uniqueChars = new ArrayList<>();
for (String s : list) {
Character c0 = s.charAt(0);
Character c4 = s.charAt(4);
if (!uniqueChars.contains(c0)) {
uniqueChars.add(c0);
}
if (!uniqueChars.contains(c4)) {
uniqueChars.add(c4);
}
}
System.out.println(uniqueChars.size());
}
}

It's not that difficult to count different numbers of the highlighted locations.you can use helper array called frequency array to get the expected result.
Try this simple algorithm using frequency array I think it worked perfectly for your case:
ArrayList<String> numlist=new ArrayList<String>();
int freq[] = new int [10];
numlist.add("2#3#1#0");
numlist.add("1#0#4#1");
numlist.add("9#2#5#0");
numlist.add("4#2#3#2");
numlist.add("1#1#2#1");
for(int i = 0; i < numlist.size(); i++){
String row = numlist.get(i);
int numValue1 = Character.getNumericValue(row.charAt(0));
int numValue2 = Character.getNumericValue(row.charAt(4));
freq[numValue1]++;
freq[numValue2]++;
}
int count = 0;
for(int i = 0; i < 10; i++){
if(freq[i] > 0){
count++;
}
}
System.out.println(count + " different numbers");
Output:
6 different numbers

Another option with bit masks:
public static void main(String[] args) {
List<String> arrayList = Arrays.asList("2#3#1#0", "1#0#4#1", "9#2#5#0", "4#2#3#2", "1#1#2#1");
int mask = 0;
for(String s : arrayList) { // Place the bits
mask = mask | (1 << Character.getNumericValue(s.charAt(0))) | (1 << Character.getNumericValue(s.charAt(4)));
}
int counter = 0;
for(int i = 0; i < 32; i++) { // count the bits
counter += (mask & (1 << i)) == 1 << i ? 1 : 0;
}
System.out.println(counter);
}
Output:
6
This relies on the bit mask which is at the end of the execution of the code:
1000111110
Possibly this is faster than most solutions, since it does not rely on conventional data structures.

Well, a good practice is always to divide the problem into smaller parts:
For example, a good design would be a class with these members:
digits: This is an instance variable of array of ints to contain the number of times each digit was repeated. It must be pre-sized to the maximum allowed digit (I guess that is 9).
differentDigits: The is an instance variable to contain the number of different digits.
processList: This method shall receive the list to browse it and call processItem for each item.
processItem: This method shall receive an item String and parse the digits according to the specified format (through StringTokenizer, for example), and call storeDigit for each required digit.
storeDigit: This method shall receive an int and use it to index the instance array digits, and increment the indexed position. If the indexed position was 0, it should also increment differentDigits.

Related

How to sort elements in an int array to create the largest number possible

I have an exercise to sort an array (type int) so I can get the largest number possible.
An example:
1,3,9 ==> 931
1,3,9,60 ==> 96031
So here is my idea: It is impossible to just sort the array to form the number that I wanted. So I can check the first number of each element in array, using the very same idea as bubble sort, just one small difference is that i use the first element to check instead of just arr[i]. But I still want to know beside using my idea, are there any other way (more efficiency). Even if your idea are the very same with my idea but you have something upgrade.
Thank you very much
It is impossible to just sort the array to form the number that I wanted.
Actually, it isn't impossible.
What you need is to design and implement an ordering that will result in the (decimal) numbers that will make the final number to be largest to sort first; e.g. for the numbers in your question, the ordering is:
9 < 60 < 3 < 1
You just need to work out exactly what the required ordering is for all possible non-negative integers. Once you have worked it out, code a Comparator class that implements the ordering.
Hint: You would be able to specify the ordering using recursion ...
Solution
For the descending order we multiply here by -1 each value in the array then sort the array and then multiply back with -1.
Ultimately we build the result string with string concatenation and print it out
import java.util.Arrays;
public class MyClass {
public static void main(String args[]) {
int[] array = {3,1,9};
for (int l = 0; l < array.length; l++){
array[l] = array[l]*-1;
}
Arrays.sort(array);
for (int l = 0; l < array.length; l++){
array[l] = array[l]*-1;
}
String res = "";
for(int i = 0; i < array.length; i++){
res+=array[i];
}
System.out.println(res);
}
}
Output
931
Alternatively
Or as #Matt has mentioned in the comments you can basically concat the string in reverse order. Then there is no need anymore for the ascending to descending transformation with *-1
import java.util.Arrays;
public class MyClass {
public static void main(String args[]) {
int[] array = {
9,
1,
3
};
String res = "";
Arrays.sort(array);
for (int l = array.length - 1; l >= 0; l--) {
res += array[l];
}
System.out.println(res);
}
}
Hope it will work as per your requirement->
public static void main(String[] args) {
Integer[] arr = {1,3,3,9,60 };
List<Integer> flat = Arrays.stream(arr).sorted((a, b) -> findfirst(b) - findfirst(a)).collect(Collectors.toList());
System.out.println(flat);
}
private static int findfirst(Integer a) {
int val = a;
if(val>=10) {
while (val >= 10) {
val = val / 10;
}
}
return val;
}
A lot of problems become easier when using Java streams. In this case you could convert all numbers to String and then sort in an order which picks the higher String value of two pairings, then finally join each number to one long one.
This works for your test data, but does NOT work for other data-sets:
List<Integer> list1 = List.of(1,3,9,60);
Comparator<String> compare1 = Comparator.reverseOrder();
String num1 = list1.stream().map(String::valueOf).sorted(compare1).collect(Collectors.joining(""));
The comparator Comparator.reverseOrder() does not work for numbers of different length which start with same values, so a more complex compare function is needed which concatenates values to decide ordering, something like this which implies that "459" > "45" > "451"
List<Integer> list2 = List.of(1,45,451,449,450,9, 4, 459);
Comparator<String> compare = (a,b) -> (b+a).substring(0, Math.max(a.length(), b.length())).compareTo((a+b).substring(0, Math.max(a.length(), b.length())));
String num2 = list2.stream().map(String::valueOf).sorted(compare).collect(Collectors.joining(""));
... perhaps.
compare first number of each int then if it is the biggest put it at beginning then you continue, if first char is equal step into the second etc etc the bigest win, if it same at max-char-size. the first selected would be pushed then the second one immediatly after as you already know.
In that maneer 9 > 60 cuz 960>609 the first char will always be the biggest in that case when u concat.
it's > 9 < not > 09 <

Java program to find the duplicate values of an array of integer using simple loop

public class ArrayTest{
public static void main(String[] args) {
int array[] = {32,3,3,4,5,6,88,98,9,9,9,9,9,9,1,2,3,4,5,6,4,3,7,7,8,8,88,88};
for(int i= 0;i<array.length-1;i++){
for(int j=i+1;j<array.length;j++){
if((array[i])==(array[j]) && (i != j)){
System.out.println("element occuring twice are:" + array[j]);
}
}
}
}
}
this program work fine but when i compile it, it print the values again and again i want to print the duplicate value once for example if 9 is present 5 times in array so it print 9 once and if 5 is present 6 times or more it simply print 5...and so on....this what i want to be done. but this program not behave like that so what am i missing here.
your help would be highly appreciated.
regards!
Sort the array so you can get all the like values together.
public class ArrayTest{
public static void main(String[] args) {
int array[] = {32,3,3,4,5,6,88,98,9,9,9,9,9,9,1,2,3,4,5,6,4,3,7,7,8,8,88,88};
Arrays.sort(array);
for (int a = 0; a < array.length-1; a++) {
boolean duplicate = false;
while (array[a+1] == array[a]) {
a++;
duplicate = true;
}
if (duplicate) System.out.println("Duplicate is " + array[a]);
}
}
}
The problem statement is not clear, but lets assume you can't sort (otherwise the problem greatly simplifies). Lets also assume the space complexity is constrained, and you can't keep a Map, etc, for counting the frequency.
You can use use lookbehind, but this unnecessarily increases the time complexity.
I think a reasonable approach is to reserve the value -1 to indicate that an array position has been processed. As you process the array, you update each active value with -1. For example, if the first element is 32, then you scan the array for any value 32, and replace with -1. The time complexity does not exceed O(n^2).
This leaves the awkcase case where -1 is an actual value. It would be required to do a O(n) scan for -1 prior to the main code.
If the array must be preserved, then clone it prior to processing. The O(n^2) loop is:
for (int i = 0; i < array.length - 1; i++) {
boolean multiple = false;
for (int j = i + 1; j < array.length && array[i] != -1; j++) {
if (array[i] == array[j]) {
multiple = true;
array[j] = -1;
}
}
if (multiple)
System.out.println("element occuring multiple times is:" + array[i]);
}
What you can do, is use a data structure that only contains unique values, Set. In this case we use a HashSet to store all the duplicates. Then you check if the Set contains your value at index i, if it does not then we loop through the array to try and find a duplicate. If the Set contains that number already, we know it's been found before and we skip the second for loop.
int array[] = {32,3,3,4,5,6,88,98,9,9,9,9,9,9,1,2,3,4,5,6,4,3,7,7,8,8,88,88};
HashSet<Integer> duplicates = new HashSet<>();
for(int i= 0;i<array.length-1;i++)
{
if(!duplicates.contains(array[i]))
for(int j=i+1;j<array.length;j++)
{
if((array[i])==(array[j]) && (i != j)){
duplicates.add(array[i]);
break;
}
}
}
System.out.println(duplicates.toString());
Outputs
[3, 4, 5, 6, 7, 88, 8, 9]
I recommend using a Map to determine whether a value has been duplicated.
Values that have occurred more than once would be considered as duplicates.
P.S. For duplicates, using a set abstract data type would be ideal (HashSet would be the implementation of the ADT), since lookup times are O(1) since it uses a hashing algorithm to map values to array indexes. I am using a map here, since we already have a solution using a set. In essence, apart from the data structure used, the logic is almost identical.
For more information on the map data structure, click here.
Instead of writing nested loops, you can just write two for loops, resulting in a solution with linear time complexity.
public void printDuplicates(int[] array) {
Map<Integer, Integer> numberMap = new HashMap<>();
// Loop through array and mark occurring items
for (int i : array) {
// If key exists, it is a duplicate
if (numberMap.containsKey(i)) {
numberMap.put(i, numberMap.get(i) + 1);
} else {
numberMap.put(i, 1);
}
}
for (Integer key : numberMap.keySet()) {
// anything with more than one occurrence is a duplicate
if (numberMap.get(key) > 1) {
System.out.println(key + " is a reoccurring number that occurs " + numberMap.get(key) + " times");
}
}
}
Assuming that the code is added to ArrayTest class, you could all it like this.
public class ArrayTest {
public static void main(String[] args) {
int array[] = {32,3,3,4,5,6,88,98,9,9,9,9,9,9,1,2,3,4,5,6,4,3,7,7,8,8,88,88};
ArrayTest test = new ArrayTest();
test.printDuplicates(array);
}
}
If you want to change the code above to look for numbers that reoccur exactly twice (not more than once), you can change the following code
if (numberMap.get(key) > 1) to if (numberMap.get(key) == 2)
Note: this solution takes O(n) memory, so if memory is an issue, Ian's solution above would be the right approach (using a nested loop).
// print duplicates
StringBuilder sb = new StringBuilder();
int[] arr = {1, 2, 3, 4, 5, 6, 7, 2, 3, 4};
int l = arr.length;
for (int i = 0; i < l; i++)
{
for (int j = i + 1; j < l; j++)
{
if (arr[i] == arr[j])
{
sb.append(arr[i] + " ");
}
}
}
System.out.println(sb);
Sort the array. Look at the one ahead to see if it is duplicate. Also look at one behind to see if this was already counted as duplicate (except when i == 0, do not look back).
import java.util.Arrays;
public class ArrayTest{
public static void main(String[] args) {
int array[] = {32,32,3,3,4,5,6,88,98,9,9,9,9,9,9,1,2,3,4,5,6,4,3,7,7,8,8,88,88};
Arrays.sort(array);
for(int i= 0;i<array.length-1;i++){
if((array[i])==(array[i+1]) && (i == 0 || (array[i]) != (array[i-1]))){
System.out.println("element occuring twice are:" + array[i]);
}
}
}
}
prints:
element occuring twice are:3
element occuring twice are:4
element occuring twice are:5
element occuring twice are:6
element occuring twice are:7
element occuring twice are:8
element occuring twice are:9
element occuring twice are:32
element occuring twice are:88

Two sum - Doesn't work

Given an array of integers, return indices of the two numbers such that they add up to a specific target.
You may assume that each input would have exactly one solution, and you may not use the same element twice.
Consider input [3,2,4] and target is 6. I added (3,0) and (2,1) to the map and when I come to 4 and calculate value as 6 - 4 as 2 and when I check if 2 is a key present in map or not, it does not go in if loop.
I should get output as [1,2] which are the indices for 2 and 4 respectively
public int[] twoSum(int[] nums, int target) {
int len = nums.length;
int[] arr = new int[2];
Map<Integer,Integer> map = new HashMap<Integer,Integer>();
for(int i = 0;i < len; i++)
{
int value = nums[i] - target;
if(map.containsKey(value))
{
System.out.println("Hello");
arr[0] = value;
arr[1] = map.get(value);
return arr;
}
else
{
map.put(nums[i],i);
}
}
return null;
}
I don't get where the problem is, please help me out
Given an array of integers, return indices of the two numbers such that they add up to a specific target.
You may assume that each input would have exactly one solution, and you may not use the same element twice. Consider input [3,2,4] and target is 6. I added (3,0) and (2,1) to the map and when I come to 4 and calculate value as 6 - 4 as 2 and when I check if 2 is a key present in map or not, it does not go in if loop.
Okay, let's take a step back for a second.
You have a list of values, [3,2,4]. You need to know which two will add up 6, well, by looking at it we know that the answer should be [1,2] (values 2 and 4)
The question now is, how do you do that programmatically
The solution is (to be honest), very simple, you need two loops, this allows you to compare each element in the list with every other element in the list
for (int outter = 0; outter < values.length; outter++) {
int outterValue = values[outter];
for (int inner = 0; inner < values.length; inner++) {
if (inner != outter) { // Don't want to compare the same index
int innerValue = values[inner];
if (innerValue + outterValue == targetValue) {
// The outter and inner indices now form the answer
}
}
}
}
While not highly efficient (yes, it would be easy to optimise the inner loop, but given the OP's current attempt, I forewent it), this is VERY simple example of how you might achieve what is actually a very common problem
int value = nums[i] - target;
Your subtraction is backwards, as nums[i] is probably smaller than target. So value is getting set to a negative number. The following would be better:
int value = target - nums[i];
(Fixing this won't fix your whole program, but it explains why you're getting the behavior that you are.)
This code for twoSum might help you. For the inputs of integer array, it will return the indices of the array if the sum of the values = target.
public static int[] twoSum(int[] nums, int target) {
int[] indices = new int[2];
outerloop:
for(int i = 0; i < nums.length; i++){
for(int j = 0; j < nums.length; j++){
if((nums[i]+nums[j]) == target){
indices[0] = i;
indices[1] = j;
break outerloop;
}
}
}
return indices;
}
You can call the function using
int[] num = {1,2,3};
int[] out = twoSum(num,4);
System.out.println(out[0]);
System.out.println(out[1]);
Output:
0
2
You should update the way you compute for the value as follows:
int value = target - nums[i];
You can also check this video if you want to better visualize it. It includes Brute force and Linear approach:

How to randomly combine elements of 2 arrays while making sure to not reuse an element until all have been used at least once?

Essentially I'm writing a program that produces random poems out of an array of nouns and an array of adjectives.
This is accomplished basically using this line
String poem = adjectives[rand.nextInt(3)]+" "+ nouns[rand.nextInt(3)];
Simple enough, but I'm supposed to make sure that it doesn't reuse the same noun or adjective for the next poems until all of them have been used at least once already. I'm not sure how to do that.
Convert the arrays to list, so you can use Collections.shuffle to shuffle them. Once shuffled, you can then simply iterate over them. The values will be random order, and all words will be used exactly once. When you reach the end of an array of words, sort it again, and start from the beginning.
If a poem consists of 1 adjective + 1 noun as in your example, then the program could go something like this:
List<String> adjectives = new ArrayList<>(Arrays.asList(adjectivesArr));
List<String> nouns = new ArrayList<>(Arrays.asList(nounsArr));
Collections.shuffle(adjectives);
Collections.shuffle(nouns);
int aindex = 0;
int nindex = 0;
for (int i = 0; i < 100; ++i) {
String poem = adjectives.get(aindex++) + " " + nouns.get(nindex++);
System.out.println(poem);
if (aindex == adjectives.size()) {
aindex = 0;
Collections.shuffle(adjectives);
}
if (nindex == nouns.size()) {
nindex = 0;
Collections.shuffle(nouns);
}
}
The program will work with other number of adjectives and nouns per poem too.
If you must use an array, you can implement your own shuffle method, for example using the Fisher-Yates shuffle algorithm:
private void shuffle(String[] strings) {
Random random = new Random();
for (int i = strings.length - 1; i > 0; i--) {
int index = random.nextInt(i + 1);
String temp = strings[i];
strings[i] = strings[index];
strings[index] = temp;
}
}
And then rewrite with arrays in terms of this helper shuffle function:
shuffle(adjectives);
shuffle(nouns);
int aindex = 0;
int nindex = 0;
for (int i = 0; i < 100; ++i) {
String poem = adjectives[aindex++] + " " + nouns[nindex++];
System.out.println(poem);
if (aindex == adjectives.length) {
aindex = 0;
shuffle(adjectives);
}
if (nindex == nouns.length) {
nindex = 0;
shuffle(nouns);
}
}
What you can do is make two more arrays, filled with boolean values, that correspond to the adjective and noun arrays. You can do something like this
boolean adjectiveUsed = new boolean[adjective.length];
boolean nounUsed = new boolean[noun.length];
int adjIndex, nounIndex;
By default all of the elements are initialized to false. You can then do this
adjIndex = rand.nextInt(3);
nounIndex = rand.nextInt(3);
while (adjectiveUsed[adjIndex])
adjIndex = rand.nextInt(3);
while (nounUsed[nounIndex]);
nounIndex = rand.nextInt(3);
Note, once all of the elements have been used, you must reset the boolean arrays to be filled with false again otherwise the while loops will run forever.
There are lots of good options for this. One is to just have a list of the words in random order that get used one by one and are then refreshed when empty.
private List<String> shuffledNouns = Collections.EMPTY_LIST;
private String getNoun() {
assert nouns.length > 0;
if (shuffledNouns.isEmpty()) {
shuffledNouns = new ArrayList<>(Arrays.asList(nouns));
Collections.shuffle(wordOrder);
}
return shuffledNouns.remove(0);
}
Best way to do this is to create a shuffled queue from each array, and then just start popping off the front of the queues to build your poems. Once the queues are empty you just generate new shuffled queues and start over. Here's a good shuffling algorithm:
https://en.wikipedia.org/wiki/Fisher–Yates_shuffle
How about keeping two lists for the adjectives and nouns? You can use Collections.shuffle() to order them randomly.
import java.util.*;
class PoemGen {
static List<String> nouns = Arrays.asList("ball", "foobar", "dog");
static List<String> adjectives = Arrays.asList("slippery", "undulating", "crunchy");
public static void main(String[] args) {
for (int i = 0; i < 3; i++) {
System.out.println(String.format("\nPoem %d", i));
generatePoem();
}
}
private static void generatePoem() {
Collections.shuffle(nouns);
Collections.shuffle(adjectives);
int nounIndex = nouns.size() - 1;
int adjectiveIndex = adjectives.size() - 1;
while (nounIndex >= 0 && adjectiveIndex >= 0) {
final String poem = adjectives.get(adjectiveIndex--)+" "+ nouns.get(nounIndex--);
System.out.println(poem);
}
}
}
Output:
Poem 0
crunchy dog
slippery ball
undulating foobar
Poem 1
undulating dog
crunchy ball
slippery foobar
Poem 2
slippery ball
crunchy dog
undulating foobar
Assuming you have the same number of noums and adjectives shuffle both arrays and then merge result. you can shuffle the arrays multiple times if you need (once you get to the end)
shuffleArray(adjectives);
shuffleArray(nouns);
for(int i=0;i<3;i++) {
String poem = adjectives[i] + " " + nouns[i];
}
A simple method to shuffle the arrays:
static void shuffleArray( String[] data) {
for (int i = data.length - 1; i > 0; i--) {
int index = rnd.nextInt(i + 1);
int aux = data[index];
data[index] = data[i];
data[i] = aux;
}
}
This might be overkill for this specific problem but it's an interesting alternative in my opinion:
You can use a linear congruential generator (LCG) to generate the random numbers instead of using rand.nextInt(3). An LCG gives you a pseudo-random sequence of numbers using this simple formula
nextNumber = (a * x + b) % m
Now comes the interesting part (which makes this work for your problem):
The Hull-Dobell-Theorem states that if your parameters a, b and m fit the following set of rules, the generator will generate every number between 0 and m-1 exactly once before repeating.
The conditions are:
m and the offset c are relatively prime
a - 1 is divisible by all prime factors of m
a - 1 is divisible by 4 if m is divisible by 4
This way you could generate your poems with exactly the same line of code as you currently have but instead just generate the array index with the LCG instead of rand.nextInt. This also means that this solution will give you the best performance, since there is no sorting, shuffling or searching involved.
Thanks for the responses everyone! This helped immeasurably. I am now officially traumatized by the sheer number of ways there are to solve even a simple problem.

searching multiple number in given array

have following problem. suppose i have an array number[n] , i want search multiple number , for example i want to search 12, 45 ,1 ,6,8,5, and if every number present array then i can get favorable result. so there is one way , i just pick one element like 7
if it is present in array number[n], then can get inside the loop , and again initialize another loop and check that if second number is in the number[n] , and so on, so here i need same number of loop as the number of searching numbers. so is there is another way to deal with such problem. because it will running time will be polynomial.
here is my code:
import java.util.Scanner;
class Number {
boolean check(int[] num)
{
for (int i = 0; i < 5; i++) {
if (num[i] == 7) {
for (j = 0; j < 5; j++) {
if (num[j] == 8) {
for (int k = 0; k < 5; k++) {
if (num[k] == 9) {
return true;
}
else
continue;
}
} else
continue;
}
} else
return false;
}
}
public static void main(string [] args)
{
Number obj1 = new Number();
Scanner input = new Scanner(System.in);
int [] num =new int[5];
for(int i=0;i<5;i++)
num[i] =input.nextInt();
boolean get ;
get = obj1.check(num []);
System.out.print(response);
}
}
You could do something like this.
public static boolean allFoundIn( int[] toSearch, int... numbers )
Set numbersSet = new HashSet(Arrays.asList(numbers));
numbersSet.removeAll(Arrays.asList(toSearch));
return numbersSet.isEmpty();
}
Then in your main, just call
allFoundIn(num, 7, 8, 9);
which will return true if 7, 8 and 9 are all found in the array num.
If you want a sub-polynomial solution then there are a few possibilities.
1) Sort both lists, then loop like so (pseudocode)
toFind = <first element of listToFind>
for i in listToSearch:
if i == toFind:
if toFind is last element of listToFind:
return true
toFind = next element of listToFind
else if i > toFind:
return false
2) Put all the elements of the list to search in a HashSet. Then loop over the elements you want to find and see if it's in the HashSet. If they all are then they're all in the list. If not then they're not all in the list. HashSet has fast lookup, so it will likely be better than polynomial time.
and since I was already beaten to the punch for 2, I'll stop thinking of alternatives and post.
Yes, you can dramatically reduce the number of passes. Firstly though, don't hard code you search numbers like that with a separate loop for each. Create one array to store the numbers being searched for and one containing the numbers being searched. Sort each in the same direction, eg ascending order. Create two ints to act as counters, one for each array. Now use a while loop to compare the numbers in each array at the positions the counters are at.
How you advance the counters depends on how the numbers compare. If the number in the array of ones being searched for is larger than the one being searched, you advance the one being searched. If the other way around you advance the one being searched and if equal you advance both and record the match. Keep going until the end of one array is reached.
Using this method you only traverse the arrays a maximum of one time. I'd write example code but I'm typing on my phone!
This solution is not the fastest since it does a binary search for every number. Additionally, it has to be sorted first. It would be better to put all your source numbers into a hash set, like in David Wallace's solution. Then each search time is constant instead of depending on the size of your source array.
boolean check(int[] num) {
int[] toSearch = new int[] { 12, 45, 1, 6, 8, 5 };
for (int search : toSearch) {
if (Arrays.binarySearch(num, search) == -1) {
return false;
}
}
return true;
}
If you want to use a hash set, you could do it like this:
boolean check(Integer[] num) {
HashSet<Integer> numSet = new HashSet<>(Arrays.asList(num));
int[] toSearch = new int[] { 12, 45, 1, 6, 8, 5 };
for (int search : toSearch) {
if (!numSet.Contains(search)) {
return false;
}
}
return true;
}

Categories

Resources