在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数P。并将P对1000000007取模的结果输出。 即输出P mod 1000000007
public class Soulation {
//防止溢出,用long存储
private static long sum=0;
public static int InversePairs(int []array){
if (array!=null){
divide(array,0,array.length-1);
}
return (int)(sum%1000000007);
}
private static void divide(int[]array,int l,int r){
if (l>=r){
return;
}
int mid=(l+r)/2;
divide(array,l,mid);
divide(array,mid+1,r);
merge(array,l,mid,r);
}
private static void merge(int[]array,int l,int mid,int r){
//记录合并后的数组
int[]tmp=new int[r-l+1];
int i=l;//左区间的起点坐标
int j=mid+1;//右区间的起点坐标
int index=0;
while (i<=mid&&j<=r){
if (array[i]>array[j]){
//发现逆序对
sum+=mid-i+1;
tmp[index]=array[j];
j++;
}else {
tmp[index]=array[i];
i++;
}
index++;
}
while (i<=mid){
tmp[index]=array[i];
i++;
index++;
}
while (j<=r){
tmp[index]=array[j];
j++;
index++;
}
System.arraycopy(tmp,0,array,l,index);
}
public static void main(String[] args) {
int[]array={1,2,3,4,5,6,7,0};
System.out.println(InversePairs(array));
}
}
思想:使用归并排序的思想
1.先对数组进行分解,将叔祖划分成左右两个区间
2.对数组进行合并,设置左区间的起点下标和右区间起点下标,如果左区间左节点数字大于右区间左节点数字,则存在逆序对,需要计算sum
-
旋转数组的最小数字
有一个长度为 n 的非降序数组,比如[1,2,3,4,5],将它进行旋转,即把一个数组最开始的若干个元素搬到数组的末尾,变成一个旋转数组,比如变成了[3,4,5,1,2],或者[4,5,1,2,3]这样的。请问,给定这样一个旋转数组,求数组中的最小值。
数据范围:1 \le n \le 100001≤n≤10000,数组中任意元素的值: 0 \le val \le 100000≤val≤10000
要求:空间复杂度:O(1)O(1) ,时间复杂度:O(logn)O(logn)
思想:
1.定义两个指针left和right ,如果array[left]<array[right] 不是旋转数组,反之则是旋转数组
2.array[mid] > array[right]--------最小元素在右边left=mid+1;
array[mid] ==array[right]--------最小元素不能确定需要一个一个试 right=right-1
array[mid] <array[right]--------最小元素在左边或者就是它本身 right=mid
public int minNumberInRotateArray (int[] nums) {
// write code here
int left=0;
int right=nums.length-1;
while (left<right){
int mid=(left+right)/2;
if (nums[mid]>nums[right]){
left=mid+1;
}else if (nums[mid]==nums[right]){
//一直找
right=right-1;
}else {
right=mid;
}
}
return nums[left];
}
}
-
比较版本号
现在给你2个版本号version1和version2,请你比较他们的大小
版本号是由修订号组成,修订号与修订号之间由一个"."连接。1个修订号可能有多位数字组成,修订号可能包含前导0,且是合法的。例如,1.02.11,0.1,0.2都是合法的版本号
每个版本号至少包含1个修订号。
修订号从左到右编号,下标从0开始,最左边的修订号下标为0,下一个修订号下标为1,以此类推。比较规则:
一. 比较版本号时,请按从左到右的顺序依次比较它们的修订号。比较修订号时,只需比较忽略任何前导零后的整数值。比如"0.1"和"0.01"的版本号是相等的
二. 如果版本号没有指定某个下标处的修订号,则该修订号视为0。例如,"1.1"的版本号小于"1.1.1"。因为"1.1"的版本号相当于"1.1.0",第3位修订号的下标为0,小于1
三. version1 > version2 返回1,如果 version1 < version2 返回-1,不然返回0.数据范围:
1 <= version1.length, version2.length <= 10001<=version1.length,version2.length<=1000
version1 和 version2 的修订号不会超过int的表达范围,即不超过 32 位整数 的范围进阶: 空间复杂度 O(1)O(1) , 时间复杂度 O(n)O(n)
思想:
1.设置两个指针,分别代表两个字符串的下标,分别遍历两个字符串
2.每次截取(.)之前的字符组成数字,遇到(.)之前直接取数字*10,可以去掉前导0(0。1和0.01是一样的)
3.比较数字大小,返回相应的值
//比较版本号
public static int compare(String s1,String s2){
int n1=s1.length();
int n2=s2.length();
//设置两个指针
int i=0;
int j=0;
//遍历字符串
while (i<n1||j<n2){
//设置字符前面的数字变量
long num1=0;
//下一个点前截取的数字
while (i<n1&&s1.charAt(i)!='.'){
num1=num1 *10+(s1.charAt(i)-'0');
i++;
}
//跳过点
i++;
long num2=0;
//从下一个点进行截取
while (j<n2 && s2.charAt(j)!='.'){
num2=num2*10+(s2.charAt(j)-'0');
j++;
}
j++;
//比较数字
if (num1>num2){
return 1;
}
if (num1<num2){
return -1;
}
}
//版本号相同
return 0;
}
public static void main(String[] args) {
String s1="1.1";
String s2="1.01";
System.out.println(compare(s1,s2));
}