How the java variable scope is working here? - java

I was trying out a sample problem statement and correct code for which is something like this -
import java.util.Scanner;
public class Sample {
private static Scanner scanner = new Scanner(System.in);
public static void main(String[] args) {
int m = 5, n = 5;
int dist = 0;
for(int i = 0; i < m; ++i) {
for(int j = 0; j < n; ++j) {
int value = scanner.nextInt();
if(value == 1) {
dist = Math.abs(i - 2) + Math.abs(j - 2);
}
}
scanner.nextLine();
}
System.out.println(dist);
}
}
This runs perfectly giving the correct answer. But when I write the code -
import java.util.Scanner;
public class Sample {
private static Scanner scanner = new Scanner(System.in);
public static void main(String[] args) {
int m = 5, n = 5;
int i = 0, j = 0;
int dist = 0;
for(; i < m; ++i) {
for(; j < n; ++j) {
int value = scanner.nextInt();
if(value == 1) {
dist = Math.abs(i - 2) + Math.abs(j - 2);
}
}
scanner.nextLine();
}
System.out.println(dist);
}
}
The answer is 0, always.
For the sample input -
0 0 0 0 0
0 0 0 0 1
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
The correct answer is 3 and I am getting 3 while running the 1st piece of code. But not while running the 2nd piece of code.

Another approach could be the following to reset the variable j as mentioned previously
public class Sample {
private static Scanner scanner = new Scanner(System.in);
public static void main(String[] args) {
int m = 5, n = 5;
int i = 0, j = 0;
int dist = 0;
for(; i < m; ++i, j = 0) {
for(; j < n; ++j) {
int value = scanner.nextInt();
if(value == 1) {
dist = Math.abs(i - 2) + Math.abs(j - 2);
}
}
scanner.nextLine();
}
System.out.println(dist);
}
}

The problem is that the variable j is not reset to 0.
The correct code would be:
import java.util.Scanner;
public class Sample {
private static Scanner scanner = new Scanner(System.in);
public static void main(String[] args) {
int m = 5, n = 5;
int i = 0;
int dist = 0;
for(; i < m; ++i) {
int j = 0; // <== this line was missing
for(; j < n; ++j) {
int value = scanner.nextInt();
if(value == 1) {
dist = Math.abs(i - 2) + Math.abs(j - 2);
}
}
scanner.nextLine();
}
System.out.println(dist);
}
}
If you don't know, see how the for statement works in https://docs.oracle.com/javase/tutorial/java/nutsandbolts/for.html

In the first piece of code, the variable j is reset back to 0 each time the code exits and restarts that inner loop. In the second piece of code, that does not happen. A step by step look at what the variables are storing might be helpful. I added the following line inside the inner loop and commented out the user input section for debugging purposes:
System.out.println("( " + i + " " + j + ")");
With the first example, this prints:
( 0 0)
( 0 1)
( 0 2)
( 0 3)
( 0 4)
( 1 0)
( 1 1)
( 1 2)
( 1 3)
( 1 4)
( 2 0)
( 2 1)
( 2 2)
( 2 3)
( 2 4)
( 3 0)
( 3 1)
( 3 2)
( 3 3)
( 3 4)
( 4 0)
( 4 1)
( 4 2)
( 4 3)
( 4 4)
However for the second example it prints:
( 0 0)
( 0 1)
( 0 2)
( 0 3)
( 0 4)
Essentially in the second example, j is not reset for each iteration of the outer loop. If you add more print statements in other places, for instance inside the outer loop but not the inner one, the scoping will become even more clear. It's important to note that the outer loop is still running 5 times, we just have no evidence of that as the print statement becomes unreachable after the first pass through the inner loop.

Related

The numbers never occur next to each other

