Open azl397985856 opened 3 years ago
在排序好的list里,找到比3倍小的数,然后结果加上比3倍大的数。并把该数插入排序好的list里
from sortedcontainers import SortedList
class Solution:
def solve(self, A):
sorted_list = SortedList()
result = 0
for n in A:
smallerNumbers = bisect.bisect_right(sorted_list, n * 3)
biggerNumbers = len(sorted_list) - smallerNumbers
result += biggerNumbers
sorted_list.add(n)
return result
时间复杂度 :O(Nlog N)
空间复杂度:O(N)
思路
遍历数组,用TreeMap存储已经遍历过的元素和元素出现的个数,用tailMap(K fromKey, boolean inclusive)寻找所有满足条件的值,将值的总和加到结果中。
代码
class Solution {
public int solve(int[] nums) {
if (nums.length == 0) return 0;
int res = 0;
TreeMap<Integer, Integer> map = new TreeMap<>();
map.put(nums[0], 1);
for (int i = 1; i < nums.length; i++) {
Map<Integer, Integer> candidates = map.tailMap(3 * nums[i], false);
for (Map.Entry<Integer, Integer> entry: candidates.entrySet()) {
res += entry.getValue();
}
map.put(nums[i], map.getOrDefault(nums[i], 0) + 1);
}
return res;
}
}
复杂度
时间复杂度:O(NlogN)
空间复杂度:O(N)
class Solution:
def solve(self, nums):
d = SortedList()
res = 0
for i in range(len(nums)):
idx = d.bisect_right(d, nums[i]*3)
res += len(nums) - idx
d.add(nums[i])
return res
https://binarysearch.com/problems/Triple-Inversion
binarySearch, mergeSort
import bisect
class Solution:
# 思路一
# 二分
def solve(self, nums):
ans = 0
tmp = []
for a in nums:
i = bisect.bisect_right(tmp, a * 3)
ans += len(tmp) - i
bisect.insort_right(tmp, a)
return ans
class Solution:
def solve(self, nums):
# time nlogn
# space n
# mergeSort
self.count = 0
def divide(low, high):
if (low < high):
mid = low + (high - low) // 2
divide(low, mid)
divide(mid + 1, high)
merge(low, mid, high)
def merge(low, mid, high):
tmp = []
i, j = low, mid + 1
while i <= mid and j <= high:
if (nums[i] <= nums[j]):
tmp.append(nums[i])
i += 1
elif (nums[i] > nums[j]):
tmp.append(nums[j])
j += 1
# 归并排序保证了一定有ti < tj
# eg:
# ti tj
# [1,7] [2,5]
# 1和2对比 ti+=1 (当1<3*2说明得在1当中继续找更得数看看会不会大于3*2,所以ti往后移)
# 7和2对比 tj+=1 (7>3*2 计数器+1 然后tj往后移看是否还存在7>3*nums[tj]的情况)
# 7和5对比 ti+=1 (7<3*5 7为左边数组最大的元素了,如果它都不大于3*nums[tj],就不可能再有更大的了,所以退出循环,计数完成)
ti, tj = low, mid + 1
while ti <= mid and tj <= high:
if (nums[ti] <= (3 * nums[tj])):
ti += 1
elif (nums[ti] > (3 * nums[tj])):
self.count += mid - ti + 1
tj += 1
while (i <= mid):
tmp.append(nums[i])
i += 1
while (j <= high):
tmp.append(nums[j])
j += 1
for i in range(0, len(tmp)):
nums[low] = tmp[i]
low += 1
divide(0, len(nums) - 1)
return self.count
1.https://leetcode-cn.com/problems/shu-zu-zhong-de-ni-xu-dui-lcof/
思路: 归并排序的优化,同时在排序完成后cnt值累加,最终输出cnt。 将大数组两两拆分,并计算满足条件的值。 最后获得所需答案
func reversePairs(nums []int) int {
n := len(nums)
if n <= 1 {
return 0
}
n1 := append([]int(nil), nums[:n/2]...)
n2 := append([]int(nil), nums[n/2:]...)
cnt := reversePairs(n1) + reversePairs(n2)
j := 0
for _, v := range n1 {
for j < len(n2) && v > 2*n2[j] {
j++
}
cnt += j
}
p1, p2 := 0, 0
for i := range nums {
if p1 < len(n1) && (p2 == len(n2) || n1[p1] <= n2[p2]) {
nums[i] = n1[p1]
p1++
} else {
nums[i] = n2[p2]
p2++
}
}
return cnt
}
时间复杂度:O(nlogn) 空间复杂度:O(n)
from sortedcontainers import SortedList
class Solution:
def solve(self, A):
d = SortedList()
ans = 0
for a in A:
i = d.bisect_right(a * 3)
ans += len(d) - i
d.add(a)
return ans
时间复杂度:O(logn) 空间复杂度:O(n)
class Solution:
def solve(self, A):
ans = 0
for i in range(len(A)):
for j in range(i+1,len(A)):
if A[i] > A[j] * 3: ans += 1
return ans
Can't AC... I am having issue with the below test case
nums = [3, 4, 3, 1, 0] Your result 7 Expected 5
Base on the constraint, it should be 7 rather than 5
Brute Force: Iterate throught the array. For each index i, compare with j (j > i) and count all the j where nums[i] > nums[j] * 3. The time complexity will be O(n^2) which is not good enough.
More stunning solution: use Merge Sort.
The brute force does not work out becase we have to compare each and every pairs, but what if we have the array sorted, then if we have number j, and we found a i that satisfy the constraint, we know that for every k (k > i), it would satisfy the constraint as well. However, if we sort the whole array, we will loose the information of th indices..., what if we could put the array in two parts? left and right, we know that the index in the left will always smaller than the index in the right, and since left part is sorted, once we found a index that satisfy the constraint, we know that all the remaining indices in the left also satisfy the conditon. To do this, we can use merge sort.
int cnt = 0;
void merge(vector<int>& nums, int s, int m, int e) {
vector<int> l;
vector<int> r;
for (int i = s; i <= m; i++)
l.push_back(nums[i]);
for (int i = m + 1; i <= e; i++)
r.push_back(nums[i]);
l.push_back(INT_MAX);
r.push_back(INT_MAX);
int i = 0, j = 0, k = s;
while (i < l.size() && j < r.size() && k <= e) {
if (l[i] <= r[j])
nums[k++] = l[i++];
else {
if (l[i] > r[j] * 3) {
cnt += l.size() - i;
}
nums[k++] = r[j++];
}
}
}
void mergeSort(vector<int>& nums, int s, int e) {
if (s >= e)
return;
int mid = s + (e - s) / 2;
mergeSort(nums, s, mid);
mergeSort(nums, mid + 1, e);
merge(nums, s, mid, e);
}
int solve(vector<int>& nums) {
mergeSort(nums, 0, nums.size() - 1);
return cnt;
}
O(nlogn) for merge sort
O(n) used to store the intermidate results for merge.
class Solution:
def maxChunksToSorted(self, nums: List[int]) -> int:
st = []
for n in nums:
if len(st)==0 or st[-1]<=n:
st.append(n)
else:
ma = st[-1]
while st and st[-1]>n:
ma = max(ma,st.pop())
st.append(ma)
return len(st)
JS
var reversePairs = function(nums) {
let res = 0;
for (let i = 0; i < nums.length; i++){
for (j = i+1; j < nums.length; j++){
if(nums[i] > nums[j] * 3){
res++;
}
}
}
return res;
};
代码
class Solution:
def solve(self, nums):
d = SortedList()
res = 0
for i in range(len(nums)):
tidx = d.bisect_right(d, nums[i]*3)
res += len(nums) - tidx
d.add(nums[i])
return res
复杂度
Time Complexity: O(nlogn)
Space Complexity: O(n)
class Solution {
public:
int countPrimeSetBits(int l, int r) {
set<int> primes = { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29 };
int cnt = 0;
for (int i = l; i <= r; i++) {
int bits = 0;
for (int n = i; n; n >>= 1)
bits += n & 1;
cnt += primes.count(bits);
}
return cnt;
}
};
int solve(vector<int>& nums) {
multiset<int> record;
int ret =0;
for(int i=0; i< nums.size(); i++)
{
multiset<int>::iterator it = record.upper_bound(3* nums[i]);
if(it != record.end())
{
ret+= distance(it, record.end());
}
record.insert(nums[i]);
}
return ret;
}
```c++
```c++
int bindarySearch(vector<int>& nums, int left, int right, int val)
{
while(left <=right)
{
int middle = left + (right-left)/2;
if(nums[middle]<=val)
{
left = middle+1;
}
else
{
right = middle-1;
}
}
return left;
}
int mergeTwoVec(vector<int>& nums, int left, int middle, int right)
{
vector<int> tmp(right - left+1);
int count =0;
int left1 = left;
int left2 = middle+1;
int right1 = middle;
int right2 = right;
int sum =0;
//cout << "left: " << left << "middle:" << middle << "right:" << right << "\n";
while(left1 <=right1 && left2 <=right2)
{
if(nums[left1]<= nums[left2])
{
tmp[count] = nums[left1];
count++;
left1++;
}
else
{
//
int t = bindarySearch(nums, left1, right1, 3*nums[left2]);
sum +=(right1 - t+1);
//cout << "sum:" << sum << "\n";
tmp[count] = nums[left2];
count++;
left2++;
}
}
while(left1<=right1)
{
tmp[count] = nums[left1];
left1++;
count++;
}
while(left2<=right2)
{
tmp[count] = nums[left2];
left2++;
count++;
}
for(int i=left; i <= right; i++)
{
nums[i] = tmp[i-left];
}
return sum;
}
void mergeSort(vector<int>& nums, int left, int right, int& count)
{
if(left>=right)
return;
int middle = left + (right - left)/2;
mergeSort(nums, left, middle, count);
mergeSort(nums, middle+1, right, count);
count += mergeTwoVec(nums, left, middle, right);
}
int solve(vector<int>& nums) {
int count =0;
mergeSort(nums, 0, nums.size()-1, count);
return count;
}
class Solution {
public int reversePairs(int[] nums) {
if (nums.length < 2) return 0;
return mergeSort(0, nums.length - 1, nums);
}
public int mergeSort(int left, int right, int[] nums) {
if (left >= right) return 0;
int mid = left + (right - left) / 2;
int l = mergeSort(left, mid, nums);
int r = mergeSort(mid + 1, right, nums);
return l + r + sort(left, right, mid, nums);
}
public int sort(int l, int r, int m, int[] nums) {
int[] temp = new int[r - l + 1];
int flag = 0;
int res = 0;
// 每一次堆排之前,左右分割出来的i一定小于j,此时只需要判断第二条件是否满足即可统计该次排序得出的翻转对数量
int i = l;
int j = m + 1;
// 计算翻转对
while (i <= m && j <= r) {
if (nums[i] > (long) nums[j] * 3) {
// 统计出i一共可以满足几个翻转对
res += m - i + 1;
j ++;
} else {
i ++;
}
}
i = l;
j = m + 1;
// 进行排序
while (i <= m && j <= r){
if (nums[i] < nums[j]) {
temp[flag ++] = nums[i ++];
} else {
temp[flag ++] = nums[j ++];
}
}
while (i <= m){
temp[flag ++] = nums[i ++];
}
while (j <= r){
temp[flag ++] = nums[j ++];
}
for (int k = 0; k < temp.length; k ++){
nums[l + k] = temp[k];
}
return res;
}
}
Problem Link
Ideas
nums[i] > nums[j] * 3
, instead of focusing on i. We should focus on j, loop through j. Then we could record the i which is essentially the previous elements of j. This idea is important.bisect.bisect_right(d, a * 3)
to find the index which satisfies the conditions. And use sortedcontainers.SortedList
to store the elements. Each time the insertion is O(logN).ti, tj = start, mid + 1
while ti <= mid and tj <= end:
if nums[ti] <= 3 * nums[tj]:
ti += 1
else:
self.cnt += mid - ti + 1
tj += 1
Complexity: hash table and bucket
Code
#TLE!
class Solution:
def solve(self, nums):
res = 0
for i in range(len(nums)):
for j in range(i, len(nums)):
if nums[i] > nums[j] * 3:
res += 1
return res
#binary search
class Solution:
def solve(self, A):
d = []
ans = 0
for a in A:
i = bisect.bisect_right(d, a * 3)
ans += len(d) - i
bisect.insort(d, a)
#binary search! use balanced binary tree
from sortedcontainers import SortedList
class Solution:
def solve(self, A):
d = SortedList()
ans = 0
for a in A:
i = d.bisect_right(a * 3)
ans += len(d) - i
d.add(a)
#print (d, a, i)
return ans
#divide and conquer, merge sort idea.
class Solution:
def solve(self, nums) -> int:
self.cnt = 0
def merge(nums, start, mid, end, temp):
i, j = start, mid + 1
while i <= mid and j <= end:
if nums[i] <= nums[j]:
temp.append(nums[i])
i += 1
else:
temp.append(nums[j])
j += 1
# 防住
# 这里代码开始
ti, tj = start, mid + 1
while ti <= mid and tj <= end:
if nums[ti] <= 3 * nums[tj]:
ti += 1
else:
self.cnt += mid - ti + 1
tj += 1
# 这里代码结束
while i <= mid:
temp.append(nums[i])
i += 1
while j <= end:
temp.append(nums[j])
j += 1
for i in range(len(temp)):
nums[start + i] = temp[i]
temp.clear()
def mergeSort(nums, start, end, temp):
if start >= end: return
mid = (start + end) >> 1
mergeSort(nums, start, mid, temp)
mergeSort(nums, mid + 1, end, temp)
merge(nums, start, mid, end, temp)
mergeSort(nums, 0, len(nums) - 1, [])
return self.cnt
二分法
构造有序数列,使用二分法找到插入点,并且将数插入数组中,使得插入的数组仍然有序。
def solve(self, nums):
d = SortedList()
ans = 0
for num in nums:
i = d.bisect_right(num * 3)
ans += len(d) - i
d.add(num)
return ans
Time Complexity: O(nlogn) Space Complexity: O(n)
let ans=0;
function mergeSort(arr){
if(arr.length===1)return arr;
let left=0,right=arr.length;
let mid=left+Math.floor((right-left)/2)
let leftArr=arr.slice(left,mid);
let rightArr=arr.slice(mid,right);
return merge(mergeSort(leftArr),mergeSort(rightArr))
}
function merge(arr1,arr2){ let temp=[]; let i=0,j=0; while(i<arr1.length&&j<arr2.length){ if(arr1[i]<arr2[j]){ temp.push(arr1[i]); i++ }else{ temp.push(arr2[j]) if(arr1[i]>arr2[j]*3){ ans++ } j++ } }
while(i<arr1.length){ temp.push(arr1[i]); i++ } while(j<arr2.length){ temp.push(arr2[j]); j++
} return temp }
class Solution {
// [2147483647,2147483647,2147483647,2147483647,2147483647,2147483647]
// 0
// Time: O(n^2)
// Space: O(1)
public int reversePairs1(int[] nums) {
int count = 0;
for (int j = 0; j < nums.length; j++) {
for (int i = 0; i < j; i++) {
if (nums[i] - nums[j] > nums[j]) {
count++;
}
}
}
return count;
}
// optimized
/*
Plan:
use a binary search tree to track (count of values <= current val, left child, right child)
search long type (2*target + 1), to avoid overflow
*/
// The worst time can be O(n^2), it is better to use balanced tree (AVL, or red-black)
// on average O(nlogn)
class Node {
long val;
int count;
Node left;
Node right;
Node(long val, Node left, Node right) {
this.val = val;
this.count = 1;
this.left = left;
this.right = right;
}
}
// return the count of numbers <
private int search(Node root, long target) {
if (root == null) return 0;
if (root.val > target) {
return root.count + search(root.left, target);
} else if (root.val < target) {
return search(root.right, target);
} else {
return root.count;
}
}
private Node insert(Node root, int target) {
if (root == null) {
return new Node(target, null, null);
} else if (root.val == target) {
root.count++;
} else if (root.val > target) {
root.left = insert(root.left, target);
} else {
root.count += 1;
root.right = insert(root.right, target);
}
return root;
}
public int reversePairs(int[] nums) {
int numOfPairs = 0;
Node root = null;
for (int num : nums) {
numOfPairs += search(root, (long) (num * 2 + 1));
root = insert(root, num);
}
return numOfPairs;
}
}
思路: 归并法
复杂度:
代码:
class Solution {
public:
int reversePairs(vector<int>& nums) {
return mergeSort(nums, 0, nums.size() - 1);
}
int mergeSort(vector<int>& nums, int left, int right) {
if (left >= right) return 0;
int mid = left + (right - left) / 2;
int res = mergeSort(nums, left, mid) + mergeSort(nums, mid + 1, right);
for (int i = left, j = mid + 1; i <= mid; ++i) {
while (j <= right && nums[i] / 2.0 > nums[j]) ++j;
res += j - (mid + 1);
}
sort(nums.begin() + left, nums.begin() + right + 1);
return res;
}
};
class Solution:
def countPrimeSetBits(self, left: int, right: int) -> int:
result=0
for num in range(left,right+1):
if self.to_binary_bit(num):
result+=1
return result
def to_binary_bit(self,num):
prime=set([2,3,5,7,11,13,17,19,23])
count=0
while num !=0:
if num%2 ==1:
count+=1
num=num//2
if count in prime:
return True
else:
return False
Time: O(nlogn)
Space: O(1)
Explanation
Python
class Solution:
def solve(self, nums):
def mergeSort(start, end, temp):
if start < end:
mid = start + (end-start)//2
mergeSort(start, mid, temp)
mergeSort(mid+1, end, temp)
merge(start, mid, end, temp)
def merge(start, mid, end, temp):
nonlocal count
i, j = start, mid+1
while i <= mid and j <= end:
if nums[i] <= nums[j]:
temp.append(nums[i])
i += 1
else:
temp.append(nums[j])
j += 1
ti, tj = start, mid+1
while ti <= mid and tj <= end:
if nums[ti] <= nums[tj] * 3:
ti += 1
else:
count += mid - ti + 1
tj += 1
while i <= mid:
temp.append(nums[i])
i += 1
while j <= end:
temp.append(nums[j])
j += 1
for i in range(len(temp)):
nums[start+i] = temp[i]
temp.clear()
count = 0
mergeSort(0, len(nums)-1, [])
return count
Complexity:
O(NlogN)
O(N)
https://binarysearch.com/problems/Triple-Inversion
思路:讲义中有讲到这题,观察需要自己构造有序序列。反向思考,对于nums中的每一项num,找前面出现过的大于num * 3的数
import bisect
def solve(self,A):
d = SortedList()
ans = 0
for a in A:
i = bisect.bisect_right(d, a * 3) #有序序列的查找,查找a*3在有序序列中的位置
ans += len(d) - i #在i位置之后的数满足题目要求
bisect.insort(d, a) #有序序列的插入
return ans
# 1141 milliseconds #
class Solution:
def solve(self, A):
d = SortedList()
ans = 0
for a in A:
i = d.bisect_right(a * 3)
ans += len(d) - i
d.add(a)
return ans
#502 milliseconds#
复杂度:
时间复杂度:O(nlog n) 二分中找到插入点的时间复杂度为O(logn),但由于数组项后移动的时间复杂度为O(n),可以采用平衡二叉树来使插入时间减少稳定在O(logn) Python 可使用 SortedList 来实现, Java 可用 TreeMap 代替
空间复杂度:O(n)
类似于 315. Count of Smaller Numbers After Self 求有条件的逆序对。有两种解法,
class Solution {
public int main(int[] nums) {
List<Integer> list = new ArrayList<>();
int ret= 0;
for (int n : nums) {
int idnex = search(list, n * 3);
ret += list.size() - idnex;
list.add(search(list, n), n);
}
return ret;
}
public int search(List<Integer> list, int n) {
int start = 0, end = list.size() - 1;
while (start <= end) {
int mid = (start + end) >>> 1;
if (list.get(mid) <= n) {
start = mid + 1;
} else {
end = mid - 1;
}
}
return start;
}
}
时间:O(nlogn)
空间:O(n)
类似于 315. Count of Smaller Numbers After Self 求有条件的逆序对。两种解法: merge sort,在merge的过程中可以求得满足条件的逆序对。 二分 + 插入排序。
class Solution {
public int main(int[] nums) {
List<Integer> list = new ArrayList<>();
int ret= 0;
for (int n : nums) {
int idnex = search(list, n * 3);
ret += list.size() - idnex;
list.add(search(list, n), n);
}
return ret;
}
public int search(List<Integer> list, int n) {
int start = 0, end = list.size() - 1;
while (start <= end) {
int mid = (start + end) >>> 1;
if (list.get(mid) <= n) {
start = mid + 1;
} else {
end = mid - 1;
}
}
return start;
}
}
思路:二分
class Solution {
public int solve(int[] nums) {
int res = 0;
List<Integer> sortedNums = new ArrayList<>();
for(int i = 0; i < nums.length; i++){
int leftBorder = findLeftBorder(sortedNums, nums[i] * 3);
res += i - leftBorder;
int insertIndex = findLeftBorder(sortedNums, nums[i]);
sortedNums.add(insertIndex, nums[i]);
}
return res;
}
private int findLeftBorder(List<Integer> sortedNums, int target){
int left = 0, right = sortedNums.size() - 1;
while(left <= right){
int mid = (left + right) / 2;
if(sortedNums.get(mid) <= target){
left = mid + 1;
}else{
right = mid - 1;
}
}
return left;
}
}
时间复杂度:O(NlogN) 空间复杂度:O(N)
class Solution {
solve(nums) {
const sorted = [];
let count = 0
for (const num of nums) {
const idx = this.findFirstLarger(sorted, num * 3);
count += sorted.length - idx;
sorted.splice(this.findFirstLarger(sorted, num), 0, num);
}
return count;
}
findFirstLarger(arr, target) {
let start = 0;
let end = arr.length;
while (start < end) {
const mid = start + ~~((end - start) / 2);
if (arr[mid] > target) {
end = mid;
} else {
start = mid + 1;
}
}
return start;
}
}
对于nums中的每一项num,找前面出现过的大于num * 3的数
import bisect
def solve(self,nums):
d = SortedList()
ans = 0
for a in nums:
i = bisect.bisect_right(d, a * 3) #查找a*3在有序序列中的位置
ans += len(d) - i
bisect.insort(d, a) #在有序序列中的插入
return ans
title: "Day 39 762.Number Stream to Intervals" date: 2021-10-18T16:30:01+08:00 tags: ["Leetcode", "c++", "Binary Search"] categories: ["91-day-algorithm"] draft: true
Given a list of integers nums, return the number of pairs i < j such that nums[i] > nums[j] * 3.
Constraints
n ≤ 100,000 where n is the length of nums
Example 1
Input
nums = [7, 1, 2]
Output
2
Explanation
We have the pairs (7, 1) and (7, 2)
- 1、构造逆序对,然后返回逆序对的数量,使用归并排序比二分法更加合适,找出每个子区间中一项大于当前num * 3的值
void merge(vector<int> &nums, int i, int mid, int j)
{
vector<int> ans(j - i + 1);
int l = i, r = mid + 1;
int cnt = 0;
while(l <= mid && r <= j)
{
if(nums[l] <= nums[r])
{
ans[cnt] = nums[l];
l++;
}
else
{
ans[cnt] = nums[r];
r++;
}
cnt++;
}
while(l <= mid) ans[cnt++] = nums[l++];
while(r <= j) ans[cnt++] = nums[r++];
cnt = 0;
while(i <= j) nums[i++] = ans[cnt++];
}
}
int mergeSort(vector<int> &nums, int l, int r)
{
if(r <= l) return 0;
int ans = 0;
int mid = (l + r) / 2;
ans += mergeSort(nums, l, mid);
ans += mergeSort(nums, mid + 1, r);
int p = l;
int q = mid + 1;
while(p <= mid && q <= r)
{
if(nums[p] > nums[q] * 3)
{
ans += (mid - p + 1);
q++;
}
else p++;
}
merge(nums, l, mid, r);
return ans;
}
int solve(vector<int> &nums)
{
int ans = mergeSort(nums, 0, nums.size() - 1);
return ans;
}
时间复杂度:O(nlogn)
空间复杂度:O(n)
利用merge sort计算逆序数
class Solution {
public:
int reversePairs(vector<int>& nums) {
if (nums.size() == 0) return 0;
// merge sort on the whole vector
return mergeSort(nums, 0, nums.size() - 1);
}
int mergeSort(vector<int>& nums, int l, int r) {
if (l == r) return 0;
int mid = l + (r - l) / 2;
// number of ans from left half and right half
int res = mergeSort(nums, l, mid) + mergeSort(nums, mid + 1, r);
// split in half
int i = l;
int j = mid + 1;
while (i <= mid) {
// j is not out-of-bound and meets the requirement
while (j <= r && (long long) nums[i] > (long long) nums[j] * 3) j++;
// add the number of values that meet the requirement and after it
res += j - mid - 1;
++i;
}
sort(nums.begin() + l, nums.begin() + r + 1);
return res;
}
};
class Solution:
def solve(self, nums):
self.cnt = 0
def merge(nums, left, mid, right, temp):
i, j = left, mid + 1
while i <= mid and j <= right:
if nums[i] <= nums[j]:
temp.append(nums[i])
i += 1
else:
temp.append(nums[j])
j += 1
while i <= mid:
temp.append(nums[i])
i += 1
while j <= right:
temp.append(nums[j])
j += 1
ti, tj = left, mid + 1
while ti <= mid and tj <= right:
if nums[ti] <= 3 * nums[tj]:
ti += 1
else:
self.cnt += mid - ti + 1
tj += 1
for i in range(len(temp)):
nums[left + i] = temp[i]
temp.clear()
def merge_sort(nums, left, right, temp):
if left >= right:
return
mid = (left + right) // 2
merge_sort(nums, left, mid, temp)
merge_sort(nums, mid + 1, right, temp)
merge(nums, left, mid, right, temp)
merge_sort(nums, 0, len(nums) - 1, [])
return self.cnt
二分,抄下别人的
int solve(vector<int>& nums) {
map<int, int> dict;
int res = 0;
for (auto& num : nums)
{
auto it = dict.upper_bound(3*num); // 找到第1个满足要求的数key1, 那哈希表中排在key1后面的数(比key1更大)也全满足 > 3*num
if (it != dict.end())
{
for (auto it1 = it; it1 != dict.end(); it1++)
res += it1->second;
}
if (dict.count(num) > 0)
dict[num]++;
else dict[num] = 1;
}
return res;
}
复杂度分析
自己构造有序数组,遍历原数组找到在num前且大于num*3的数的个数,并将num加入有序数组。
class Solution:
def solve(self, nums):
arr = SortedList()
ans = 0
for n in nums:
i = arr.bisect_right(n)
ans += len(arr) - i
arr.add(n)
return ans
复杂度
Go Code:
func reversePairs(nums []int) int {
var res int
mergeSort(nums, 0, len(nums)-1, &res)
return res
}
func mergeSort(nums []int, left, right int, res *int) {
if left >= right {
return
}
mid := (right-left)/2 + left
mergeSort(nums, left, mid, res)
mergeSort(nums, mid+1, right, res)
merge(nums, left, mid, right, res)
}
func merge(nums []int, left, mid, right int, res *int) {
newNums := make([]int, right-left+1)
index, i, j := 0, left, mid+1
for i <= mid && j <= right {
if nums[i] > 2*nums[j] {
*res += mid - i + 1
j++
} else {
i++
}
}
i, j = left, mid+1
for i <= mid && j <= right {
if nums[i] < nums[j] {
newNums[index] = nums[i]
i++
} else {
newNums[index] = nums[j]
j++
}
index++
}
// 多余的数据尾部插入
for i <= mid {
newNums[index] = nums[i]
i++
index++
}
for j <= right {
newNums[index] = nums[j]
j++
index++
}
for _, num := range newNums {
nums[left] = num
left++
}
}
复杂度分析
令 n 为数组长度。
二分法
class Solution:
def solve(self, A):
d = []
ans = 0
for a in A:
i = bisect.bisect_right(d, a * 3)
ans += len(d) - i
bisect.insort(d, a)
时间复杂度:O(logn)
空间复杂度:O(n)
借助归并排序,在归并排序的过程中,利用↓的特点进行统计。
归并排序的特点:合并之前,左分支和右分支就已经是有序的了。
// 伪代码
mergeSort(...) {
mergeSort(leftPart);
mergeSort(rightPart);
// 递归执行到这里,leftPart和rightPart都已经sorted
countPairs(...);
merge(leftPart, rightPart);
}
class Solution {
public int reversePairs(int[] nums) {
return mergeSort(nums, 0, nums.length - 1);
}
private int mergeSort(int[] nums, int left, int right){
if (left >= right) return 0;
int middle = left + (right - left) / 2;
int res = mergeSort(nums, left, middle) + mergeSort(nums, middle + 1, right);
for(int leftIndex = left, rightIndex = middle + 1; leftIndex <= middle; leftIndex++) {
while (rightIndex <= right && nums[leftIndex] / 3.0 > nums[rightIndex]) rightIndex++;
res += rightIndex - (middle + 1);
}
// 合并左右分支,相当于进行了依次排序
Arrays.sort(nums, left, right + 1);
return res;
}
}
实现一个二分查找法: 找到保持有序情况下 最右的插入位置
实现逻辑为, 建立一个列表, 成为我们的查找区间, 然后便利输入的列表.
查找 3遍历值num
, 找到会是插入下标, 此时满足条件 i<j 且 nums[i]>nums[j]3
增加count: len(temp) - 刚找到的下标
最后找到插入 num
的位置,并插入
class Solution:
def solve(self, nums):
def binarySearch(temp, target):
left = 0
right = len(temp)
while left<right:
mid = (right+left)//2
if temp[mid]<= target:
left = mid+1
else:
right = mid
return left
count = 0
temp = []
for num in nums:
smaller_count = binarySearch(temp,num*3)
print(temp,smaller_count)
count += len(temp) - smaller_count
idx = binarySearch(temp,num)
temp.insert(idx,num)
return count
class Solution: def solve(self, nums): d = [] ans = 0
for a in A:
i = bisect.bisect_right(d, a * 3)
ans += len(d) - i
bisect.insort(d, a)
# logn n
class Solution { public int reversePairs(int[] nums) { return mergeSort(nums, 0, nums.length - 1); } private int mergeSort(int[] nums, int left, int right){ if (left >= right) return 0; int middle = left + (right - left) / 2; int res = mergeSort(nums, left, middle) + mergeSort(nums, middle + 1, right); for(int leftIndex = left, rightIndex = middle + 1; leftIndex <= middle; leftIndex++) { while (rightIndex <= right && nums[leftIndex] / 3.0 > nums[rightIndex]) rightIndex++; res += rightIndex - (middle + 1); } // 合并左右分支,相当于进行了依次排序 Arrays.sort(nums, left, right + 1); return res; } }
二分法
Python Code
class Solution:
def solve(self, nums) -> int:
self.cnt = 0
def merge(nums, start, mid, end, temp):
i, j = start, mid + 1
while i <= mid and j <= end:
if nums[i] <= nums[j]:
temp.append(nums[i])
i += 1
else:
temp.append(nums[j])
j += 1
# 防住
# 这里代码开始
ti, tj = start, mid + 1
while ti <= mid and tj <= end:
if nums[ti] <= 3 * nums[tj]:
ti += 1
else:
self.cnt += mid - ti + 1
tj += 1
# 这里代码结束
while i <= mid:
temp.append(nums[i])
i += 1
while j <= end:
temp.append(nums[j])
j += 1
for i in range(len(temp)):
nums[start + i] = temp[i]
temp.clear()
def mergeSort(nums, start, end, temp):
if start >= end: return
mid = (start + end) >> 1
mergeSort(nums, start, mid, temp)
mergeSort(nums, mid + 1, end, temp)
merge(nums, start, mid, end, temp)
mergeSort(nums, 0, len(nums) - 1, [])
return self.cnt
复杂度
class Solution {
public int lowbit(int x){
return x&-x;
}
public boolean judget(int n ){
if(n<2){
return false;
}
for(int i =2;i<=n/i;i++){
if(n%i==0){
return false;
}
}
return true;
}
public int countPrimeSetBits(int left, int right) {
int ans = 0;
for(int i = left;i<=right;i++){
int tem = 0;
int x = i;
while(x!=0){
x-=lowbit(x);
tem++;
}
if(judget(tem)){
ans++;
}
}
return ans;
}
}
构造有序序列.
参考题解
在把一个element插入sorted array时, 我们想得到它的位置. 用STLset
的问题在于, 为了得到位置, 还得再subtract iterators and this operation is O(n). 可以自定义一个indexed_set
, 只有O(logn).
order_of_key()
to determine how many elements to the right satisfy the requirement in the problem statement. indexed_set
, we multiply it's value by 3. Since elements in the array may have the same value, we insert a pair instead(with the second element of the pair being the position of the element) in order to avoid the removal of duplicates since an indexed_set
acts like a set (not a multiset).using namespace __gnu_pbds;
typedef tree<pair<int, int>, null_type, less<pair<int, int>>, rb_tree_tag,
tree_order_statistics_node_update>
indexed_set;
int solve(vector<int>& nums) {
indexed_set sett;
int ans = 0;
for (int i = nums.size() - 1; i >= 0; i--) {
ans += sett.order_of_key(make_pair(nums[i], i));
sett.insert(make_pair(3 * nums[i], i));
}
return ans;
}
class Solution {
public int reversePairs(int[] nums) {
return mergeSort(nums, 0, nums.length - 1);
}
private int mergeSort(int[] nums, int left, int right){
if (left >= right) return 0;
int middle = left + (right - left) / 2;
int res = mergeSort(nums, left, middle) + mergeSort(nums, middle + 1, right);
for(int leftIndex = left, rightIndex = middle + 1; leftIndex <= middle; leftIndex++) {
while (rightIndex <= right && nums[leftIndex] / 3.0 > nums[rightIndex]) rightIndex++;
res += rightIndex - (middle + 1);
}
// 合并左右分支,相当于进行了依次排序
Arrays.sort(nums, left, right + 1);
return res;
}
}
Java Code:
class Solution {
public int main(int[] nums) {
List<Integer> list = new ArrayList<>();
int ret= 0;
for (int n : nums) {
int idnex = search(list, n * 3);
ret += list.size() - idnex;
list.add(search(list, n), n);
}
return ret;
}
public int search(List<Integer> list, int n) {
int start = 0, end = list.size() - 1;
while (start <= end) {
int mid = (start + end) >>> 1;
if (list.get(mid) <= n) {
start = mid + 1;
} else {
end = mid - 1;
}
}
return start;
}
}
复杂度分析
令 n 为数组长度。
class Solution {
private int count = 0;
public int reversePairs(int[] nums) {
if (nums == null || nums.length < 2) {
return 0;
}
count = 0;
mergeSort(nums, 0, nums.length - 1);
return count;
}
private void mergeSort(int[] nums, int start, int end) {
// 一个时不用划分
if (start == end) {
return;
}
int mid = start + (end - start) / 2;
mergeSort(nums, start, mid);
mergeSort(nums, mid + 1, end);
// 开始合并
int i = start;
int j = mid + 1;
// 开始统计翻转对
while (i <= mid && j <= end) {
if ((long) nums[i] > 2 * (long) nums[j]) {
count += mid - i + 1;
j++;
} else {
i++;
}
}
// 统计完之后合并
int[] tempArr = new int[end - start + 1];
i = start;
j = mid + 1;
int index = 0;
while (i <= mid && j <= end) {
tempArr[index++] = nums[i] < nums[j] ? nums[i++] : nums[j++];
}
while (i <= mid) {
tempArr[index++] = nums[i++];
}
while (j <= end) {
tempArr[index++] = nums[j++];
}
for (i = 0, j = start; j <= end; i++, j++) {
nums[j] = tempArr[i];
}
}
}
先打个卡
int solve(vector<int>& nums) {
map<int, int> dict;
int res = 0;
for (auto& num : nums)
{
auto it = dict.upper_bound(3*num); // 找到第1个满足要求的数key1, 那哈希表中排在key1后面的数(比key1更大)也全满足 > 3*num
if (it != dict.end())
{
for (auto it1 = it; it1 != dict.end(); it1++)
res += it1->second;
}
if (dict.count(num) > 0)
dict[num]++;
else dict[num] = 1;
}
return res;
}
class Solution {
public int solve(int[] nums) {
if (nums.length == 0) return 0;
int res = 0;
TreeMap<Integer, Integer> map = new TreeMap<>();
map.put(nums[0], 1);
for (int i = 1; i < nums.length; i++) {
Map<Integer, Integer> candidates = map.tailMap(3 * nums[i], false);
for (Map.Entry<Integer, Integer> entry: candidates.entrySet()) {
res += entry.getValue();
}
map.put(nums[i], map.getOrDefault(nums[i], 0) + 1);
}
return res;
}
}
二分法
class Solution:
def solve(self, nums) -> int:
self.cnt = 0
def merge(nums, start, mid, end, temp):
i, j = start, mid + 1
while i <= mid and j <= end:
if nums[i] <= nums[j]:
temp.append(nums[i])
i += 1
else:
temp.append(nums[j])
j += 1
# 防住
# 这里代码开始
ti, tj = start, mid + 1
while ti <= mid and tj <= end:
if nums[ti] <= 3 * nums[tj]:
ti += 1
else:
self.cnt += mid - ti + 1
tj += 1
# 这里代码结束
while i <= mid:
temp.append(nums[i])
i += 1
while j <= end:
temp.append(nums[j])
j += 1
for i in range(len(temp)):
nums[start + i] = temp[i]
temp.clear()
def mergeSort(nums, start, end, temp):
if start >= end: return
mid = (start + end) >> 1
mergeSort(nums, start, mid, temp)
mergeSort(nums, mid + 1, end, temp)
merge(nums, start, mid, end, temp)
mergeSort(nums, 0, len(nums) - 1, [])
return self.cnt
归并排序。
class Solution:
def solve(self, nums):
def merge_sort(l, r):
# 终止条件
if l >= r:
return 0
# 递归划分
m = ((r - l) >> 1) + l
res = merge_sort(l, m) + merge_sort(m + 1, r)
# 合并阶段
i, j = l, m + 1
t = l
tmp[l:r+1] = nums[l:r+1]
for k in range(l, r + 1):
if i >= m + 1:
nums[k] = tmp[j]
j += 1
elif j >= r + 1 or tmp[i] <= tmp[j]:
nums[k] = tmp[i]
i += 1
else:
# 开始,去除不符合条件的 tmp[t] <= 3 * tmp[j]
while t <= m and tmp[t] <= 3 * tmp[j]:
t += 1
# 结束
res += m - t + 1
nums[k] = tmp[j]
j += 1
return res
tmp = [0] * len(nums)
return merge_sort(0, len(nums) - 1)
二分(打卡)
class Solution:
def solve(self, A):
d = SortedList()
ans = 0
for a in A:
i = d.bisect_right(a * 3)
ans += len(d) - i
d.add(a)
return ans
抄答案
class Solution: def solve(self, nums) -> int: self.cnt = 0 def merge(nums, start, mid, end, temp): i, j = start, mid + 1 while i <= mid and j <= end: if nums[i] <= nums[j]: temp.append(nums[i]) i += 1 else: temp.append(nums[j]) j += 1
# 这里代码开始
ti, tj = start, mid + 1
while ti <= mid and tj <= end:
if nums[ti] <= 3 * nums[tj]:
ti += 1
else:
self.cnt += mid - ti + 1
tj += 1
# 这里代码结束
while i <= mid:
temp.append(nums[i])
i += 1
while j <= end:
temp.append(nums[j])
j += 1
for i in range(len(temp)):
nums[start + i] = temp[i]
temp.clear()
def mergeSort(nums, start, end, temp):
if start >= end: return
mid = (start + end) >> 1
mergeSort(nums, start, mid, temp)
mergeSort(nums, mid + 1, end, temp)
merge(nums, start, mid, end, temp)
mergeSort(nums, 0, len(nums) - 1, [])
return self.cnt
762.Number Stream to Intervals
入选理由
暂无
题目地址
https://binarysearch.com/problems/Triple-Inversion
前置知识
题目描述
Constraints
n ≤ 100,000 where n is the length of nums Example 1 Input nums = [7, 1, 2] Output 2 Explanation We have the pairs (7, 1) and (7, 2)