I have the code work with iteration in a single thread enviorment:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.HashSet;
import java.util.Set;
class Solution {
int res = 0;
public static void main(String[] args) throws IOException {
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
String line;
while ((line = in.readLine()) != null) {
int n = Integer.parseInt(line);
int ret = new Solution().totalNQueens(n);
String out = String.valueOf(ret);
System.out.print(out);
}
}
public int totalNQueens(int n) {
Set<Integer> columns = new HashSet<Integer>();
Set<Integer> record1 = new HashSet<Integer>();
Set<Integer> record2 = new HashSet<Integer>();
backTrace(n, 0, columns, record1, record2);
return res;
}
private int backTrace(int n, int row, Set<Integer> columns, Set<Integer> record1, Set<Integer> record2) {
if (n == row) {
return 1;
}
for (int i = 0; i < n; i++) {
if (columns.contains(i)) {
continue;
}
int check1 = row - i;
if (record1.contains(check1)) {
continue;
}
int check2 = row + i;
if (record2.contains(check2)) {
continue;
}
columns.add(i);
record1.add(check1);
record2.add(check2);
System.out.println("res start:" + res);
res = res + backTrace(n, row + 1, columns, record1, record2);
System.out.println("res end:" + res);
columns.remove(i);
record1.remove(check1);
record2.remove(check2);
}
return 0;
}
}
the result of the code is below, and it seems the res
reset when res = res + backTrace(n, row + 1, columns, record1, record2);
res start:0
res start:0
res end:0
res start:0
res start:0
res end:0
res end:0
res end:0
res start:0
res start:0
res start:0
res start:0
res end:1
res end:0
res end:0
res end:0
res start:0
res start:0
res start:0
res start:0
and when we change the code, let a new variable to save the result of backTrace, and it works fine.
package com.nbp.cdncp.vpe.api.controller;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.HashSet;
import java.util.Set;
class Solution {
int res = 0;
public static void main(String[] args) throws IOException {
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
String line;
while ((line = in.readLine()) != null) {
int n = Integer.parseInt(line);
int ret = new Solution().totalNQueens(n);
String out = String.valueOf(ret);
System.out.print(out);
}
}
public int totalNQueens(int n) {
Set<Integer> columns = new HashSet<Integer>();
Set<Integer> record1 = new HashSet<Integer>();
Set<Integer> record2 = new HashSet<Integer>();
backTrace(n, 0, columns, record1, record2);
return res;
}
private int backTrace(int n, int row, Set<Integer> columns, Set<Integer> record1, Set<Integer> record2) {
if (n == row) {
return 1;
}
for (int i = 0; i < n; i++) {
if (columns.contains(i)) {
continue;
}
int check1 = row - i;
if (record1.contains(check1)) {
continue;
}
int check2 = row + i;
if (record2.contains(check2)) {
continue;
}
columns.add(i);
record1.add(check1);
record2.add(check2);
System.out.println("res start:" + res);
var a = backTrace(n, row + 1, columns, record1, record2);
res += a;
System.out.println("res end:" + res);
columns.remove(i);
record1.remove(check1);
record2.remove(check2);
}
return 0;
}
}
the result:
res start:0
res start:0
res end:0
res start:0
res start:0
res end:0
res end:0
res end:0
res start:0
res start:0
res start:0
res start:0
res end:1
res end:1
res end:1
res end:1
res start:1
res start:1
res start:1
res start:1
res end:2
res end:2
res end:2
res end:2
res start:2
res start:2
res start:2
res end:2
res end:2
res start:2
res end:2
res end:2
2
Why this happens in a single thread environment
The expression res + backTrace(n, row + 1, columns, record1, record2)
is evaluated left to right. This means the value of res
is read before calling backTrace
, and doesn’t reflect the change to the value that happens within that method call.
If you reverse the order of arguments to backTrace(n, row + 1, columns, record1, record2) + res
, this avoids the problem, however this may still make the code hard to understand. Most people expect addition to be commutative. This assumption is violated in code where evaluation of one of the operands affects the value of the other. It would be clearer to rewrite the method to avoid using the non-local variable res
:
class Solution {
public static void main(String[] args) throws IOException {
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
String line;
while ((line = in.readLine()) != null) {
int n = Integer.parseInt(line);
int ret = new Solution().totalNQueens(n);
String out = String.valueOf(ret);
System.out.print(out);
}
}
public int totalNQueens(int n) {
Set<Integer> columns = new HashSet<Integer>();
Set<Integer> record1 = new HashSet<Integer>();
Set<Integer> record2 = new HashSet<Integer>();
return backTrace(n, 0, columns, record1, record2);
}
private int backTrace(int n, int row, Set<Integer> columns, Set<Integer> record1, Set<Integer> record2) {
if (n == row) {
return 1;
}
int res = 0;
for (int i = 0; i < n; i++) {
if (columns.contains(i)) {
continue;
}
int check1 = row - i;
if (record1.contains(check1)) {
continue;
}
int check2 = row + i;
if (record2.contains(check2)) {
continue;
}
columns.add(i);
record1.add(check1);
record2.add(check2);
System.out.println("res start:" + res);
res += backTrace(n, row + 1, columns, record1, record2);
System.out.println("res end:" + res);
columns.remove(i);
record1.remove(check1);
record2.remove(check2);
}
return res;
}
}