I wrote a program that reads an array of integers and two numbers n and m. The program check that n and m never occur next to each other (in any order) in the array.
import java.util.*;
class Main {
public static void main(String[] args) {
// put your code here
Scanner scanner = new Scanner (System.in);
int len = scanner.nextInt();
int [] array = new int [len];
boolean broken = false;
for (int i = 0; i < len; i++){
array [i] = scanner.nextInt();
}
int n = scanner.nextInt();
int m = scanner.nextInt();
for (int j = 1; j < len; j++){
if((array[j]==n)&&(array[j+1]==m) || (array[j]==n)&&(array[j-1]==m) || (array[j]==m)&&(array[j+1]==n) || (array[j]==m)&&(array[j-1]==n)){
broken = true;
break;
}
}
System.out.println(broken);
}
}
Test input:
3
1 2 3
3 4
Correct output: true
My output is blank. What am I doing wrong?
Your code will throw ArrayIndexOutOfBoundsException as you are using array[j+1] whereas you have loop condition as j < len. The condition should be j < len -1.
The following works as expected:
for (int j = 1; j < len - 1; j++) {
if ((array[j] == n && array[j + 1] == m) || (array[j] == n && array[j - 1] == m)
|| (array[j] == m && array[j + 1] == n) || (array[j] == m && array[j - 1] == n)) {
broken = true;
break;
}
}
A sample run:
3
1 2 3
3 4
true
Your code will throw ArrayIndexOutOfBoundsException because of array[j+1] where j can be len-1. Actually you don't need to check both sides(previous and next element), checking combination with previous is enough since in the next iteration combination with next element will be checked.
for (int j = 1; j < len; j++){
if((array[j]==n && array[j-1]==m) || (array[j]==m && array[j-1]==n)){
broken = true;
break;
}
}
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
int len = scan.nextInt();
Map<Integer, Set<Integer>> map = new HashMap<>();
for (int i = 0, prv = 0; i < len; i++) {
int num = scan.nextInt();
if (!map.containsKey(num))
map.put(num, new HashSet<>());
if (i > 0)
map.get(prv).add(num);
prv = num;
}
int n = scan.nextInt();
int m = scan.nextInt();
boolean res = !map.containsKey(n) || !map.containsKey(m) || !map.get(n).contains(m) && !map.get(m).contains(n);
System.out.println(res);
}

java 2D integer array looping wrong output

code :
class test1 {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
int a = scan.nextInt(); // input number rows & colums
int twoD[][] = new int[a][];
int z;
for (z = 0 ; z < a ; z++) {
twoD[z] = new int[z + 1];
}
int i,j,k = 0;
for (i = 0 ; i < a ; i++) {
for (j = 0 ; j <= i ; j++){
twoD[i][j] = k;
k++;
}
for (i = 0 ; i < a ; i++ ) {
for (j = 0 ; j <= i ; j++){
System.out.print(twoD[i][j] + " ");
}
System.out.println();
}
}
}
my expected output is ( for a = 4) :
0
1 2
3 4 5
6 7 8 9
my output is (for a = 4):
0
0 0
0 0 0
0 0 0 0
please help me fix my problem. according to me the lopping is correct. there might be mistake somewhere else...
The loop that prints the contents of the array is contained within the loop that is supposed to fill the 2D array with values. Since it uses the same variables, it interferes with the execution of the first loop. Move it out:
int i,j,k = 0;
for (i = 0 ; i < a ; i++) {
for (j = 0 ; j <= i ; j++){
twoD[i][j] = k;
k++;
}
}
for (i = 0 ; i < a ; i++ ) {
for (j = 0 ; j <= i ; j++){
System.out.print(twoD[i][j] + " ");
}
System.out.println();
}
You could have avoided this by
using and editor or IDE that automatically formats your code, so that is shows you how the control structures are nested
using common idioms like declaring the loop variables with the smallest necessary scope:
for (int i = 0 ; i < a ; i++)

Drawing a diamond of numbers in a 2d array Java

