Checking for Duplicates in an Array Backwards - java

This is the same person who had trouble with the last array problem just one or two days ago.
We've a new assignment which asks us to find and replace duplicates in an array of randomly generated numbers. I wrote a code and sent it to my teacher for feedback; she responded with this solution:
So, take the first random num and store into the first slot (this can be done before the loop). Then, start a loop that creates the second random num and tests backwards to see if there are duplicates from the ones already stored. So, a backwards loops that tests for duplicates and counts down to 0 from the current location and replaces duplicates. Once that test passes, then you'll go to the next element, create a new random number, and then test the ones before it for duplicates.
I've done this here, and it's reduced the number of randomly generated numbers, but I still run into the stray duplicate:
import java.lang.Object;
import java.util.Random;
public class Prog433a {
public static void main(String[]args) {
Random randslct = new Random();
int[] list = new int[20];
int counter = 0;
int index = 0;
int min2 = 0;
System.out.println("\nAfter");
for (int k = 0; k < list.length - 1; k++) {
list [k] = randslct.nextInt(30) + 1;
for (int z = list.length - 1; z >= 0; z--) {
if (list[k] == list[z] && z!=k) {
while (list[k] == list[z]) {
list [k] = randslct.nextInt(30) + 1;
}
}
}
}
int min = list[0];
while (counter < list.length - 1) {
for (int x = 0; x < list.length - 1; x++) { // scroll through the indexes.
if (list[x] < min) {
min = list[x];
index = x; // keep the index of the biggest number.
}
}
System.out.println(list[index]);
min = 100 * (list[index]);
list[index] = 100 * (list[index]); // change the value in the original array so it won't find the same max again
counter++;
}
}
}
System Output:
After
2
5
6
10
11
12
13
15
16
17
19
22
22
24
25
27
28
29
29
After
1
2
2
4
5
7
8
9
10
13
15
16
21
24
25
26
28
29
30
After
1
2
3
5
6
7
11
12
13
14
15
16
18
21
22
25
26
27
29
After
2
3
3
4
6
10
12
14
15
16
17
20
22
23
24
25
26
27
30
After
7
8
11
12
13
14
15
16
17
17
18
19
20
21
23
24
27
29
30
I posted my output towards the bottom.
Because this is an introductory coding class, I'd prefer if the solution did not involve Sets or any of the like. But alas, beggars cannot be choosers.
Is there something I have forgotten to add?

Your problem is that when you detect a duplicate you generate a new number, but you never go back and check that the the newly generated number is not a duplicate of the numbers you already checked. When you run into a duplicate you'll need to reset the checking loop through some mechanism.
I fixed up the code to work around the problem, but it's not the prettiest solution. I also did some minor optimisation as you were looping through unnecessary indices.
import java.util.Random;
public class Prog433a {
public static void main(String[] args) {
Random randslct = new Random();
int[] list = new int[20];
int counter = 0;
int index = 0;
int min2 = 0;
System.out.println("\nAfter");
for(int k = 0; k < list.length - 1; k++) {
list[k] = randslct.nextInt(30) + 1;
boolean unique = true;
for(int z = k - 1; z >= 0; z--) {
if(list[k] == list[z]) {
if(list[k] == list[z]) {
unique = false;
break;
}
}
}
if(!unique) {
// Repeat last index
--k;
}
}
int min = list[0];
while(counter < list.length - 1) {
for(int x = 0; x < list.length - 1; x++) { // scroll through the indexes.
if(list[x] < min) {
min = list[x];
index = x; // keep the index of the biggest number.
}
}
System.out.println(list[index]);
min = 100 * (list[index]);
list[index] = 100 * (list[index]); // change the value in the original array so it won't find the same max again
counter++;
}
}
}

Your mistake is when you try to add a new number. You just check, if it isn't the same as the one before, but not if it is the same as twice before. You can do this as follow:
boolean isDuplicate(int index, int[] list){
for(int i=index-1; i>=0;i--){
if(int[i]==int[index])
return false
}
return true;
}
instead of your inner of the for-loop you can now write:
do{
list[k] = randslct.nextInt(30) + 1;
}while(isDuplicate(k, list));
Also you should change your output, e.g. give the already written output a negative value and ignore negative values. If you want to change the numbers up to e.g. 200 your code now won't work.

