问题
例子
思路
暴力方法,两个for循环,超时
-
方法1
$$$$
使用对并排序,两个数组排好序归并时【左边数组 l=i; l<=m,右边数组r=m+1; r<=j】:如果nums[l]>nums[r],由于都已经排好序,则l到m都>nums[r],有m-r+1个
-
方法2
$$$$
代码
//方法1
class Solution {
private int res=0;
public int reversePairs(int[] nums) {
sort(nums,0,nums.length-1,new int[nums.length]);
return res;
}
public void sort(int[] nums,int i, int j,int[] temp) {
if(i<j) {
int m = i+(j-i)/2;
sort(nums,i,m,temp);
sort(nums,m+1,j,temp);
merge(nums,i,m,j,temp);
}
}
public void merge(int[] nums,int i, int m, int j,int[] temp) {
int ii = i;
int l=i,r=m+1;
while(l<=m && r<=j) {
if(nums[l]<=nums[r]) {
temp[i++]=nums[l++];
}else{
// 则从 nums[l] 到 nums[m] 必定都是大于 nums[r] 的,
// 因为两部分的子数组已经是各自有序的
res += m-l+1;
temp[i++]=nums[r++];
}
}
for(; l<=m; l++)
temp[i++]=nums[l];
for(; r<=j; r++)
temp[i++]=nums[r];
System.arraycopy(temp,ii,nums,ii,j-ii+1);
}
}
315. 计算右侧小于当前元素的个数
思路
归并
因为要记录每个下标后面有几个数字小于该数,所以使用二维数组记录每个数字的下标,排序的时候,带着该元素所在的下标一起排序
使用int数组记录结果
- 方法1
归并时,两个有序数组,arr1,arr2,如果arr1[l]>arr2[r],则arr1中下标在l之后的元素都>arr2[r] - 方法2
归并时,两个有序数组,arr1,arr2, 如果arr[l]<=arr[r],则arr[l]>所有的arr2中下标<r的数
//方法1
class Solution {
int[] res = null;
public List<Integer> countSmaller(int[] nums) {
if(nums.length==0) return new ArrayList<Integer>();
res = new int[nums.length];
int[][] temp = new int[nums.length][2];
int[][] arr = new int[nums.length][2];
for(int i=0; i<nums.length; i++) {
arr[i][0]=nums[i];
arr[i][1]=i;
}
sort(0,nums.length-1,arr,temp);
List<Integer> list = new ArrayList<>();
for(int n:res){
list.add(n);
}
return list;
}
public void sort(int i, int j, int[][] arr, int[][] temp) {
if(i<j) {
int m = i+(j-i)/2;
sort(i,m,arr,temp);
sort(m+1,j,arr,temp);
merge(i,m,j,arr,temp);
}
}
public void merge(int i,int m,int j,int[][] arr,int[][] temp) {
int l=i,r=m+1,ii=i;
while(l<=m && r<=j) {
if(arr[l][0]<=arr[r][0]){
// res[arr[l][1]]+=(r-1)-(m+1)+1;
temp[i++]=arr[l++];
}else{
for(int k=l; k<=m; k++)
{
int index = arr[k][1];
res[index]++;
}
temp[i++]=arr[r++];
}
}
for(;l<=m;l++)
{
// res[arr[l][1]]+=j-(m+1)+1;
temp[i++]=arr[l];
}
for(;r<=j;r++)
temp[i++]=arr[r];
System.arraycopy(temp, ii, arr, ii, j-ii+1);
}
}
//方法2
class Solution {
int[] res = null;
public List<Integer> countSmaller(int[] nums) {
if(nums.length==0) return new ArrayList<Integer>();
res = new int[nums.length];
int[][] temp = new int[nums.length][2];
int[][] arr = new int[nums.length][2];
for(int i=0; i<nums.length; i++) {
arr[i][0]=nums[i];
arr[i][1]=i;
}
sort(0,nums.length-1,arr,temp);
List<Integer> list = new ArrayList<>();
for(int n:res){
list.add(n);
}
return list;
}
public void sort(int i, int j, int[][] arr, int[][] temp) {
if(i<j) {
int m = i+(j-i)/2;
sort(i,m,arr,temp);
sort(m+1,j,arr,temp);
merge(i,m,j,arr,temp);
}
}
public void merge(int i,int m,int j,int[][] arr,int[][] temp) {
int l=i,r=m+1,ii=i;
while(l<=m && r<=j) {
if(arr[l][0]<=arr[r][0]){
res[arr[l][1]]+=(r-1)-(m+1)+1;
temp[i++]=arr[l++];
}else{
// for(int k=l; k<=m; k++)
// {
// int index = arr[k][1];
// res[index]++;
// }
temp[i++]=arr[r++];
}
}
for(;l<=m;l++)
{
res[arr[l][1]]+=j-(m+1)+1;
temp[i++]=arr[l];
}
for(;r<=j;r++)
temp[i++]=arr[r];
System.arraycopy(temp, ii, arr, ii, j-ii+1);
}
}