腾讯17年暑期实习生笔试题 - 有趣的数字

问题

小Q今天在上厕所时想到了这个问题:有n个数,两两组成二元组,差最小的有多少对呢?差最大呢?


输入描述

输入包含多组测试数据。
对于每组测试数据:
N - 本组测试数据有n个数
a1,a2…an - 需要计算的数据
保证:1<=N<=100000,0<=ai<=INT_MAX.


输出描述

对于每组数据,输出两个数,第一个数表示差最小的对数,第二个数表示差最大的对数。


Java Code

import java.util.Arrays;
import java.util.Scanner;

public class IntrestingNumber {
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);

        while(scan.hasNext()) {
            int n = scan.nextInt();
            int[] nums = new int[n];
            for(int i = 0; i < n; ++i)
                nums[i] = scan.nextInt();
            System.out.println(solve(n, nums));
        }

        scan.close();
    }

    private static String solve(int n, int[] nums){

        //默认升序排列
        Arrays.sort(nums);

        //最大差值是数组的最大元素值(可能有多个)减去最小元素值(可能有多个)
        int maxCount;

        //数组中最小元素值的个数(至少有一个)
        int minNum = 1;
        int j = 1;
        while(j < n && nums[j-1] == nums[j]) {
            minNum++;
            j++;
        }

        //数组中最大元素值的个数(至少有一个)
        int maxNum = 1;
        j = n-2;
        while(j >= 0 && nums[j] == nums[j+1]) {
            maxNum++;
            j--;
        }

        //得到最大差值二元组的个数(组合数)
        if(nums[0] == nums[n-1])
            maxCount = n*(n-1)/2;
        else
            maxCount = maxNum * minNum;



        //最小差值是排序之后所有相邻元素的差值中的最小值
        int minCount = 0;

        //计算并记录升序数组中相邻元素的差值
        for(int i = 0; i < n-1; ++i)
            nums[i] = nums[i+1] - nums[i];

        int min = Integer.MAX_VALUE;//最小差值
        int tempCount = 0;//每个差值为0的区间的长度统计
        boolean flag = true;//标志位,用于标记每个差值为0的区间的首元素(true变成false)和尾元素(false变成true)

        for(int i = 0; i < n-1; ++i) {
            if(nums[i] == 0) {//如果差值为0
                if(min != 0) {//如果第一次遇到最小差值0
                    minCount = 0;//重新开始统计最小差值的个数
                    min = 0;//更新min
                }

                tempCount++;//当前差值为0的区间计数加1         
                if(flag)//差值为0的区间的首元素出现
                    flag = false;//反转标志位

            }else {//如果差值非0
                if(nums[i] == min)//如果非0差值重复出现
                    minCount++;//计数加1
                else if(nums[i] < min) {//如果出现更小的差值(大于0)
                    minCount = 1;//重新统计最小差值个数
                    min = nums[i];//更新最小差值
                }

                if(!flag) {//如果差值为0的区间刚结束
                    minCount += tempCount*(tempCount + 1)/2;//累计最小差值个数
                    tempCount = 0;//重置计数器,准备统计下一个差值为0的区间的长度
                    flag = true;//反转标志位
                }
            }
        }

        //累计最后一个差值为0的区间的最小差值个数
        if(tempCount > 0)
            minCount += tempCount*(tempCount + 1)/2;

        return (minCount + " " + maxCount);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值