思路1
递归,dp(n) = dp(n-1)+[n到n-1]之间比n小的和,例如,遍历数组,第一个数是5,则判断4是否在右侧,如果有,则统计IDX5到IDX4之间比5小的值的个数,并获得4的索引IDX4,递归计算4右侧逆序数量。
用HashMap可以加快递归过程,递归获得4右侧的逆序数量时,先从hashMap中找4是否已经计算过,如果已经计算过,则直接读取计算的结果值,否则递归调用3右侧逆序数量。(但就是利用了HashMap还是会运行超时,哎。。。)
自测运行可以通过,但正式提交时运行超时。import java.util.HashMap; public class Solution { class Content{ public int num; public int idx; public Content(int inNum, int inIdx){ num = inNum;//当前数组元素的逆序对数目 idx = inIdx;//当前数组元素的索引值 } } public int InversePairs(int [] array) { if(array.length == 0) return 0; int res = 0; //构建字典 int iHashMapSize =(int)((float)array.length/0.75f+1); HashMap<Integer,Content> mapArray = new HashMap<Integer,Content>(iHashMapSize); int iMinValue = array[0]; for(int idx = 0; idx < array.length; ++idx){ Content tmpC = new Content(-1,idx); mapArray.put(array[idx],tmpC); if(iMinValue >array[idx]) iMinValue = array[idx]; } //计算结果值 for(int idx = 0; idx<array.length;++idx){ res+=CalTimes(mapArray,array,array[idx],iMinValue); } return res; } int CalTimes(HashMap<Integer,Content> mapArray,int [] array,int inValue,int inMinValue){ //如果是数组中最小值,则右侧比最小值小的值为0 if(inValue == inMinValue) return 0; Content c = mapArray.get(inValue); if((c.num)!=-1){ //已经计算过,则返回已经计算过的值 return c.num; } //没有统计过该值,则计算该值右侧比该值小的数有多少个 //当前Value的idx int curValueIdx = c.idx; int nextValueIdx = 0; int curValue = inValue; while(false == mapArray.containsKey(curValue-1) || mapArray.get(curValue-1).idx < curValueIdx){ if(true == mapArray.containsKey(curValue-1)){ nextValueIdx = mapArray.get(curValue-1).idx ; } if((curValue-1) == inMinValue) break; --curValue; } nextValueIdx = mapArray.get(curValue-1).idx ; int curNum = 0; int ptValue = curValue; if( mapArray.get(curValue-1).idx < curValueIdx){ curNum = 0; } else{ //在curValueIdx和NextValueIdx之间还有n个小于curValue的值 for(int idx = curValueIdx; idx < nextValueIdx; ++idx){ if(array[idx] <inValue){ ++curNum; } } curNum += ((CalTimes(mapArray,array,curValue-1,inMinValue)+1)%1000000007); } c.num =curNum; return curNum; } }
正确思路1
归并排序
引申:遇到区间问题都可以用归并来求解,但区间问题的具体定义是什么呢?public class Solution { private int cnt; public int InversePairs(int [] array) { if(array.length == 0) return 0; int []temp = new int[array.length]; return sort(array,0,array.length-1,temp); //return cnt; } int sort(int [] array,int inStart, int inEnd,int []temp){ if(inStart < inEnd){ int mid = (inStart+inEnd)/2; int res1 = sort(array,inStart,mid,temp); int res2 = sort(array,mid+1,inEnd,temp); /*二分法的左右区间处理,右区间的起始可以+1开始, 这样可解决在2,3之间算mid,mid = 2时,有区间是[2,3]的情况 */ int res3 = merge(array,inStart,mid,inEnd,temp); return (res1+res2+res3)%1000000007; } return 0; } int merge(int []array ,int inStart,int inMid,int inEnd, int[]temp){ int res = 0; int i = inStart;//含右,因为inEnd也是有效值 int j = inMid+1; int k = inStart; while(i <= inMid && j <= inEnd){ if(array[i] <= array[j]){ temp[k++] = array[i++]; } if(array[i] > array[j]){ res = (res + (inMid-i+1))%1000000007; temp[k++] = array[j++]; /* temp[k++] = array[j++]; cnt = (cnt + (inMid-i+1))%1000000007;*/ } } //把剩下的接到temp中 while(i <=inMid){ temp[k++] = array[i++]; } while(j <=inEnd){ temp[k++] = array[j++]; } //将当前array区间覆盖为有序的temp for(int l = inStart; l <k;++l){ array[l] = temp[l]; } return res; } }
防吞格式
防吞格式
防吞格式
防吞格式
防吞格式
防吞格式
防吞格式