Lets take this by example. Consider that the current list that has been generated is:
list = [5, 7, 9, 3, 8, 9]
where 9 is the current number.
Now in the for-loop, you iterate from list[6] to list[0]. Here, in comparision, you come to 2nd index (list[2]) where the condition
list[k] == list[z] && z != k
turns out to be true and a new random number is generated. Lets assume that here the new random number that you generated is '8'. The loop terminates successfully and your array now has a duplicate.

Related

HackerRank - Picking Numbers

I'm new to programming and it's my first ever question here.
I've been trying to solve this challenge https://www.hackerrank.com/challenges/picking-numbers/problem?isFullScreen=true for three consecutive days but still got 3/10 test cases failed.
Here the algorithm I use:
For each element in the main array create a subarray where all elements are equal or no more or less by 1
Resulting number of subarrays (which equals to the number of elements in the first array) are checked for validity meaning that each element is equal or no more or less by 1
Find the longest valid subarray and return it's size
Here is the code for the solution:
import java.io.*;
import java.util.*;
import java.util.stream.Stream;
import static java.util.stream.Collectors.joining;
import static java.util.stream.Collectors.toList;
class Result {
/*
* Complete the 'pickingNumbers' function below.
*
* The function is expected to return an INTEGER.
* The function accepts INTEGER_ARRAY a as parameter.
*/
public static int pickingNumbers(List<Integer> a) {
int maxLength = 0;
boolean isValidArray = false;
List<Integer> subarray = new ArrayList<Integer>();
for (int i = 0; i < a.size(); i++) {
subarray = findValidSubarray(a, a.get(i));
isValidArray = arrayValidityCheck(subarray);
if ((isValidArray) && (subarray.size() > maxLength)) {
maxLength = subarray.size();
}
}
return maxLength;
}
private static List<Integer> findValidSubarray(List<Integer> array, Integer integer) {
List<Integer> subarray = new ArrayList<Integer>();
for (int elem : array) {
if ((elem == integer) || (elem + 1 == integer) || (elem == integer + 1)) {
subarray.add(elem);
}
}
return subarray;
}
//check that all elements are equal or not more or less than 1 to each other
private static boolean arrayValidityCheck(List<Integer> subarray) {
boolean isValid = false;
for (int i = 0; i < subarray.size(); i++) {
for (int j = 0; j < subarray.size(); j++) {
if ((subarray.get(i) == subarray.get(j)) || (subarray.get(i) + 1 == subarray.get(j)) || (subarray.get(i) == subarray.get(j) + 1)) {
isValid = true;
} else {
isValid = false;
break;
}
}
if (!isValid) {
break;
}
}
return isValid;
}
}
public class Solution {
public static void main(String[] args) throws IOException {
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
String[] firstMultipleInput = bufferedReader.readLine().replaceAll("\\s+$", "").split(" ");
int n = Integer.parseInt(firstMultipleInput[0]);
List<Integer> a = Stream.of(bufferedReader.readLine().replaceAll("\\s+$", "").split(" "))
.map(Integer::parseInt)
.collect(toList());
bufferedReader.close();
int result = Result.pickingNumbers(a);
System.out.println(result);
}
}
Sample test case data which is failing:
100
and
14 18 17 10 9 20 4 13 19 19 8 15 15 17 6 5 15 12 18 2 18 7 20 8 2 8 11
2 16 2 12 9 3 6 9 9 13 7 4 6 19 7 2 4 3 4 14 3 4 9 17 9 4 20 10 16 12
1 16 4 15 15 9 13 6 3 8 4 7 14 16 18 20 11 20 14 20 12 15 4 5 10 10 20
11 18 5 20 13 4 18 1 14 3 20 19 14 2 5 13
Valid answer:
15
My answer:
13
I'm out of ideas where the bug is here.
Could you please help me?
PS: I'm aware that this algorithm is not optimal. Any optimization tips would be much appreciated.
Edit: As pointed out in the comments it is sufficient to do one type of check and only check if the other elements are 1 larger than the first element in the check. Answer modified accordingly
Your problem is that when you build your subarray, you allow numbers in it that are both 1 higher and 1 lower than the first element you start with.
You then later try to clean up your results by re-validating your generated arrays, but this will not fix the problem that you will not generate any all possible valid subarrays with your method.
My proposal to fix your code would be:
Modify your findValidSubarray method so that only allows elements that are 1 higher in it. (The cases where lower numbers would be allowed in will be handled in other iteration when that lower number is the starting element for the iteration)
remove the arrayValidityCheck as this one will no longer be needed as the above will directly only produce valid subarrays.
Modified findValidSubarray method:
private static List<Integer> findValidSubarray(final List<Integer> array, final Integer integer) {
final List<Integer> subarray = new ArrayList<Integer>();
for (final int elem : array) {
if ((elem == integer) || (elem + 1 == integer)) {
subarray.add(elem);
}
}
return subarray;
}
Calling that method:
public static int pickingNumbers(final List<Integer> a) {
int maxLength = 0;
List<Integer> subarray = new ArrayList<Integer>();
for (int i = 0; i < a.size(); i++) {
subarray = findValidSubarray(a, a.get(i));
if ((subarray.size() > maxLength)) {
maxLength = subarray.size();
}
}
return maxLength;
}

