1.エリアと検索-配列は変更可能
1.1、タイトル要件
配列番号を指定して、2種類のクエリを実行してください。
- クエリの1つのタイプでは、配列numsの添え字に対応する値を更新する必要があります。
- 別のタイプのクエリは、配列nums内の(包括的)インデックスleftとインデックスrightの間のnumsの要素の合計を返すように要求します。ここでleft <= right
NumArrayクラスを実装します。
- NumArray(int [] nums)は、整数配列numsでオブジェクトを初期化します。
- void update(int index、int val)nums[index]の値をvalに更新します。
- int sumRange(int left、int right)配列nums内の(両端を含む)indexleftとindexrightの間のnumsの要素の合計を返します(つまり、nums [left] + nums [left + 1]、…、nums [right ])。
示例 1:
输入:
["NumArray", "sumRange", "update", "sumRange"]
[[[1, 3, 5]], [0, 2], [1, 2], [0, 2]]
输出:
[null, 9, null, 8]
解释:
NumArray numArray = new NumArray([1, 3, 5]);
numArray.sumRange(0, 2); // 返回 1 + 3 + 5 = 9
numArray.update(1, 2); // nums = [1,2,5]
numArray.sumRange(0, 2); // 返回 1 + 2 + 5 = 8
提示:
1 <= nums.length <= 3 * 104
-100 <= nums[i] <= 100
0 <= index < nums.length
-100 <= val <= 100
0 <= left <= right < nums.length
调用 pdate 和 sumRange 方法次数不大于 3 * 104
ソース:LeetCode
リンク:https ://leetcode-cn.com/problems/range-sum-query-mutable
1.2、lowbit()操作
このアルゴリズムを最初に実行するには、最初にツリー配列とは何かを理解する必要があります。
ツリー配列を理解するには、知っておく必要のある前提知識があります。それは** lowbit()**操作です。lowbit()演算とは何ですか?その概念的な理解は、非負の整数の最下位ビットと、バイナリ表現の背後にある0によって形成される値です。1))のビット単位のANDを反転します。
//计算树状数组中的lowbit(x)的值
int lowbit(int x){
return x & -x;
}
1.3。思考と実現
c [x]は[x-lowbit(x)+ 1、x]の合計です。ここで、次のシーケンスのグラフを描画します。
C[x]の親ノードはC[x+ lowbit(x)]です。
1.4、メソッドのクエリとメソッドの追加
1.4.1、クエリメソッド(間隔クエリ)
C [x]を追加または追加するには、祖先ノードを変更および変更し、x + = lowbit(x)を計算して、親ノードの添え字を取得します。
//树状数组中的query方法
int query(int x){
int ans = 0;
//查询tree[x]节点的前缀
for(int i = x;i > 0;i -= lowbit(i))
//计算tree[x]节点的前缀和
ans += tree[i];
return ans;
}
1.4.2、メソッドの追加(シングルポイント変更)
C [x]ノードの接頭辞の合計を照会し、ノードから座席までの前のノードを見つけ、x-= lowbit(x)を計算して、前のノードの添え字を取得します。
//树状数组中的add方法
void add(int x,int y){
//查询tree[x]节点的祖先节点
for(int i = x;i <= n;i +=lowbit(i))
//将tree[x]节点的祖先节点进行更改
tree[i] += y;
}
1.5、問題解決のアイデア
タイトルでは、実装で特定の位置にある修道女の値を更新する必要があるため、元のnums配列を保存します。
- コンストラクター:ツリー配列は最初はゼロシーケンスに対応しているため、nums配列をトラバースし、add関数を呼び出してツリー配列を更新します。
- update関数:インデックスでnumsの増分値を取得し、add関数を呼び出してツリー配列を更新し、nums [index]=valを更新します。
- sumRange関数:間隔の合計[左、右]は、2つのプレフィックスの合計の差に変換できます。ツリー配列のprefixSum関数を呼び出して、最初の右+ 1要素のプレフィックスの合計とsum1、およびのプレフィックスの合計を取得します。最初の左側の要素。Sum2、sum1-sum2を返します。
1.6。アルゴリズム
class NumArray {
//定义一个树状数组
int [] tree;
int [] sum;
int n;
//计算树状数组中的lowbit(x)的值
int lowbit(int x){
return x & -x;
}
//树状数组中的query方法
int query(int x){
int ans = 0;
//查询tree[x]节点的前缀
for(int i = x;i > 0;i -= lowbit(i))
//计算tree[x]节点的前缀和
ans += tree[i];
return ans;
}
//树状数组中的add方法
void add(int x,int y){
//查询tree[x]节点的祖先节点
for(int i = x;i <= n;i +=lowbit(i))
//将tree[x]节点的祖先节点进行更改
tree[i] += y;
}
//用整数数组 nums 初始化对象
public NumArray(int[] nums) {
sum = nums;
n = sum.length;
tree = new int[n+1];
for(int i = 0;i<n;i++)
add(i + 1,sum[i]);
}
//将 nums[index] 的值 更新 为 val
public void update(int index, int val) {
add(index + 1,val-sum[index]);
sum[index] = val;
}
//返回数组 nums 中索引 left 和索引 right 之间( 包含 )的nums元素的和
public int sumRange(int left, int right) {
return query(right + 1) - query(left);
}
}