(面试)编程训练4

在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数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));
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值