Skip to content

Commit bfe5db1

Browse files
committed
feat: add solutions to lc problem: No.0775
No.0775.Global and Local Inversions
1 parent e5a785b commit bfe5db1

File tree

6 files changed

+509
-2
lines changed

6 files changed

+509
-2
lines changed

solution/0700-0799/0775.Global and Local Inversions/README.md

+243-2
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,6 @@
4242
<strong>解释:</strong>有 2 个全局倒置,和 1 个局部倒置。
4343
</pre>
4444

45-
46-
4745
<p><strong>提示:</strong></p>
4846

4947
<ul>
@@ -58,22 +56,265 @@
5856

5957
<!-- 这里可写通用的实现逻辑 -->
6058

59+
**方法一:维护前缀最大值**
60+
61+
根据题意,我们可以发现,一个数组中的局部倒置一定是全局倒置,但是全局倒置不一定是局部倒置。也就是说,全局倒置的数量一定大于等于局部倒置的数量。
62+
63+
因此,我们枚举每个数 `nums[i]`,其中 $ 2 \leq i \leq n - 1$,维护前缀数组 $nums[0,..i-2]$ 中的最大值,记为 $mx$。如果存在 $mx$ 大于 $nums[i]$,则说明全局倒置的数量大于局部倒置的数量,返回 `false` 即可。
64+
65+
遍历结束后,返回 `true`
66+
67+
时间复杂度 $O(n)$,空间复杂度 $O(1)$。其中 $n$ 为数组 `nums` 的长度。
68+
69+
**方法二:树状数组**
70+
71+
这道题目实际上是一个“逆序对”问题。
72+
73+
局部倒置的数量等于相邻元素之间逆序对的个数,可以在遍历数组 `nums` 的过程中直接求出;而全局倒置的数量等于逆序对的个数,求解逆序对个数的一个常用做法是使用树状数组。
74+
75+
树状数组,也称作“二叉索引树”(Binary Indexed Tree)或 Fenwick 树。 它可以高效地实现如下两个操作:
76+
77+
1. 单点更新:即函数 `update(x, delta)`,把序列 $x$ 位置的数加上一个值 $delta$。时间复杂度 $O(\log n)$。
78+
1. 前缀和查询:即函数 `query(x)`,查询序列 `[1,...x]` 区间的区间和,即位置 $x$ 的前缀和。时间复杂度 $O(\log n)$。
79+
80+
对于本题,我们定义一个变量 $cnt$ 记录局部倒置的数量与全局倒置的数量之差。如果遍历过程中,$cnt$ 的值小于 $0$,则说明全局倒置的数量大于局部倒置的数量,返回 `false` 即可。
81+
82+
时间复杂度 $O(n\times \log n)$,空间复杂度 $O(n)$。其中 $n$ 为数组 `nums` 的长度。
83+
6184
<!-- tabs:start -->
6285

6386
### **Python3**
6487

6588
<!-- 这里可写当前语言的特殊实现逻辑 -->
6689

6790
```python
91+
class Solution:
92+
def isIdealPermutation(self, nums: List[int]) -> bool:
93+
mx = 0
94+
for i in range(2, len(nums)):
95+
mx = max(mx, nums[i - 2])
96+
if mx > nums[i]:
97+
return False
98+
return True
99+
```
68100

101+
```python
102+
class BinaryIndexedTree:
103+
def __init__(self, n):
104+
self.n = n
105+
self.c = [0] * (n + 1)
106+
107+
def update(self, x, delta):
108+
while x <= self.n:
109+
self.c[x] += delta
110+
x += x & -x
111+
112+
def query(self, x):
113+
s = 0
114+
while x:
115+
s += self.c[x]
116+
x -= x & -x
117+
return s
118+
119+
120+
class Solution:
121+
def isIdealPermutation(self, nums: List[int]) -> bool:
122+
n = len(nums)
123+
tree = BinaryIndexedTree(n)
124+
cnt = 0
125+
for i, v in enumerate(nums):
126+
cnt += (i < n - 1 and v > nums[i + 1])
127+
cnt -= (i - tree.query(v))
128+
if cnt < 0:
129+
return False
130+
tree.update(v + 1, 1)
131+
return True
69132
```
70133

71134
### **Java**
72135

73136
<!-- 这里可写当前语言的特殊实现逻辑 -->
74137

