天天看點

1803. 統計異或值在範圍内的數對有多少題目大意:思路分析AC代碼(帶注釋,友善複習)

周賽題解

  • 題目大意:
  • 思路分析
    • 閑扯
    • 思路
  • AC代碼(帶注釋,友善複習)

題目大意:

統計異或值在範圍内的數對有多少

給你一個整數數組 nums (下标 從 0 開始 計數)以及兩個整數:low 和 high ,請傳回 漂亮數對 的數目。

漂亮數對 是一個形如 (i, j) 的數對,其中 0 <= i < j < nums.length 且 low <= (nums[i] XOR nums[j]) <= high 。

  • 輸入輸出

輸入:nums = [1,4,2,7], low = 2, high = 6

輸出:6

解釋:所有漂亮數對 (i, j) 列出如下:

- (0, 1): nums[0] XOR nums[1] = 5

- (0, 2): nums[0] XOR nums[2] = 3

- (0, 3): nums[0] XOR nums[3] = 6

- (1, 2): nums[1] XOR nums[2] = 6

- (1, 3): nums[1] XOR nums[3] = 3

- (2, 3): nums[2] XOR nums[3] = 5

  • 資料範圍

1 <= nums.length <= 2 * 104

1 <= nums[i] <= 2 * 104

1 <= low <= high <= 2 * 104

思路分析

閑扯

這道題給人的第一感覺就是直接暴力枚舉,一看資料範圍就知道還是刷題不夠,這個2e4範圍明顯不能暴力枚舉,賽後聽群裡大佬說用Trie樹,雖然知道Trie樹的基本用法,但還是不會bushi,看了題解才發現隻會用Trie樹求最大異或對是遠遠不夠的

思路

  • 我們使用Trie樹來存儲 (1-i-1) 的所有數,第i個數為x,這裡采用邊插入邊查詢,即每次插入x之前查詢 (1-i-1) 中滿足與x異或在範圍内的,是以需要開辟的空間為:O(NlogS)
  • 查詢操作的時候如何查找初符合x^u在範圍内的數量是這道題的難點,可以采用字首和的思想:找出 x ^ u<=high的u的數量r,滿足 x ^u <=low-1 的數量l,則對于插入的第i個數,1-i-1 中滿足的數為: r-l
  • 問題轉化為求x ^u<=limit 的u的個數,這種寫法我一直wa掉,最後借鑒了大佬的<limit 的寫法,這樣寫法很簡明,以後建議使用
  • 具體的Trie樹操作可以去了解一下,這個資料結構處理異或的一些操作很有效

AC代碼(帶注釋,友善複習)

class Solution {
public:
    static const int N=20010*20;
    int tr[N][2],cnt[N],idx=0;
    void insert(int x)
    {
        int p=0;
        for(int i=16;i>=0;i--){
            int u=x>>i&1;
            if(!tr[p][u]) tr[p][u]=++idx;
            p=tr[p][u];
            cnt[p]++;
        }
    }
    int query(int x,int limit)
    {
        int p=0;
        int res=0;
        for(int i=16;i>=0;i--){
            int u=x>>i&1,v=limit>>i&1;
            //這種寫法可以發現res累加的都是異或後小于limit的,等于的都沒有選擇,是以limit的範圍要大一
            //因為每次有兩種選擇時,我都是目前的cur與limit相等,
            //是以每次累加的都是異或後<limit的,最後統計的總和也是異或後小于limit的,
            if(u == 0 && v == 0) p = tr[p][0];
            else if(u == 0 && v == 1) res += cnt[tr[p][0]], p = tr[p][1];
            else if(u == 1 && v == 0) p = tr[p][1];
            else if(u == 1 && v == 1) res += cnt[tr[p][1]], p = tr[p][0];
            if(!p) break;
        }
        return res;
    }
    int countPairs(vector<int>& nums, int low, int high) {
        int res = 0;
        for(auto &x : nums) {
        //這裡要先查詢在插入,因為x^x =0也是滿足的
            res += query(x, high+1) - query(x, low);
            insert(x);
        }
        return res;
    }
};