我目前正在尝试解决一个名为战舰的代码大战问题:沉没损坏或未触及?。给定一个包含'船舶的2D阵列。另一个包含攻击坐标的二维数组我必须生成一个分数。我使用船舶位置填充哈希映射,然后根据地图检查攻击位置。打印时,第一个测试用例的原始位置和攻击是相同的。尽管如此,map.get()
继续返回 null ,map.containsKey()
返回 false 。
public class BattleshipsSDN {
public static Map<String,Double> damagedOrSunk(final int[][] board, final int[][] attacks) {
int y;
HashMap<int[], Integer> ships = new HashMap<>();
// build map of boat locations
for (int i = 0; i < board.length; i++) {
y = board.length - i;
for (int j = 0; j < board[i].length; j++) {
if (board[i][j] == 0) continue;
else {
int[] location = {j+1,y};
ships.put(location, board[i][j]);
System.out.println("Location: "+location[0]+","+location[1]);
//System.out.println("Value: "+ships.get(location));
}
}
}
//establish original boat lengths
int ship1 = Collections.frequency(new ArrayList<Integer>(ships.values()), 1);
int ship2 = Collections.frequency(new ArrayList<Integer>(ships.values()), 2);
int ship3 = Collections.frequency(new ArrayList<Integer>(ships.values()), 3);
System.out.println("Ships: "+ship1+ship2+ship3);
for(int[] x : ships.keySet()) System.out.println(x[0]+","+x[1]);
//check for hits
for (int[] x : attacks) {
System.out.println(x[0]+","+x[1]);
if (ships.get(x) == null) continue;
else{
System.out.println("Hit");
ships.remove(x);
}
}
double sunk = 0;
double hit = 0;
double missed = 0;
//find number of ship spots after attacks
int leftShip1 = Collections.frequency(new ArrayList<Integer>(ships.values()), 1);
int leftShip2 = Collections.frequency(new ArrayList<Integer>(ships.values()), 2);
int leftShip3 = Collections.frequency(new ArrayList<Integer>(ships.values()), 3);
System.out.println("Ships: "+leftShip1);
if (ship1 > 0) {
if (leftShip1 == 0) sunk++;
else if (ship1 % leftShip1 > 0) hit++;
else if (ship1 == leftShip1) missed++;
}
if (ship2 > 0) {
if (leftShip2 == 0) sunk++;
else if (ship2 % leftShip2 > 0) hit++;
else if (ship2 == leftShip2) missed++;
}
if (ship3 > 0) {
if (leftShip3 == 0) sunk++;
else if (ship3 % leftShip3 > 0) hit ++;
else if (ship3 == leftShip3) missed++;
}
HashMap<String, Double> score = new HashMap<>();
score.put("sunk", sunk);
score.put("damaged", hit);
score.put("notTouched", missed);
score.put("points", sunk + hit/2 - missed);
return score;
}
}
我不是要求你为我解决问题。我完全不知道为什么我的HashMap以这种方式行事。这可能意味着它是一些非常小的愚蠢的事情。
注意:位置的 y 值会被翻转,因为问题是&#39; board&#39; y-coord是从底部测量的。因此,在4x4板或数组中,索引[0] [0]对应于坐标(1,4)
答案 0 :(得分:2)
问题是您使用int[]
作为HashMap
的密钥。数组不会覆盖方法equals
和hashCode
。因此,对于他们来说,这些方法通过身份而不是内容来比较对象。
考虑一下:
int[] first = new int[] { 1, 2, 3 };
int[] second = new int[] { 1, 2, 3 };
System.out.println(first.equals(second)); // Prints 'false'
两个数组都具有相同的内容,但它们被视为不等于,因为它们是不同的对象(first != second
)。
当您现在使用哈希代码调用map.get(key)
地图搜索密钥之类的内容时,{{1}返回的内容} 方法。但是,此方法也适用于数组的 identity-base 。
如果您现在使用密钥存储数据,然后重新创建具有相同内容的密钥,那么为了获取数据,您将无法再找到它:
hashCode
虽然Map<int[], String> map = new HashMap<>();
// Put data
int[] key = new int[] { 1, 2, 3 };
map.put(key, "test");
// Retrieve it
int[] similarKey = new int[] { 1, 2, 3 };
String data = map.get(similarKey); // Is 'null', not ' test'
// Try it with 'key' instead of 'similarKey'
String otherData = map.get(key); // Works now since same object
具有相同的内容,但它具有不同的similarKey
,因为不是同一个对象(按身份)。
要解决此问题,只需使用数据结构,该数据结构不是按身份实现hashCode
和hashCode
,而是比较内容。您可以使用equals
(documentation),Collection
(documentation)中的内容,例如:
ArrayList