問題
例子
思路
暴力方法,兩個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);
}
}