首页 > 试题广场 >

奇特区间数

[编程题]奇特区间数
  • 热度指数:892 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解
给出一个大小为n的数组a和整数t,定义区间[l,r](0<=l<r<=n-1),若存在下标i,j(l<=i<j<=r)属于区间[l,r],且a[i]异或a[j]=t,那么称[l,r]是非奇特区间,如不存在,则[l,r]是奇特区间,求a数组里的奇特区间个数。
示例1

输入

[2,4,8],6

输出

1

说明

因为2异或4为6,等于t,所以只有区间[1,2]是奇特区间,对应的数组是[4,8],数组不能为[2,4],数组也不能为[2,4,8],因为里面包含了2和4
示例2

输入

[2,3,4],6

输出

2

说明

因为2异或4为6,等于t,所以区间[0,1],[1,2]是奇特区间,对应的数组分别为[2,3],[3,4]

备注:


滑动窗口

先定义两个指针left和right,均从0开始,作为窗口的左右边界,记区间的左右边界为L和R。
遍历数组,扩张窗口的右边界,考察每个元素a[right]为区间右端点的情况。当右边界遍历到某个位置right时,累加a[right]的频数。
  1. 如果a[right]^t在哈希表内,说明之前加入的数中存在一个数a[right]^t,当它作为区间左边界元素时,在a[right]为区间右边界的情况下会造成a[L]^a[R]=a[right]^t^a[right]=t,使得[L,R]为非奇特区间,此时开始收缩窗口的左边界,直到非奇特区间被排除在外,即a[right]^t不在哈希表内。
  2. 如果a[right]^t不在哈希表内,说明[left,right]中都是奇特区间,在right为区间右端点的情况下,从left到right-1都可以作为区间的左端点形成奇特区间,此时有right-left个奇特区间产生,将其累加到奇特区间的总数上。
import java.util.*;


public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param a int整型一维数组 
     * @param t int整型 
     * @return long长整型
     */
    public long section (int[] a, int t) {
        // write code here
        int n = a.length;
        HashMap<Integer, Integer> counter = new HashMap<>();
        int left = 0, right = 0;
        long count = 0;
        while(right < n){
            counter.put(a[right], counter.getOrDefault(a[right], 0) + 1);
            while(counter.containsKey(a[right] ^ t)){
                // 收缩左边界
                if(counter.get(a[left]) == 1){
                    counter.remove(a[left]);
                }else{
                    counter.put(a[left], counter.get(a[left]) - 1);    // 排除一个能与a[right]异或得到t的值
                }
                left++;
            }
            count += right - left;
            // 扩张右边界
            right++;
        }
        return count;
    }
}

编辑于 2022-01-05 11:58:56 回复(2)
最核心的思想: 
a[i]^a[j] = t 
-> a[i] ^ a[j] ^ a[i] = t ^ a[i] 
-> a[j] = t ^ a[i]

func section( a []int ,  t int ) int64 {
    // 存在a[i]^a[j] == t 就不是奇特区间
    // 用map 存储出现的数,并且遍历到j时判断a[j]^t是否存在
    // a[i] == a[j]^t 就不是奇特区间
    m := make(map[int]int, 0)
    l, r := 0, 0
    ans := 0
    for r < len(a) {
        m[a[r]] = r
        for {
            if idx, ok := m[a[r]^t]; !ok || idx < l {
                break
            } else {
                l = idx+1
            }
        }
        // fmt.Println(l, r)
        ans += r-l
        r ++
    }
    return int64(ans)
}


发表于 2023-03-15 17:28:14 回复(0)
滑动窗口:
class Solution {
public:
    long long section(vector<int>& a, int t) {
        // write code here
        unordered_map<int, int> un;
        long long ans = 0;
        int l = 0, r = 0;
        while (r < a.size()) {
            if (un.count(a[r] ^ t) > 0) {
                l = max(l, un.at(a[r] ^ t) + 1);
            }
            ans += r - l;
            un[a[r]] = r;
            r++;
        }
        return ans;
    }
};


编辑于 2022-04-02 17:23:04 回复(3)
    public long section (int[] a, int t) {
        // write code here
        int l = 0, r = 1;
        long res = 0;
        Map<Integer,Integer> map = new HashMap<>();
        map.put(a[l],l);
        while(r < a.length) {
            int now = a[r];
            if(map.containsKey(now^t)) {
                l = Math.max(map.get(now^t) + 1, l);
            }
            res += r - l;
            map.put(now,r);
            r++;
        }
        return res;
    } 
map记录出现数字的下标,每次冲突,左边界直接跳到冲突数字的下一个
发表于 2022-03-07 18:48:55 回复(1)

答案

这个问题要求找出所有的“奇特区间”,这些区间定义为在一个给定数组 a 中,不存在两个元素 a[i]a[j](其中 i < j)使得它们的异或结果等于给定的整数 t

