LeetCode -- 775. 全局倒置与局部倒置
首先c一手暴力法:利用树状数组,线段树,归并排序法查找逆序对,即全局倒置;在求出局部倒置,时间复杂度为nlogn
这里为了好写,采用树状数组方法进行逆序对求解
注:树状数组中下标不能有0,要对原数组进行+1修正
c ++ class Solution { int n; int tr[1000010]; int lowbit(int x) { return x & -x; } void add(int x) { for(int i = x; i <= n; i += lowbit(i)) { tr[i] ++ ; } } int query(int x) { int res = 0; for(int i = x; i > 0; i -= lowbit(i)) { res += tr[i]; } return res; } public: bool isIdealPermutation(vector<int>& nums) { n = nums.size(); add(nums[0] + 1); long long a = 0, b = 0; for(int i = 1; i < n; i ++ ) { a += i - query(nums[i] + 1); b += nums[i] < nums[i - 1] ? 1 : 0; add(nums[i] + 1); } return a == b; } };
java class Solution { int n; int[] tr; int lowbit(int x) { return x & -x; } void add(int x) { for(int i = x; i <= n; i += lowbit(i)) { tr[i] ++ ; } } int query(int x) { int res = 0; for(int i = x; i != 0; i -= lowbit(i)) { res += tr[i]; } return res; } public boolean isIdealPermutation(int[] nums) { n = nums.length; tr = new int[n + 10]; long a = 0, b = 0; add(nums[0] + 1); for(int i = 1; i < n; i ++ ) { a += i - query(nums[i] + 1); b += nums[i] < nums[i - 1] ? 1 : 0; add(nums[i] + 1); } return a == b; } }
python class TreeArray: def __init__(self, n): self.n = n self.tr = [0] * (n + 10) def lowbit(self, x): return x & -x def add(self, x): while x <= self.n: self.tr[x] += 1 x += self.lowbit(x) def query(self, x): res = 0 while x: res += self.tr[x] x -= self.lowbit(x) return res class Solution: def isIdealPermutation(self, nums: List[int]) -> bool: n = len(nums) tr = TreeArray(n) a = 0 b = 0 tr.add(nums[0] + 1) for i in range(1, n): a += i - tr.query(nums[i] + 1) if nums[i] < nums[i - 1]: b += 1 tr.add(nums[i] + 1) return a == b
golang type TreeArray struct { n int tr []int } func newTreeArray(n int) TreeArray { tr := make([]int, n + 10) return TreeArray{n, tr} } func lowbit(x int) int { return x & -x } func (this TreeArray) add(x int) { for x <= this.n { this.tr[x] ++ x += lowbit(x) } } func (this TreeArray) query(x int) int { res := 0 for x > 0 { res += this.tr[x] x -= lowbit(x) } return res } func isIdealPermutation(nums []int) bool { n := len(nums) tr := newTreeArray(n) cnt := 0 for i, v := range nums { if i < n - 1 && v > nums[i + 1] { cnt ++ } cnt -= i - tr.query(v + 1) tr.add(v + 1) } return cnt == 0 }
方法二:维护后缀最小值
局部置换一定是一个全局置换,因此要判断局部置换与全局置换是否相等,只要检查有没有非局部置换就可以了。
这里的非局部置换为 i < j - 1 && nums[i] > nums[j]
c ++ class Solution { public: bool isIdealPermutation(vector<int>& nums) { int n = nums.size(), mi = nums[n - 1]; for(int i = n - 3; i >= 0; i -- ) { if(nums[i] > mi) { return false; } mi = min(mi, nums[i + 1]); } return true; } };
js /** * @param {number[]} nums * @return {boolean} */ var isIdealPermutation = function(nums) { let n = nums.length, mi = nums[n - 1]; for(let i = n - 3; i >= 0; i -- ) { if(nums[i] > mi) { return false; } mi = Math.min(mi, nums[i + 1]); } return true; };