• 累加出整个范围所有的数最少还需要几个数


    累加出整个范围所有的数最少还需要几个数

    作者:Grey

    原文地址:

    博客园:累加出整个范围所有的数最少还需要几个数

    CSDN:累加出整个范围所有的数最少还需要几个数

    题目描述#

    给定一个有序的正数数组 arr 和一个正数 aim ,如果可以自由选择 arr 中的数字,想累加得到 1~aim 范围上所有的数,返回 arr 最少还缺几个数。

    例如:

    arr = {1,2,3,7},aim = 15

    想累加得到1~15范围上所有的数,arr 还缺 14 这个数,所以返回 1。

    arr = {1,5,7},aim = 15

    想累加得到1~15范围上所有的数,arr 还缺 2 和 4,所以返回 2。

    题目链接见:累加出整个范围所有的数最少还需要几个数

    主要思路#

    如果区间是1~1,可以组成的数是1;

    如果区间是1~2,可以组成的数是1,2,3,即1~3

    如果区间是1~3,可以组成的数是1,2,3,45,即1~5

    ……

    依此类推

    如果区间是1~n,可以组成的数是1,2……(2*n - 2),(2*n - 1),即1~(2*n - 1)

    所以,如果数组已经可以组成1~range,但是还没有达到1~aim,数组需要增加一个数range+1,就可以让数组的可以组成范围扩大到2*range+1,不断这个过程,直到覆盖1~aim这个区间,这种做法是最经济的

    完整代码如下

    import java.util.Arrays;
    import java.util.Scanner;
    
    /**
     * @author Young
     * @version 1.0
     * @date 2021/1/25 0:06
     */
    public class Main {
        public static void main(String[] args) {
            Scanner in = new Scanner(System.in);
            int n = in.nextInt();
            int aim = in.nextInt();
            int[] arr = new int[n];
            for (int i = 0; i < n; i++) {
                arr[i] = in.nextInt();
            }
            System.out.println(missing(arr, aim));
            in.close();
        }
    
        // 如果要实现1~range所有目标,但整个目标还没有达到1~aim,你永远缺range+1,一定是最省且最经济的,补上range+1后,能达到的数是1~2*range+1
        // 先将数组排序,依次考察如何最经济使用i位置的数
        public static int missing(int[] arr, int aim) {
            int miss = 0;
            long range = 0;
            Arrays.sort(arr);
            for (int item : arr) {
                while (item > range + 1) {
                    // 数组每次可以扩充的范围
                    range += (range + 1);
                    miss++;
                    if (range >= aim) {
                        return miss;
                    }
                }
                range += item;
                if (range >= aim) {
                    return miss;
                }
            }
            while (aim >= range + 1) {
                range += range + 1;
                miss++;
            }
            return miss;
        }
    }
    
    

    代码说明

    首先对数组进行排序的目的是找到连续的数组区间,这样才能判断扩散的范围,然后遍历数组,其中

                while (item > range + 1) {
                    // 数组每次可以扩充的范围
                    range += (range + 1);
                    miss++;
                    if (range >= aim) {
                        return miss;
                    }
                }
    

    表示数组出现了断层,比如 item 之前的数可以组成的1~8,但是 item 值为 12,说明9~11无法被组成,此时,原数组需要补充一个 9(即:miss++),就可以将原数组的可组成范围扩大到1~17(即:range+=(range+1))。

    时间复杂度O(N*logN),瓶颈主要是前面的排序的时间复杂度。

    空间复杂度O(1)

    更多#

    算法和数据结构笔记

  • 相关阅读:
    【C++】:内存管理
    java计算机毕业设计作业自动评阅系统的设计和开发源码+数据库+系统+lw文档+mybatis+运行部署
    鸿萌数据恢复服务:Mac 文件系统是如何影响 Mac 数据恢复的?
    从零开始写一个APM监控程序(一)协议
    每日一练——Java
    js函数定义方式的区别
    Java数学工具类Math
    大数据技术基础实验十一:Hive实验——Hive分区
    爱惨了,这个听书神器APP
    ubuntu20下使用 torchviz可视化计算图
  • 原文地址:https://www.cnblogs.com/greyzeng/p/16725698.html