In Java, how would I print a 2d array that resembles a seating chart?

I have an assignment where I would have to print a 2d array (8 rows and 7 columns) that resembles a seating chart with an aisle going down the middle that cannot have any seats (these elements would be left blank). The chart would have to have a number for each seat, and continue in ascending order (as seen below).
1 2 3 x 4 5 6
7 8 9 x 10 11 12
13 14 15 x 16 17 18
19 20 21 x 22 23 24
The program would continue until there would be 48 total seats.
I have to print the array with for loops (which I have no problem doing), but I do not know how to make a blank column (the column with xs), or how to make each number increase as you progress through the cells.
Right now, I have only the for loops that would print out the array.
I think what you need there is a nested loop. Your code should look like this:
public static void main(String []args){
print_2d_array(8, 7);
}
public static void print_2d_array(int rows, int columns) {
int x = rows/2;
int y = columns - 1;
for(int i = 0; i < x; i++) { // number of rows
for(int j = 0; j < y; j++) { // number of columns
System.out.print((j + y*i + 1) + " "); // That's the formula I was talking about
if(j == (y/2)-1) System.out.print("x ");
}
System.out.println();
}
}

Is there something wrong with my id array?

This program pulls two columns from the input.txt file where the first column indicates the value of the object, and the second column represents the weight. The values are imported and placed into two arrays: the value array and the weight array. The knapsack calculations are then made. There are 23 objects in total represented by the rows of the arrays. My code correctly calculates the total value that is being held in the knapsack, and will print out the correct IDs if the weight capacity entered is 5, but for any other weight the IDs being held in the id array are not correct, but the total value printed out is. Here is my code for both files, and if anyone is able to figure out how to correctly save and print the IDs being held in the knapsack please let me know . . .
input.txt file:
17 5
12 8
15 22
17 11
33 21
43 15
15 4
44 35
23 19
10 23
55 39
8 6
21 9
20 28
20 13
45 29
18 16
21 19
68 55
10 16
33 54
3 1
5 9
knapsack.java file:
//We did borrow concepts from:
//http://www.sanfoundry.com/java-program-solve-knapsack-problem-using-dp/
import java.util.Scanner;
import java.util.*;
import java.lang.*;
import java.io.*;
public class knapsack
{
static int max(int a, int b)
{
if(a > b)
{
//System.out.println(a);
return a;
}
else
//System.out.println(b);
return b;
}
static int knapSack(int maxCapacity, int weight[], int value[], int n)
{
int track = 0;
int i, w;
int foo1 = 0;
int foo2 = 0;
K = new int[n+1][maxCapacity+1];
// Build table K[][] in bottom up manner
for (i = 0; i <= n; i++)
{
for (w = 0; w <= maxCapacity; w++)
{
if (i==0 || w==0)
K[i][w] = 0;
else if (weight[i-1] <= w)
{
//K[i][w] = max(value[i-1] + K[i-1][w-weight[i-1]], K[i-1][w]);
if(value[i-1] + K[i-1][w-weight[i-1]] > K[i-1][w])
{
K[i][w] = value[i-1] + K[i-1][w-weight[i-1]];
//System.out.println("A: "+i);
}
else
{
K[i][w] = K[i-1][w];
id[track++] = i;
//System.out.println("B: "+i);
}
}
else
{
K[i][w] = K[i-1][w];
}
}
//System.out.println(K[foo1][foo2]);
}
return K[n][maxCapacity];
}
public static void main(String args[])throws java.io.FileNotFoundException
{
Scanner sc = new Scanner(System.in);
int n = 23;
File file = new File("input.txt");
Scanner scanner = new Scanner(file);
id = new Integer [n];
//knapval = new int[n];
//knapweight = new int [n];
int []value = new int[n];
int []weight = new int[n];
for(int i=0; i<n; i++)
{
value[i] = scanner.nextInt();
weight[i] = scanner.nextInt();
}
System.out.println("Enter the maximum capacity: ");
int maxCapacity = sc.nextInt();
System.out.println("The maximum value that can be put in a knapsack with a weight capacity of "+maxCapacity+" is: " + knapSack(maxCapacity, weight, value, n));
System.out.println();
System.out.println("IDs Of Objects Held In Knapsack: ");
//System.out.println();
for(int z = 0; z < n && id[z] != null; z++)
{
System.out.println(id[z]);
}
if(id[0] == null)
System.out.println("All objects are too heavy, knapsack is empty.");
sc.close();
scanner.close();
}
protected static Integer [] id;
protected static int [][]K;
}
Your way of recording your solution in the id array is flawed. At the time you do id[track++] = i;, you don’t yet know whether i will be in your final solution. Because of the nested loops you may even add i more than once. This in turn may lead to overflowing the array with a java.lang.ArrayIndexOutOfBoundsException: 23 (this happens for max capacity 12 and above).
I suggest instead of using id, after your solution is complete you track your way backward through the K array (by Java naming conventions, it should be a small k). It holds all the information you need to find out which objects were included in the maximum value.
private static void printKnapsack(int maxCapacity, int weight[], int value[], int n) {
if (K[n][maxCapacity] == 0) {
System.out.println("No objects in knapsack");
} else {
int w = maxCapacity;
for (int i = n; i > 0; i--) {
if (K[i][w] > K[i - 1][w]) { // increased value from object i - 1
System.out.format("ID %2d value %2d weight %2d%n", i, value[i - 1], weight[i - 1]);
// check that value in K agrees with value[i - 1]
assert K[i - 1][w - weight[i - 1]] + value[i - 1] == K[i][w];
w -= weight[i - 1];
}
}
}
}
The above prints the objects backward. Example run:
Enter the maximum capacity:
13
The maximum value that can be put in a knapsack with a weight capacity of 13 is: 36
ID 13 value 21 weight 9
ID 7 value 15 weight 4
If you want the objects in forward order, inside the for loop put them into a list (you may for instance use id from your old attempt), and then print the items from the list in opposite order.