I've been solving some coding questions to get myself prepared for a coding interview, and found out a question that seemed kind of puzzling. I solved the question after spending some time on it; however, the code looks hardcoded and has no style. So, I was wondering if I could get some feedbacks on styling the code, or perhaps getting an better idea of approaching the problem.
The question basically asks you to draw a diamond of numbers with a pattern in 2d array.
It gives a coordinate of 'x' and range of x. From the x, the numbers spread one by one until the range. So, there are 4 different inputs, N (the size of an array), X, Y (the coordinate of 'x' as (rows, cols)), and R (range).
If they were given a size of 8, coordinate of (4,5) with a range of 3, the result would be like,
0 0 0 0 3 0 0 0
0 0 0 3 2 3 0 0
0 0 3 2 1 2 3 0
0 3 2 1 x 1 2 3
0 0 3 2 1 2 3 0
0 0 0 3 2 3 0 0
0 0 0 0 3 0 0 0
0 0 0 0 0 0 0 0
And the below is what I have,
int n = sc.nextInt();
char[][] arr = new char[n][n];
int r = sc.nextInt() - 1;
int c = sc.nextInt() - 1;
int range = sc.nextInt();
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
arr[i][j] = '0';
}
}
arr[r][c] = 'x';
int num = 1;
for (int i = 0; i < range; i++) {
//Cross
if (c-num > -1) {
arr[r][c - num] = (char) (num + '0');
}
if (c+num < n) {
arr[r][c + num] = (char) (num + '0');
}
if (r-num > -1) {
arr[r - num][c] = (char) (num + '0');
}
if (r+num < n) {
arr[r + num][c] = (char) (num + '0');
}
//Diagonal
if (i > 0) {
int sum = num - 1, delta = 1;
while (sum != 0) {
if (r-sum > -1 && c+delta < n) {
arr[r - sum][c + delta] = (char) (num + '0');
}
sum--;
delta++;
}
sum = num - 1; delta = 1;
while (sum != 0) {
if (r+sum < n && c-delta > -1) {
arr[r + sum][c - delta] = (char) (num + '0');
}
sum--;
delta++;
}
sum = num - 1; delta = 1;
while (sum != 0) {
if (r-sum > -1 && c-delta > -1) {
arr[r - sum][c - delta] = (char) (num + '0');
}
sum--;
delta++;
}
sum = num - 1; delta = 1;
while (sum != 0) {
if (r+sum < n && c+delta > -1) {
arr[r + sum][c + delta] = (char) (num + '0');
}
sum--;
delta++;
}
}
num++;
}
I could not figure out any other way to take care of the diagonal numbers other than using four different while-loops. I would appreciate any kind of feedback. Thanks in advance!
You can just loop over the array once, and set the values based on the relative distance of the current location (i, j) to the fixed coordinate (x, j).
Your code could look like this:
import java.util.Arrays;
public class Test {
public static void main(String[] args) {
// variables
int n = 8;
int x = 4 - 1; // coordinates are one-based
int y = 5 - 1; // coordinates are one-based
int r = 3;
char[][] array = new char[n][n];
// logic
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
int dist = Math.abs(x - i) + Math.abs(y - j); // calculate distance
if(dist == 0) { // at x,y
array[i][j] = 'x';
} else if (dist <= r) { // distance to x,y is within range
array[i][j] = (char) (dist + '0');
} else { // distance to x,y is outside of range
array[i][j] = '0';
}
}
}
// dump output
System.out.println(Arrays.deepToString(array)
.replace("], ", "]\n")
.replace("[", "")
.replace("]", "")
.replace(", ", " "));
}
}
Which yields the following output:
0 0 0 0 3 0 0 0
0 0 0 3 2 3 0 0
0 0 3 2 1 2 3 0
0 3 2 1 x 1 2 3
0 0 3 2 1 2 3 0
0 0 0 3 2 3 0 0
0 0 0 0 3 0 0 0
0 0 0 0 0 0 0 0
If you want to be even more concise, you can replace the branched if… else if… else statement with ternary operators:
array[i][j] = dist == 0 ? 'x' : dist <= r ? (char) (dist + '0') : '0';
Here's a fairly compact method. On each iteration i we fill a single-character wide i+1 by i+1 diamond-shaped ring, centered on (row, col), with value i. To avoid filling the interior of the diamond we check that the manhattan distance to (row, col) is equal to i - this is only true for cells on the boundary of the diamond.
static char[][] buildDiamond(int n, int row, int col, int range)
{
char[][] arr = new char[n][n];
for(char[] a : arr) Arrays.fill(a, '0');
arr[row][col] = 'x';
for(int i=1; i<=range; i++)
for(int j=0; j<=i; j++)
for(int k=0; k<=i; k++)
if(Math.abs(k-j) + Math.abs(k+j-i) == i)
arr[row+k-j][col+k+j-i] += i;
return arr;
}
Test:
public static void main(String[] args)
{
for(char[] a : buildDiamond(7, 3, 3, 3))
System.out.println(new String(a).replaceAll(".", "$0 "));
}
Output:
0 0 0 3 0 0 0
0 0 3 2 3 0 0
0 3 2 1 2 3 0
3 2 1 x 1 2 3
0 3 2 1 2 3 0
0 0 3 2 3 0 0
0 0 0 3 0 0 0
You can try using floodfill, although depending on your level it might be a bit far.
https://en.wikipedia.org/wiki/Flood_fill
EDIT: Robby Cornelissen's code looks much cleaner and simpler than mine so you should probably check out his. However, floodfill is a pretty important concept for later on so might as well check it out.
The article is pretty long, but the GIF in the article is the most important part.
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.Queue;
import java.util.StringTokenizer;
public class test {
public static void main(String[] args) throws IOException {
//Get inputs (I used BufferedReader, Scanner works fine as well)
//My inputs are formatted as 'N X Y R' (ex. '8 4 5 3')
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine(), " ");
int N = Integer.parseInt(st.nextToken());
int R = Integer.parseInt(st.nextToken()) - 1;
int C = Integer.parseInt(st.nextToken()) - 1;
int range = Integer.parseInt(st.nextToken());
char[][] arr = new char[N][N];
//Make everything in array '0'
for (int i = 0; i < N; i++) {
Arrays.fill(arr[i], '0');
}
//Floodfill using BFS
//FYI: this BFS is iterative, not recursive
Queue<int[]> q = new LinkedList<>();
q.add(new int[]{0, R, C});
while (!q.isEmpty()) {
int[] current = q.remove();
if (arr[current[1]][current[2]] == '0' && current[0] <= range) {
arr[current[1]][current[2]] = (current[0]+"").charAt(0);
if(current[1]+1 < N) q.add(new int[]{current[0]+1, current[1]+1, current[2]});
if(current[1]-1>= 0) q.add(new int[]{current[0]+1, current[1]-1, current[2]});
if(current[2]+1 < N) q.add(new int[]{current[0]+1, current[1], current[2]+1});
if(current[2]-1>= 0) q.add(new int[]{current[0]+1, current[1], current[2]-1});
}
}
arr[R][C] = 'x';
//Print out the final grid
for (int i = 0; i < N; i++) {
for (int j = 0; j< N; j++) {
System.out.print(arr[i][j] + " ");
}
System.out.println();
}
}
}

