每日一题,由自信走向自闭(493. 翻转对,level:hard)
前言
第一次思考
-
当我看完题目,顿觉好像有点思路了,又看了看难度:
hard
,有点震惊,这不是可以用哈希表做么? -
当我想用
哈希表
时,想到键值的问题:key
放什么,value
放什么。
初步思考觉得key可以为值,value为下标,但是看了第一个示例又打消了念头。(第一个示例有两个值相同,但下标不同)只能再修改一下value,结果发现value不行,于是打算改成计数数组即cnt[]做。
第二次思考
-
cnt数组
的上限可以去原数组找最高值,然后eleMx*2
即可。 -
那么有一个问题,cnt[]放数组出现的元素?还是放元素的两倍?为了方便,我觉得可以直接放元素的两倍,之后用来查询是否存在当前值
cur(nums[i])>nums[j]*2
。 -
还有一个问题,题目要求
i > j
&&nums[i] > nums[j]*2
,这里的cnt是有可能记录到i前面已有的符合值,所以每遍历一个元素必须删除一个。
再度思考完,基本可以用解决第一二个示例了。
class Solution {
public int reversePairs(int[] nums) {
int ans = 0,n = nums.length;
int max = 0;
//取数组上限
for(int i : nums){
max = Math.max(max, i);
}
int[] cnt = new int[max * 2 + 5];
//先计算元素*2值
for(int i : nums){
cnt[i * 2]++;
}
//每过一个元素,删除对应cnt
for(int i = 0;i < n - 1; ++i){
int cur = nums[i];
for(int j = cur - 1;j > 0;--j){
if(cnt[j] > 0){
ans++;
}
}
cnt[i]--;
}
return ans;
}
}
第三次思考
-
上一个思考可以实现题目的两个示例,但在提交时报错了,出现了
[-5,-5]
这样的负数示例,我直接否认了之前的想法,因为题目注意下面说了最大值不超过32位
,所以又回到了第一次思考。 -
这一次我自然地把
value
值当成了key值频率
,然后对原先的进行替换修改。以为可以解决负数这一难题,结果还是太天真,GG。
最后我发现下限出现了问题,我前面的思考没考虑到负数这一情况,所以我打算直接从下限
入手,进行修改。
class Solution {
public int reversePairs(int[] nums) {
int ans = 0,n = nums.length;
//数组无法解决负数,key:当前下标值*2 value:出现次数
Map<Integer,Integer> map = new HashMap();
//先计算元素*2值
for(int i = 0;i < n;++i){
map.put(nums[i] * 2,map.getOrDefault(nums[i] * 2, 0) + 1);
}
//每过一个元素,删除对应map
for(int i = 0;i < n - 1; ++i){
int cur = nums[i];
int flag = cur > 0 ? 0 : Integer.MIN_VALUE;
for(int j = cur - 1;j > flag;--j){
if(map.containsKey(j) && map.get(j) > 0){
ans++;
}
}
map.put(nums[i] * 2, map.get(nums[i] * 2) - 1);
}
return ans;
}
}
- 重点来了!此时我以为万事俱备,必能过的时候,测试案例给我来了一棒
[2147483647,2147483647,2147483647,2147483647,2147483647,2147483647]
什么东西,边缘值???
自此,思考结束,我发现hard不愧是hard。。。。
题解之一:归并排序
递归里面主要分为:
- 临界条件
- 递归left和right,保存ret值
- 统计下标对数量
- 合并两个有序数组,
- 更新nums数组为有序数组