2352. 相等行列对
这题还是非常简单的。如果用模拟的方法,时间复杂度要达到O(n^3)了,感觉不太可。
这回学聪明了,没有一上来就想着暴力模拟。用哈希的办法,可以把时间复杂度降为O(n^2)。
我的思路是先转置矩阵,再用哈希Map。基本思路就是把grid当中的每一行存到一个哈希Map里,并记录它出现的次数;然后比对转置数组tmp的每一行是否在哈希Map中出现,以及出现的次数。
我想先转置矩阵的原因是,这道题要求行和列进行比较。Java里,二维数组就是一维数组的数组,操控行就是操控一个个一维数组,直接用下标grid[i]即可。操控列我感觉不那么方便。
Java里面没有转置二维数组的库函数,要自己写一个。(刚开始我还以为Arrays里有,在里面找了半天也没找到。后来才想起来是Python的numpy库里有……)
如何把数组内容存到哈希表里?直接写Map<int[],xxxx>或Set<int[]>是不能达到目的的。注意,这样写语法上是没问题的,但是放入Map或Set中的是数组的引用,实际上存入的并不是数组的内容。因此,如果要实现把数组按照内容放入哈希中,必须自己封装一个数组并重写hashcode()方法。
其实也不复杂,可以这样:
import java.util.Arrays;
public class MyIntArray {
private int[] array;
public MyIntArray(int[] array) {
this.array = array;
}
// Getter and setter methods...
@Override
public int hashCode() {
return Arrays.hashCode(array);
}
// Equals method and other code...
}
MyIntArray
类包装了一个整型数组。在hashCode()
方法中使用Arrays.hashCode()
方法来计算整型数组的哈希码。该方法会将整型数组的内容纳入计算,并返回最终的哈希码。
注意:Arrays.hashCode()
方法会考虑整型数组的内容来计算哈希码。这样可以确保在只有数组的内容相同的情况下,两个MyIntArray
对象的哈希码才会相等。
Arrays.hashCode()
是Java中Arrays
类提供的一个静态方法,用于计算数组的哈希码。它接受一个数组作为参数,并返回一个基于数组内容的哈希码。
Arrays.hashCode()
方法的计算过程如下:
如果传入的数组为null,返回0作为哈希码。
如果传入的数组不为null,计算数组的哈希码。
遍历数组的每个元素,并将每个元素的哈希码进行累加或异或操作,生成最终的哈希码。
使用
Arrays.hashCode()
方法可以方便地计算数组的哈希码,而不需要手动编写复杂的哈希码计算逻辑。它内部使用了与Java的Object.hashCode()
方法类似的算法,确保在只有数组的内容相同的情况下,不同的数组会生成不同的哈希码。需要注意的是,
Arrays.hashCode()
方法只计算数组的内容,而不考虑数组的引用地址。这意味着如果两个数组具有相同的内容,即使它们在内存中的位置不同,它们的哈希码也会相等。
由于hashcode是native方法,没法直接在idea中查看到它的源码。不过记住这个结论就好了。
我实现的时候其实没有用到上面的这些O(∩_∩)O
我通过自定义arrayToString()方法,把数组的内容转换成字符串,然后对字符串进行哈希操作。String是重写过hashcode()方法的,所以没有上述问题。
为什么用Map不用Set?原因很简单,因为原数组grid当中可能存在内容相同的行。如果用哈希Set,那么它们会被去重。比如原数组中有两行都是2 2 7 1,转置数组tmp中也有一行是2 2 7 1.那么原本应该记录结果为2,但由于Set去重了原数组中的两相同行,最终结果会变成1.
String arrayToString(int[] array) {
String ret = "";
for (int j : array) {
ret += j + " ";
}
return ret;
}
注意,ret += j + " " 这一句里,后面的这个空格拼接非常重要。看看输入这个样例的情况就知道了:
[[11,1],[1,11]]
Java里的Arrays.toString转换后是格式化的字符串,其实也是可以的。因为这里这个分隔符并不影响。
不过,要想没有分隔符,也是可以的,可以这样:
import java.util.Arrays;
import java.util.stream.Collectors;
int[] arr = {1, 2, 3, 4, 5};
String arrString = Arrays.stream(arr)
.mapToObj(String::valueOf)
.collect(Collectors.joining());
System.out.println(arrString); // 输出:12345
(不过这道题似乎就没有这个必要背这个了……)
我提交的代码是这,是通过的:
class Solution {
String arrayToString(int[] array) {
int n = array.length;
String ret = "";
for (int j : array) {
ret += j + " ";
}
return ret;
}
public int equalPairs(int[][] grid) {
int n = grid.length;
int[][] tmp = new int[n][n];
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
tmp[i][j] = grid[j][i];
}
}
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
System.out.print(grid[i][j] + " ");
}
System.out.println();
}
System.out.println("-----");
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
System.out.print(tmp[i][j] + " ");
}
System.out.println();
}
int count = 0;
Map<String, Integer> map = new HashMap<>();
for (int i = 0; i < n; i++) {
String str = arrayToString(grid[i]);
map.put(str, map.getOrDefault(str, 0)+1);
}
int j = 0;
while(j < n) {
String str = arrayToString(tmp[j]);
if(map.containsKey(str)) {
count += map.get(str);
}
j++;
}
return count;
}
}
今天还刷了二分:162. 寻找峰值
class Solution {
int bin(int[] nums, int l, int r) {
if(l == r) {
return l;
}
l = 1;
r = nums.length-2;
while(l < r) {
int mid = (l+r+1)>>1;
if(nums[mid] > nums[mid+1] && nums[mid] > nums[mid-1]) {
return mid;
}else if(nums[mid] < nums[mid+1]){
l = mid;
}else if(nums[mid] > nums[mid+1]){
r = mid-1;
}
}
return l;
}
public int findPeakElement(int[] nums) {
if(nums.length == 1) {
return 0;
}
int ret = bin(nums, 1, nums.length-2);
if(nums[0] > nums[1]) ret = 0;
if(nums[nums.length - 1] > nums[nums.length - 2]) ret = nums.length - 1;
return ret;
}
}
巩固一下模板: