简介
题目链接 Leetcode 775. Global and Local Inversions
这题也不算是什么难题,只是想借由题目来讲一个思想,那就是:审题后要对题目所需进行拆解,以得出最优的方案,有时候“所见即所得”不一定是件好事。
题目中提到
Return
true
if and only if the number of global inversions is equal to the number of local inversions.
返回true
如果全局倒置的数量等于本地倒置的数量
如果按照题目要求的去做,很有可能出现以下过程:
- 计算全局倒置和本地倒置的数量
- 比较二者的总量,返回结果
但实际上,如果对题目有更深入的理解就会发现,全局倒置=本地倒置+非本地倒置
,一旦我们发现任何形式的非本地倒置(也就是说A[i] < A[j], j < i-1
),就可以直接得出False
的结论。因为无论如何,本地倒置的数量不可能超过全局倒置,一旦有任何非本地倒置,就说明,全局倒置不可能等于本地倒置。
注意:文章中一切注解皆为Python代码
理解题目
给定一个列表A
,是数字[0, 1, 2, ..., n-1]
的排列(Permutation
)。其中,本地倒置(local inversion
)是说:
A[i] < A[i-1]
而全局倒置是说任何形式的倒置,也就是说:
A[i] < A[j], j < i
因此,我们可以得出推论:
- 全局倒置包含本地倒置
- 全局倒置 = 本地倒置 + 非本地倒置
- 非本地倒置可以定义为:
A[i] < A[j], j < i-1
所以,与其去计算本地倒置和全局倒置再互相比较,为什么不去判断一下非本地倒置是不是0呢?
代码实现
a. 直观解法
计算本地倒置和全局倒置,再互相比较
class Solution:
def isIdealPermutation(self, A: List[int]) -> bool:
n = len(A)
g = local = 0
for i in range(1, n):
if A[i] < A[i-1]: # Calculate local inversion
local += 1
if A[i] < i: # Calculate global inversion
diff = i - A[i] # diff = actual_index - index_this_value_is_supposed_to_have_if_the_list_is_in_order
g += diff * (diff+1) // 2 # see explanation for this formula from `Explanation` section
return g == local
b. 深入理解思考后的解法
即上文有提到的:
判断一下非本地倒置是不是0
反向遍历,记录最小值,如果发现A[i] < A[j], j < i-1
就返回False
。因为有记录最小值,因此可以换一种写法,写作A[i] < A[j], j == i-2
。
class Solution:
def isIdealPermutation(self, A: List[int]) -> bool:
floor = N = len(A)
for i in range(N-1, 1, -1):
floor = min(floor, A[i])
if A[i-2] > floor: return False
return True
解题后的思考
尽管两种方法都是O(N)
的时间复杂度,O(1)
的空间复杂度,但是后者代码明显简介,而且最优时间可以做到O(1)
,综合来讲还是要优于第一种解法。
理解题目,并进行深层次的思考是如此重要,不仅能帮助解题,甚至还能优化时间复杂度,让解法更简便。