nested while-loop that doesn't match the condition

I am trying to make a program that print the following numbers :
1 1
1 2
1 3
1 4
2 1
2 2
2 3
2 4
The code is
public class JavaApplication8 {
public static void main(String[] args) {
int i = 1;
int j = 1;
while (i <= 2 && j <= 4) {
while (i <= 2 && j <= 4) {
System.out.printf("%d%d\n", i, j);
j++;
}
j = j - 4;
i++;
System.out.printf("%d%d\n", i, j);
j++;
}
}
}
The program prints this
1 1
1 2
1 3
1 4
2 1
2 2
2 3
2 4
3 1
I don't know why this is happening behind the condition inside while says that it i must be smaller or equal 2
It's outputting that final 3 1 because your final println statement (indicated below) is unconditional. So after incrementing i to 3, you still run that statement. The while condition only takes effect afterward, which is why it then stops after printing that.
public class JavaApplication8 {
public static void main(String[] args) {
int i = 1;
int j = 1;
while (i <= 2 && j <= 4) {
while (i <= 2 && j <= 4) {
System.out.printf("%d%d\n", i, j);
j++;
}
j = j - 4;
i++;
System.out.printf("%d%d\n", i, j); // <=== This one
j++;
}
}
}
That whole thing can be dramatically simpler, though:
public class JavaApplication8 {
public static void main(String[] args) {
for (int i = 1; i <= 2; ++i) {
for (int j = 1; j <= 4; ++j) {
System.out.printf("%d%d\n", i, j);
}
}
}
}
Live Example

Backwards Method?

I'm creating a program to create an Identity Matrix - which is pretty easy. But now I need to create the Identity Matrix, but backwards. The result needs to be like so:
0 0 1
0 1 0
1 0 0
Here is the program I'm using that is creating the Identity Matrix:
import java.util.*;
class Lab19Part2 {
public static int[][] create(int size) {
int[][] matrix = new int[size][size];
for(int i = 0; i < size; i++)
for(int j = 0; j < size; j++)
matrix[i][j] = (i == j) ? 1 : 0;
return matrix;
} public static void main(String[] args) {
Scanner input=new Scanner(System.in);
System.out.println("Enter size of matrix: ");
int size=input.nextInt();
int matrix[][]=create(size);
for (int i=0 ; i < matrix.length ; i++) {
System.out.println();
for (int j=0 ; j < matrix[i].length ; j++){
System.out.print(matrix[i][j]+" ");
}
}
}
}
Though it prints out the Identity Matrix like so:
1 0 0
0 1 0
0 0 1
Question is, how do I make it so it prints out like the first Identity Matrix? I know it has something to do with the for loops but I can't pinpoint it.
Thanks!
You would need to change your condition that controls whether the value is 1 or 0:
matrix[i][j] = (i + j == size - 1) ? 1 : 0;
So that if size is 3, positions [0][2], [1][1], and [2][0] get 1's.
Change
matrix[i][j] = (i == j) ? 1 : 0;
to
matrix[i][j] = (i == size - j - 1) ? 1 : 0;
Why not do this for your identity case:
for(int i = 0; i < size; i++) {
matrix[i][i] = 1;
}
Then for the other case use:
for(int i = 0; i < size; i++) {
matrix[i][size - (i+1)] = 1;
}
Here is the brief example how to create it with la4j (Linear Algebra for Java):
Matrix a = new Basic2DMatrix(Matrices.asIdentitySource(3)).transpose();
// will create a 3x3 matrix
//
// 0 0 1
// 0 1 0
// 1 0 0

Categories

Resources