Printing pattern from list in Java

What I have done here is taken the contents of the table below and stored them in a list called tableElems
0 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
List<WebElement> tableElems = chrome.findElements(By.tagName("td"));
From this table I want to print in a pattern starting at the 4th element (#3 in the table) and I want to print 3 elements, then skip the next 6, print the next 3 and then skip the next 6, etc. etc.
So my expected output would be 3 4 5 12 13 14 21 22 23 30 31 32
My initial attempt ended with
for (int i = 3; i<tableElems.size(); i++) {
if(i % 3 == 0) { System.out.println(tableElems.get(i).getText()); }
else if(i % 4 == 0) { System.out.println(tableElems.get(i).getText()); }
else if(i % 5 == 0) { System.out.println(tableElems.get(i).getText()); }
}
Obviously this is wrong, because my % 3 will print the 9th element, % 4 will print the 16th element, etc.
I am having trouble wrapping my head around this, so any advice to point me in the right direction is appreciated!
try this:
for (int i = 3; i<tableElems.size(); i++) {
if (((i / 3) % 3) == 1) { System.out.println(tableElems.get(i).getText()); }
}
Think about this as dividing into groups of nine, and further dividing each group of 9 into groups of 3. on the second group of 3 (i.e. 3-5, 12-14) it will display.
int offset = 4;
int width = 3;
advice:
for each row in table check offset + width is under the row width, and then start from offset + 0, offset + 1 upto offset + width
and continue this loop for all the row of table
You mentioned that tableElems is a list, so I assume it's akin to a single-dimension array, rather than what appears to be a multi-dimensional table like you've laid out(I assume for visual purposes).
You're right by starting the for loop at i = 3. The easiest way, IMO, to do this is to just bump the loop ahead several spaces in the array after you've printed three elements. Here's my solution using C# and an array; you should be able to convert it to Java pretty easily.
int counter = 0;
for (int i = 3; i < array.Length; i++)
{
if (counter < 3)
{
Console.WriteLine(array[i]);
counter++;
}
else
{
i += 5; // we are incrementing by one on the next pass, so this can be 5
counter = 0;
}
}
If you want to stick to %, then this should work
int rowSize = 9;
for (int i = 0; i < tableElems.size(); i++) {
int column = i % rowSize;
if (column >=3 && column <= 5) {
System.out.println(tableElems.get(i).getText());
}
}
Update: Java code
for (int i = 3; i<tableElems.size(); i += 9) {
System.out.println(tableElems.get(i).getText());
System.out.println(tableElems.get(i+1).getText());
System.out.println(tableElems.get(i+2).getText());
System.out.println(tableElems.get(i+3).getText());
}
If you are creating a larger pattern:
int starting = 3;
int nextStartDistance = 9;
int waveCount = 3;
for (int i = starting; i<tableElems.size(); i += nextStartDistance) {
for (int b = 0; b <= waveCount; b ++) {
System.out.println(tableElems.get(i).getText());
}
}
This code is written in JavaScript, but the algorithm considered:
var list =[
0,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];
for (var index = 3; index <= list.length; index +=9 ) {
var a = list[index];
var b = list[index+1];
var c = list[index+2];
var d = list[index+3];
console.log(a,b,c,d);
}
Result will be what you expected:
// 3 4 5 6
// 12 13 14 15
// 21 22 23 24
// 30 31 32 33
// user:~$
for (int i = 3; i < tableElems.size(); i += 9) {
for (int j = i; j < i + 3 && j < tableElems.size(); j++) {
System.out.println(tableElems.get(j).getText());
}
}
i think this would be very close to your code:
for (int i = 3; i < tableElems.size(); i++) {
if (i % 3 == 0) {
System.out.println(tableElems.get(i).getText());
} else if ((i % 3) == 1) {
System.out.println(tableElems.get(i).getText());
} else if ((i % 3) == 2) {
System.out.println(tableElems.get(i).getText());
i = i + 6;
}
}
i just adapted your modulo and skip 6 elements every time i hit the last one to print out
furthermore its quite effective because all unneeded elements are just skipped instead of iterated and checked
Assuming you only care about the values out of your table and the html structure is standard html tags as shown on your questions, then you can use css selector to select appropriate values.
chrome.findElements(By.cssSelector("td:nth-child(4),td:nth-child(5), td:nth-child(6)"))
Please note that css nth-child selector is 1 based.

Can't see where I'm dividing by 0?

Here is all the code I think anyone would need to be able to asses my problem
1 import.java.util.Scanner
2 public class ccattano_Sieve{
3 private boolean [] primes = new boolean [50001];
4 private int upper;
5 private int lower;
6
7 public ccattano_Sieve(){
8 upper = 50000;
9 lower = 1;
10 for (int i = 2; i < primes.length; i++){
11 primes[i] = true;
12 }
13 primes[0] = false;
14 primes[1] = false;
15 }
16
17 public void processSieve(){
18 for (int i = 2; i < Math.round(Math.sqrt(50000)); i++){
19 if (primes[i] == true){
20 for (int c = 2; c < (primes.length - 1); i++){
21 if (c % i == 0){
22 primes[c] = false;
23 }
24 else{
25 primes[c] = true;
26 }
27 }
28 }
29 }
30 }
I'm pretty sure my else statement on lines 24 - 26 aren't needed I added it when trying to trouble shoot. But on line 21 when trying to run the code I receive a divide by zero error. The exact error is as follows.
Exception in thread "main" java.lang.ArithmeticException: / by zero
at ccattano_Sieve.processSieve(ccattano_Sieve.java:21)
at ccattano_SieveTest.main(ccattano_SieveTest.java:7)
This line "at ccattano_SieveTest.main(ccattano_SieveTest.java:7)" calls the code I pasted so it can be ignored. So line 21 is the main issue and I can't find a solution.
The modulus operator is the "rest of the division" meaning that it involves a division.
I believe you have a bug on line 20 where you are incrementing i instead of c.
This means the i variable will overflow (reach so high that it will turn negative) and eventually will turn into 0.
You never update the value of c in your inner loop; instead you increase i by the length of your array minus 1 every time up till the square root of 50,000. I'd suspect this is an error and not what you want to do, but I await a comment to the contrary.

Categories