3種算法 - 子數組異或查詢


題目

有一個正整數數組 arr,現給你一個對應的查詢數組 queries,其中 queries[i] = [Li, Ri]。

對於每個查詢 i,請你計算從 Li 到 Ri 的 XOR 值(即 arr[Li] xor arr[Li+1] xor … xor arr[Ri])作爲本次查詢的結果。

並返回一個包含給定查詢 queries 所有結果的數組。

示例 1:

輸入:arr = [1,3,4,8], queries = [[0,1],[1,2],[0,3],[3,3]]
輸出:[2,7,14,8]
解釋:
數組中元素的二進制表示形式是:
1 = 0001
3 = 0011
4 = 0100
8 = 1000
查詢的 XOR 值爲:
[0,1] = 1 xor 3 = 2
[1,2] = 3 xor 4 = 7
[0,3] = 1 xor 3 xor 4 xor 8 = 14
[3,3] = 8
示例 2:

輸入:arr = [4,8,2,10], queries = [[2,3],[1,3],[0,0],[0,3]]
輸出:[8,0,4,4]

提示:

1 <= arr.length <= 3 * 10^4
1 <= arr[i] <= 10^9
1 <= queries.length <= 3 * 10^4
queries[i].length == 2
0 <= queries[i][0] <= queries[i][1] < arr.length

解法一

思路:
最直接的思路,就是直接對區間執行兩層循環,進行遍歷,但實際執行最後一個一個測試用例時超時,代碼及測試用例如下(測試用例有525kb,應該是一個29898個數據的數組和2萬4千多個[0,29898],太長了,文檔中只放了一部分),可以通過這個地址下載查看該測試用例:https://www.zhenxiangsimple.com/files/tech/testCase20200105.txt

空間複雜度:O(1)
時間複雜度:O(k*m),k爲queries數組個數,m爲數據差值

public class Solution {
    public int[] XorQueries(int[] arr, int[][] queries) {
        int [] r = new int[queries.Length];
        for(int i=0;i<queries.Length;i++)
        {
            int t = 0;
            for(int j=queries[i][0];j<=queries[i][1];j++)
            {
                t = t^ arr[j];
            }
            r[i] = t;
        }
        return r;
    }
}
[64038788,905710003,961785464,588745940,342531091,......,[0,29898],[0,29898],[0,29898],[0,29898],[0,29898]]

解法二

思路:
由於解法一超時,想辦法看看能否減少重複計算,當前算法使用空間換時間多思路,先將所有值計算出來,然後查找時候直接索引查找。但是,這種做法對內存消耗太大,對解法一超時多測試用例,當前解法超出了內存空間。
事實上,程序在提交的時候,還沒運行到最後一個測試用例,已經內存超出了,測試用例有668Kb,點擊鏈接查看該測試用例:https://www.zhenxiangsimple.com/files/tech/testCase202001051.txt
1,行表示當前計算的數據個數
2,列表示當前計算多起始索引
因此,最終只需要獲取數據數和索引即可,代碼如下:

空間複雜度:O(N2),N爲arr數組數據
時間複雜度:O(N2 + k),k爲queries數組個數

public class Solution {
    public int[] XorQueries(int[] arr, int[][] queries) {
        int len = queries.Length, lenA = arr.Length;
        int [,] t = new int[lenA,lenA];
        for(int i=0;i<lenA;i++)
        {//首行
            t[0,i] = arr[i];
        }
        for(int i=1;i<lenA;i++)
        {//之後行
            for(int j=0;j<lenA-i;j++)
            {
                t[i,j] = t[i-1,j] ^ arr[j+i];
            }
        }
        
        int [] r = new int[len];
        for(int i=0;i<len;i++)
        {
            int rIdx=queries[i][1] - queries[i][0];
            r[i] = t[rIdx,queries[i][0]];
        }
        return r;
    }
}

解法三

思路:
使用前綴和的思路,即首先通過前綴累積,然後通過索引對應第值進行相減得到區間值,不過本算是多和改爲異或,即進行前綴異或算法,索引N存儲前N個數的異或值,並通過兩個位置的和相減得到區間值。
對於異或來講,加法和減法都是執行異或操作,即A xor A = 0或者 A xor B xor A = B。
代碼如下:
空間複雜度:O(N),N爲arr數組數據
時間複雜度:O(N+k),k爲queries數組個數

public class Solution {
    public int[] XorQueries(int[] arr, int[][] queries) {
        int len=queries.Length, lenA = arr.Length;
        int [] t = new int[lenA+1];
        t[0] = 0;
        for(int i=1;i<=lenA;i++)
        {
            t[i] = t[i-1] ^ arr[i-1];
        }
        
        int [] r = new int[len];
        for(int i=0;i<len;i++)
        {
            r[i] = t[queries[i][1]+1] ^ t[queries[i][0]];
        }
        return r;
    }
}

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章