ツリー配列
Leetcodeは、毎日の質問で線分ツリーの問題に遭遇します。テンプレートを読んでいないと、午前中はびっくりする可能性がありますが、ツリー配列のテンプレートを理解していれば、この問題は簡単に解決できます。 、それは実際には単なるテンプレートです。問題は、ツリー配列の構造を強制的に絞り出す場合、それが関与したかどうかによって異なります。これは非常に強力です。
ツリーのような配列学習:
https://oi-wiki.org/ds/fenwick/
1.構造的性質
配列では、インデックス1から始まり、隣接する2つのインデックス値ごとに接続され、インデックス値が大きい方がCレイヤーであると仮定して、インデックス値が小さい上位レイヤーが参照され、次にC層のインデックス値は再び2つずつ接続されますが、それでも大きなインデックス値を持つ上位層を参照し、それがD層であり、小さい方がC層にとどまり、Dを再帰的に接続するとしますEFG H ......などのレイヤーを作成し続けるには、レイヤーを1つずつ作成します。
そのような奇数インデックス13579を見るのは明らかです。これらはリーフノードです。これは、時間に接続された最初の22が、インデックス値が奇数インデックス値に接続されて偶数に戻っていると判断されたためです。
さらに、ペアワイズ接続の実践も2 ^ Nの実施形態であり、2 ^ Nのインデックス値のみがより高いNレベルに昇格されます。
2.検索
次に、構造は整然としたインデックス値構造で構造化されているため、配列内の各ノードの数、つまりターゲットノード(インデックス値)と次に格納される量を確認するための検索方法が格納されていると見なすことができます。インデックス値へノードの数、または逆に親ノードを見つけて、親ノードへの子ノードの数を数えます。
ロービット:
public int lowbit(int i) {
return i & -i;
}
このブロックは統計処理中です。現在のノードi(インデックス値i)を計算しました。次に、統計を続行するためにどのノードにジャンプしますか?カウントを続けるには、i + lowbit(i)またはi-lowbit(i)にジャンプするだけです。
性質上、配列のインデックス値はペアで接続されていることがわかります。奇数はすべて孤立しており、2 ^ Nはすべて人間であり、バイナリ2 ^ Nは1000 000を表します...( N個のゼロ)、0、i + lowbit(i)(下から見上げる場合)、i-lowbit(i)(上から見下ろす場合)の数のレイヤーがあります。
そして、iは正の整数、-iは補集合、iが奇数の場合i&-i = 1、iが偶数の場合i&-i = 2 ^ Nは定理です。
親ノードデータの更新
public void update(int i, int v) { // 索引 i 插入数量 v
while(i <= N) {
tree[i] += v;
i += lowbit(i); // 往上找父节点,每个节点都更新数量 v
}
}
統計ダウン
public int getSum(int i) { // 从索引 i 下面,统计所有 <= i 的索引存放数量
int ans = 0;
while(i > 0) {
ans += tree[i];
i -= lowbit(i); // 不断往 <= i 的索引找
}
return ans;
}
问题:命令を使用してソートされた配列を作成する
難易度:難しい
説明:
順序付けされていない配列が与えられた場合、配列の挿入ソートを行い、検索を依頼します。配列内の各要素を挿入ソートする場合、すべての要素に必要な最小数の比較(消費と呼ばれます)。挿入ソートは、キューまたは挿入の前に挿入できます。チームの後、各要素は、チームの前後の挿入の最小消費量を計算するだけで済みます(つまり、問題は、それよりも大きい数と最小値よりも小さい数です)。
件名リンク:https://leetcode.com/problems/create-sorted-array-through-instructions/submissions/
入力範囲:
1 <= instructions.length <= 105
1 <= instructions[i] <= 105
ケースを入力してください:
Example 1:
Input: instructions = [1,5,6,2]
Output: 1
Explanation: Begin with nums = [].
Insert 1 with cost min(0, 0) = 0, now nums = [1].
Insert 5 with cost min(1, 0) = 0, now nums = [1,5].
Insert 6 with cost min(2, 0) = 0, now nums = [1,5,6].
Insert 2 with cost min(1, 2) = 1, now nums = [1,2,5,6].
The total cost is 0 + 0 + 0 + 1 = 1.
Example 2:
Input: instructions = [1,2,3,6,5,4]
Output: 3
Explanation: Begin with nums = [].
Insert 1 with cost min(0, 0) = 0, now nums = [1].
Insert 2 with cost min(1, 0) = 0, now nums = [1,2].
Insert 3 with cost min(2, 0) = 0, now nums = [1,2,3].
Insert 6 with cost min(3, 0) = 0, now nums = [1,2,3,6].
Insert 5 with cost min(3, 1) = 1, now nums = [1,2,3,5,6].
Insert 4 with cost min(3, 2) = 2, now nums = [1,2,3,4,5,6].
The total cost is 0 + 0 + 0 + 0 + 1 + 2 = 3.
Example 3:
Input: instructions = [1,3,3,3,2,4,2,1,2]
Output: 4
Explanation: Begin with nums = [].
Insert 1 with cost min(0, 0) = 0, now nums = [1].
Insert 3 with cost min(1, 0) = 0, now nums = [1,3].
Insert 3 with cost min(1, 0) = 0, now nums = [1,3,3].
Insert 3 with cost min(1, 0) = 0, now nums = [1,3,3,3].
Insert 2 with cost min(1, 3) = 1, now nums = [1,2,3,3,3].
Insert 4 with cost min(5, 0) = 0, now nums = [1,2,3,3,3,4].
Insert 2 with cost min(1, 4) = 1, now nums = [1,2,2,3,3,3,4].
Insert 1 with cost min(0, 6) = 0, now nums = [1,1,2,2,3,3,3,4].
Insert 2 with cost min(2, 4) = 2, now nums = [1,1,2,2,2,3,3,3,4].
The total cost is 0 + 0 + 0 + 0 + 1 + 0 + 1 + 0 + 2 = 4.
私のコード:
BSTを使い始めたときは完全にタイムアウトしました。
ツリー配列を学習していない場合は非常に困難ですが、他の人の家族からこの天才ツリーを学習する場合は、テンプレートを使用し、要素値をキーとして使用して、ツリーの添え字値に対応させます。
java:
class Solution {
private static int N = 100001;
private static int[] tree = new int[N];
public int lowbit(int i) {
return i & -i;
}
public void update(int i, int v) {
while(i <= N) {
tree[i] += v;
i += lowbit(i);
}
}
public int getSum(int i) {
int ans = 0;
while(i > 0) {
ans += tree[i];
i -= lowbit(i);
}
return ans;
}
public int createSortedArray(int[] inst) {
long res = 0;
int len = inst.length;
Arrays.fill(tree, 0);
for(int i = 0;i < len;i ++) {
res += Math.min(getSum(inst[i] - 1), i - getSum(inst[i]));
update(inst[i], 1);
}
return (int)(res % ((int)Math.pow(10, 9) + 7));
}
}
C ++:
class Solution {
public:
int N = 100001;
int *tree = new int[N];
int lowbit(int i) {
return i & -i;
}
void update(int i, int v) {
while (i < N) {
tree[i] += v;
i += lowbit(i);
}
}
int getSum(int i) {
int ans = 0;
while (i) {
ans += tree[i];
i -= lowbit(i);
}
return ans;
}
int createSortedArray(vector<int>& instr) {
memset(tree, 0, N);
long res = 0;
int n = instr.size();
for (int i = 0; i < n; ++i) {
res += min(getSum(instr[i] - 1), i - getSum(instr[i]));
update(instr[i], 1);
}
return (int)(res % 1000000007);
}
};
タイムアウトBSTもありますが、メモリを大量に消費し、比較統計の数が多すぎます。
class Solution {
private static long res;
private static int num, len, size;
public int createSortedArray(int[] inst) {
res = 0;
num = 1;
len = inst.length;
size = len + 1;
int[] val = new int[size], left = new int[size], right = new int[size]
,nleft = new int[size], nright = new int[size], n = new int[size];
val[1] = inst[0];
n[1] = 1;
for(int i = 1;i < len;i ++) {
int[] mamx = new int[2];
insert(inst[i], 1, val, left, right, nleft, nright, n, mamx);
res += Math.min(mamx[0], mamx[1]);
}
return (int)(res % ((int)Math.pow(10, 9) + 7));
}
public int insert(int v, int r, int[] val, int[] left, int[] right, int[] nleft, int[] nright, int[] n, int[] mamx) {
if(val[r] == 0) {
r = ++ num;
n[r] ++;
val[r] = v;
} else if(val[r] == v) {
n[r] ++;
mamx[0] += nleft[r];
mamx[1] += nright[r];
} else if(val[r] < v) {
right[r] = insert(v, right[r], val, left, right, nleft, nright, n, mamx);
nright[r] ++;
mamx[0] += n[r] + nleft[r];
} else if(val[r] > v) {
left[r] = insert(v, left[r], val, left, right, nleft, nright, n, mamx);
nleft[r] ++;
mamx[1] += n[r] + nright[r];
}
return r;
}
}