解决这个问题的一个有效方法是使用滑动窗口技术。具体步骤如下:

  1. 初始化两个指针 leftright,它们都从数组的起始位置开始。这两个指针将定义一个窗口,窗口内的元素是当前考虑的子数组。

  2. 遍历数组,逐渐扩大窗口的右边界。对于每个新的 right 位置,我们检查在这个位置之前的所有元素是否存在某个元素,与 a[right] 的异或结果等于 t。如果存在,说明当前窗口不是奇特区间,我们需要收缩左边界直到排除这种情况。

  3. 如果在当前窗口内,没有找到与 a[right] 异或等于 t 的元素,那么从 leftright 的所有子区间都是奇特区间。

  4. 使用一个哈希表来记录窗口内元素的出现次数,以便快速检查是否存在与 a[right] 异或等于 t 的元素。

  5. 在窗口右移的过程中,累加奇特区间的数量。

class Solution:
    def section(self, a, t):
        n = len(a)  # 获取数组的长度
        left = 0    # 初始化左指针
        right = 0   # 初始化右指针
        count = 0   # 用于计数奇特区间的数量
        counter = {}  # 用于存储数组中各元素的出现次数

        while right < n:  # 遍历数组
            # 将当前右指针所指元素的计数加1
            counter[a[right]] = counter.get(a[right], 0) + 1

            # 如果存在使得异或等于t的元素,开始收缩左边界
            while counter.get(a[right] ^ t, 0) > 0:
                # 减少左指针所指元素的计数
                counter[a[left]] -= 1
                # 如果左指针所指元素计数为0,则从counter中移除该元素
                if counter[a[left]] == 0:
                    del counter[a[left]]
                # 左指针向右移动
                left += 1

            # 计算并累加奇特区间的数量
            count += right - left
            # 右指针向右移动
            right += 1

        return count  # 返回奇特区间的总数

# 示例使用
sol = Solution()
print(sol.section([2, 4, 8], 6)) # 输出: 1
print(sol.section([2, 3, 4], 6)) # 输出: 2
发表于 2023-11-13 17:35:30 回复(0)

滑动窗口 + 哈希

  1. 每次移动完右边界之后,以右边界为固定
  2. 对于固定的右边界,移动左边界,直到左边界到右边界中不会出现让这个区域内出现非奇特的区间(即cache[a[r] ^ t] == 0
from collections import defaultdict
class Solution:
    def section(self , a , t ):
        lenth = len(a)
        if lenth < 2:
            return 0

        cache = defaultdict(int)

        l, r = 0, 1
        cache[a[l]] += 1
        result = 0
        while r < lenth:
            while cache[a[r] ^ t] > 0:
                cache[a[l]] -= 1
                l += 1

            cache[a[r]] += 1
            result += r - l
            
            r += 1
        return result


编辑于 2023-05-30 14:49:32 回复(0)
class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param a int整型vector 
     * @param t int整型 
     * @return long长整型
     */

    typedef long long LL;
    long long section(vector<int>& a, int t) {
        // write code here
        LL res = 0;
        int n = a.size(), L = 0;
        unordered_map<int, int> cnt;
        for(int i = 0; i < a.size(); i ++) {
            if(cnt.count(a[i])) {
                L = max(L, cnt[a[i]] + 1);
            }
            res = res + 0ll + i - L;
            cnt[a[i] ^ t] = i;
        }
        return res;
    }
};

发表于 2023-01-23 00:14:43 回复(0)
class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param a int整型vector 
     * @param t int整型 
     * @return long长整型
     */
    long long section(vector<int>& a, int t) {
        // write code here
        unordered_map<int,int> mp;
        long long res=0;
        int l=0,r=0;
        while(r<a.size()){
            mp[a[r]]++;
            while(mp.count(a[r]^t) && mp[a[r]^t]>0){
                mp[a[l]]--;
                l++;
            }
            res+=(r-l);
            r++;
        }
        return res;
    }
};

发表于 2022-01-04 16:57:16 回复(0)
基本思路:滑动窗口
class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param a int整型vector 
     * @param t int整型 
     * @return long长整型
     */
    long long section(vector<int>& a, int t) {
        // write code here
        using ll = long long;
        ll res = 0;
        int n = (int)a.size();
        unordered_map<int, int> cnt;
        if (n < 2) return 0;
        cnt[a[0]]++;
        int l = 0, r = 1;
        while (r < n)
        {
            int c = t^a[r];
            while (cnt.count(c) > 0)
            {
                res += max(0, r-l-1);
                if (--cnt[a[l]] == 0)
                    cnt.erase(a[l]);
                l++;
            }
            cnt[a[r++]]++;
        }
        for (int i = l; i < n-1; ++i)
        res += max(0, r-i-1);
        return res;
    }
};


发表于 2021-12-24 20:13:25 回复(0)

问题信息

上传者:小小
难度:
9条回答 1943浏览

热门推荐

通过挑战的用户

奇特区间数