无法弄清楚我的二进制索引树解决方案有什么问题

时间:2016-07-20 22:14:11

标签: c++ algorithm binary-indexed-tree

我正在解决问题。

    Count of Range Sum

    Given an integer array nums, return the number of range sums that 
    lie in [lower, upper] inclusive. Range sum S(i, j) is defined as 
    the sum of the elements in nums between indices i and j (i ≤ j),inclusive.
    Example: Given nums = [-2, 5, -1], lower = -2, upper = 2, Return 3.
    The three ranges are : [0, 0], [2, 2], [0, 2] and their respective sums are: -2, -1, 2

我的解决方案如下:

1.将[0,i]中的所有总和作为sum [i]

2.将矢量和矢量作为克隆矢量,并根据克隆矢量中的索引重新索引元素。将sum元素值作为map reflect的键,将new index作为reflect的值。将向量和元素从后向前添加到二进制索引树中,同时在克隆中找到满足下限和上限条件的有效元素索引范围[idx1,idx2]。

3.在我们的BIT中记住从节点0到节点idx1的总和以及从节点0到节点idx2的总和。如果节点已插入BIT,我们将在BIT中找到该节点。因此,满足我们的约束条件的节点数量是总和。

 public:
 vector<long>tree,clone;
 int countRangeSum(vector<int>& nums, int lower, int upper) {
 int n=nums.size();
 vector<long>sum(n+1);
 for(int i=1;i<=n;i++)
 sum[i]=sum[i-1]+nums[i-1];// step1

 clone=sum;
 sort(clone.begin(),clone.end());
 tree.resize(sum.size()+1);
 unordered_map<long,int>reflect;
 for(int i=0;i<clone.size();i++)
 reflect[clone[i]]=i;//step2

 int res=0;
 for(int i=sum.size()-1;i>=0;i--)
 {

   int idx1=binarysearch(sum[i]+lower,true);
   int idx2=binarysearch(sum[i]+upper,false);

   res=res+count(idx2)-count(idx1);
   add(reflect[sum[i]]); //step3
 }
 return res;
 }




 int binarysearch(long val, bool includeself)
{  
if(includeself)
return lower_bound(clone.begin(),clone.end(),val)-clone.begin();
return upper_bound(clone.begin(),clone.end(),val)-clone.begin();
}





void add(int pos){
pos=pos+1;
while(pos<tree.size())
{
    tree[pos]++;
    pos=pos+(pos&-pos);
}
}




int count(int pos){
int cnt=0;
pos=pos+1;
while(pos>0)
{
    cnt=cnt+tree[pos];
    pos=pos-(pos&-pos);
}
return cnt;
}

错误: 输入: [-2,5,-1] -2 2 输出: 197 预期: 3

我真的不知道如何格式化我的代码,我总是写这样的c ++这样......

抱歉它有点长,我想好几天仍然不知道哪里出错了。任何想法都赞赏!!

1 个答案:

答案 0 :(得分:0)

我很难理解你是如何尝试使用二进制索引树的,但我想我明白了。

让我试着解释一下我认为算法是什么,用n作为输入数组的长度。

  1. 计算范围以索引0开头的所有范围总和。
  2. 按递增顺序对这些总和进行排序。
  3. 初始化大小为n的二进制索引树,表示每个位置的频率计数为0。这表示您开始的所有总和都是无效的,并且它将用于跟踪算法进展时哪些总和变为有效。
  4. 通过范围和S(0,n)隐式偏移所有和,以便获得范围以索引n而不是索引0开始的范围和。
  5. 确定落入[下限,上限]的最小和最大总和的排序列表中的索引。
  6. 查询二进制索引树以计算这些总和中有多少是有效的。将此值添加到属于[下限,上限]
  7. 的范围总和的计数中
  8. 确定二进制索引树中范围和S(0,n)的索引,并通过将其频率计数设置为1来标记它将在下一次迭代中成为有效总和。
  9. 循环回到步骤4,遍历n - 1,n - 2,n - 3 ,. 。 。,2,1,0。
  10. 我认为,您实现的最重要问题是您的树不够大。它应该更大一点,因为不使用0索引。所以使用

    tree.resize(sum.size()+2);
    

    而不是您当前的+1

    此外,如果您希望能够多次使用该方法,则需要清除树,将所有值设置回零,而不是仅调整其大小。

    修复第一个问题使其适用于您的示例数据。我没有注意到你的代码有任何其他问题,但我没有彻底测试。