题目地址
https://binarysearch.com/problems/Triple-Inversion
题目描述
思路
- 原本我想的是对遍历到的数之后的数排序,看有多少满足 nums[i] > nums[j] * 3,这样不可避免的要排序很多次,不出乎意料地超时了……那就反过来,对已遍历过的数排序,看当前遍历到的数之前有多少满足nums[j] * 3< nums[i]的
[已经遍历过的有序数组,索引范围为[0, i - 1]
|遍历到的当前数,索引为i
|还未遍历到的数组
] - 在已遍历过的数构成的有序数组里,通过二分法找到满足条件的最小的索引,也就是通过二分法找左边界
- 那么这个最小索引之后一直到 i 之间的数字都是满足条件的数字,令结果
res = i - leftBorder
- 接下来要将当前数加到排序数组中,还是通过二分法找到比当前数大的最小索引,在该索引位置插入当前数
- 二分法步骤
- 令
left = 0
,right = 排序数组末尾索引
- 令
mid = (left + right) / 2
- 如果
sortedNums.get(mid) <= target
,mid太小了,要增加mid,left = mid + 1
- 如果
sortedNums.get(mid) > target
,mid可能偏大,也有可能就是我们想要的结果,令right = mid - 1
那么查找区间变成了[left, mid - 1],如果mid不是我们想要的左边界,那就丢弃了;如果mid是我们想要的左边界,那么在这之前应当已满足left == mid == 之前的right
,right减少了之后left > right
,不再满足循环条件,返回left;如果数组里的所有数都不符合条件,那根本不会走这个语句
PS: Python有时候要超时,如果超时了多跑几遍会通过的;Java不会超时
代码(Python)
class Solution:
def solve(self, nums):
res = 0
sorted_nums = []
for i in range(len(nums)):
left_border = self.find_left_border(sorted_nums, nums[i] * 3)
res += i - left_border
insert_index = self.find_left_border(sorted_nums, nums[i])
sorted_nums.insert(insert_index, nums[i])
return res
def find_left_border(self, sorted_nums, target):
left = 0
right = len(sorted_nums) - 1
while left <= right:
mid = (left + right) // 2
if sorted_nums[mid] <= target:
left = mid + 1
else:
right = mid - 1
return left
代码(Java)
import java.util.*;
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 ( n 2 ) O(n^2) O(n2),for循环一定有 O ( n ) O(n) O(n),for循环里面的二分法有 O ( l o g n ) O(logn) O(logn),插入操作最差有 O ( n ) O(n) O(n),最后就是 O ( n 2 ) O(n^2) O(n2)
- 空间复杂度: O ( n ) O(n) O(n)