75138
```java
139+
class Solution {
140+
public boolean isIdealPermutation(int[] nums) {
141+
int mx = 0;
142+
for (int i = 2; i < nums.length; ++i) {
143+
mx = Math.max(mx, nums[i - 2]);
144+
if (mx > nums[i]) {
145+
return false;
146+
}
147+
}
148+
return true;
149+
}
150+
}
151+
```
152+
153+
```java
154+
class BinaryIndexedTree {
155+
private int n;
156+
private int[] c;
157+
158+
public BinaryIndexedTree(int n) {
159+
this.n = n;
160+
c = new int[n + 1];
161+
}
162+
163+
public void update(int x, int delta) {
164+
while (x <= n) {
165+
c[x] += delta;
166+
x += x & -x;
167+
}
168+
}
169+
170+
public int query(int x) {
171+
int s = 0;
172+
while (x > 0) {
173+
s += c[x];
174+
x -= x & -x;
175+
}
176+
return s;
177+
}
178+
}
179+
180+
class Solution {
181+
public boolean isIdealPermutation(int[] nums) {
182+
int n = nums.length;
183+
BinaryIndexedTree tree = new BinaryIndexedTree(n);
184+
int cnt = 0;
185+
for (int i = 0; i < n && cnt >= 0; ++i) {
186+
cnt += (i < n - 1 && nums[i] > nums[i + 1] ? 1 : 0);
187+
cnt -= (i - tree.query(nums[i]));
188+
tree.update(nums[i] + 1, 1);
189+
}
190+
return cnt == 0;
191+
}
192+
}
193+
```
194+
195+
### **C++**
196+
197+
```cpp
198+
class Solution {
199+
public:
200+
bool isIdealPermutation(vector<int>& nums) {
201+
int mx = 0;
202+
for (int i = 2; i < nums.size(); ++i) {
203+
mx = max(mx, nums[i - 2]);
204+
if (mx > nums[i]) return false;
205+
}
206+
return true;
207+
}
208+
};
209+
```
210+
211+
```cpp
212+
class BinaryIndexedTree {
213+
public:
214+
BinaryIndexedTree(int _n) : n(_n), c(_n + 1) {}
215+
216+
void update(int x, int delta) {
217+
while (x <= n) {
218+
c[x] += delta;
219+
x += x & -x;
220+
}
221+
}
222+
223+
int query(int x) {
224+
int s = 0;
225+
while (x) {
226+
s += c[x];
227+
x -= x & -x;
228+
}
229+
return s;
230+
}
231+
232+
private:
233+
int n;
234+
vector<int> c;
235+
};
236+
237+
class Solution {
238+
public:
239+
bool isIdealPermutation(vector<int>& nums) {
240+
int n = nums.size();
241+
BinaryIndexedTree tree(n);
242+
long cnt = 0;
243+
for (int i = 0; i < n && ~cnt; ++i) {
244+
cnt += (i < n - 1 && nums[i] > nums[i + 1]);
245+
cnt -= (i - tree.query(nums[i]));
246+
tree.update(nums[i] + 1, 1);
247+
}
248+
return cnt == 0;
249+
}
250+
};
251+
```
252+
253+
### **Go**
254+
255+
```go
256+
func isIdealPermutation(nums []int) bool {
257+
mx := 0
258+
for i := 2; i < len(nums); i++ {
259+
mx = max(mx, nums[i-2])
260+
if mx > nums[i] {
261+
return false
262+
}
263+
}
264+
return true
265+
}
266+
267+
func max(a, b int) int {
268+
if a > b {
269+
return a
270+
}
271+
return b
272+
}
273+
```
76274

275+
```go
276+
func isIdealPermutation(nums []int) bool {
277+
n := len(nums)
278+
tree := newBinaryIndexedTree(n)
279+
cnt := 0
280+
for i, v := range nums {
281+
if i < n-1 && v > nums[i+1] {
282+
cnt++
283+
}
284+
cnt -= (i - tree.query(v))
285+
if cnt < 0 {
286+
break
287+
}
288+
tree.update(v+1, 1)
289+
}
290+
return cnt == 0
291+
}
292+
293+
type BinaryIndexedTree struct {
294+
n int
295+
c []int
296+
}
297+
298+
func newBinaryIndexedTree(n int) BinaryIndexedTree {
299+
c := make([]int, n+1)
300+
return BinaryIndexedTree{n, c}
301+
}
302+
303+
func (this BinaryIndexedTree) update(x, delta int) {
304+
for x <= this.n {
305+
this.c[x] += delta
306+
x += x & -x
307+
}
308+
}
309+
310+
func (this BinaryIndexedTree) query(x int) int {
311+
s := 0
312+
for x > 0 {
313+
s += this.c[x]
314+
x -= x & -x
315+
}
316+
return s
317+
}
77318
```
78319

79320
### **...**

0 commit comments

Comments
 (0)