1. 程式人生 > 實用技巧 >每日一題,由自信走向自閉(493. 翻轉對,level:hard)

每日一題,由自信走向自閉(493. 翻轉對,level:hard)

前言

493. 翻轉對

第一次思考

  • 當我看完題目,頓覺好像有點思路了,又看了看難度: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。。。。

題解之一:歸併排序

遞迴裡面主要分為:

  1. 臨界條件
  2. 遞迴left和right,儲存ret值
  3. 統計下標對數量
  4. 合併兩個有序陣列,
  5. 更新nums陣列為有序陣列

官方題解