找到单个数字的最大完美平方的最快函数?

Posted

技术标签:

【中文标题】找到单个数字的最大完美平方的最快函数?【英文标题】:Fastest function to find largest perfect squares of a single number? 【发布时间】:2021-12-19 22:42:39 【问题描述】:

我正在尝试编写一种算法,该算法将找到给定整数的最大完美平方,并尽可能快地每次从总数中减去它们的值。这有点难以解释,对于有点模棱两可的标题,我深表歉意,所以我将给出一些输入/输出示例:


输入:23 输出:[16、4、1、1、1] 解释:25 (5x5) 太大,但 16 (4x4) 适合。将其添加到数组中并从 23 (7) 中减去 16。下一个适合的最大完美正方形是 4 (2x2),因​​此将其添加到数组中并从 7 (3) 中减去 4。从这里开始,最大的完美正方形就是 1 (1x1)。所以将 1 添加到数组中,直到我们得到 0。
输入:13 输出:[9, 4] 解释:9 (3x3) 是最大的正方形,因此将其添加到数组中并从 13 (4) 中减去。那么 4 也是一个完美的正方形,所以添加它并在那里结束。

我的解决方案如下(变量名称与向我提出问题的方式相关):

public static int[] solution(int startingSquareYards) 

        ArrayList<Integer> largestSquares = new ArrayList<Integer>();

        // Cast for use with Math. methods
        double remainingSquareYards = (double) startingSquareYards;

        while (remainingSquareYards > 0) 

            double largestSquareRoot = Math.floor(Math.sqrt(remainingSquareYards));
            
            // Edit - used to be: 
            // double yardsOfMaterialUsed = Math.pow(largestSquareRoot, 2);
            double yardsOfMaterialUsed = largestSquareRoot * largestSquareRoot;

            remainingSquareYards -= yardsOfMaterialUsed;

            largestSquares.add((int) yardsOfMaterialUsed);

        

        int[] solutionArray = largestSquares.stream().mapToInt(i -> i).toArray();

        return solutionArray;
    

我正在征求对我的解决方案的意见,以及我是否可以针对时间/空间复杂性、简单性(同时保持易于阅读/理解)等以任何方式对其进行优化。它目前适用于我做过的所有测试写但我可能缺少边缘情况或改进它的地方 - 输入startingSquareYards可以在1到1,000,000之间。感谢任何建设性的反馈:)

感谢收看!

【问题讨论】:

如果您的代码有效,那么这个问题属于Code Review 提示 1:pow(x, 2) 很慢。替换为简单的x*x 提示 2:sqrt 很慢。如果您使用非常大的startingSquareYards,那么也许用正方形填充ArrayList&lt;int&gt;,并找到最接近(但小于)remainingSquareYards(向后遍历)。缓存列表中的最后一个索引,以便在下一次迭代中从那里开始。 您的问题是实施回溯。考虑 32。这是 16 和 16,但您的算法会找到 25、4、1、1、1。要快速找到 any 解决方案,只需返回全 1。要找到最小削减,您需要back track。另见Dijkstra 考虑这个 48 - 这里有多种可能形成 48 但你的答案应该是什么? [16,16,16] 或 [25,26,4,1,1,1] 或 [36,9,1,1,1] 或 [36,4,1,1,1,1,1,1 ,1,1] 【参考方案1】:

如 cmets 所述,您的确切要求尚不清楚。以下代码将重现您的问题的示例。通常,它会更喜欢包含最大的正方形而不是产生最短的解决方案。 例如。 32 将产生 [25, 4, 1, 1, 1] 而不是 [16, 16]。这似乎是您的意图,因为您的示例 23 预计会产生 [16, 4, 1, 1, 1] 而不是 [9, 9, 4, 1]

private static final BitSet SQUARES = new BitSet(1_000_001);
static  for(int i = 0; i <= 1_000; i++) SQUARES.set(i * i); 

public static int[] solution(int startingSquareYards) 
    IntStream.Builder b = IntStream.builder();
    for(int square; startingSquareYards > 0; startingSquareYards -= square) 
        square = SQUARES.previousSetBit(startingSquareYards);
        b.add(square);
    
    return b.build().toArray();

它旨在处理您在 1 到 1,000,000 之间指定的输入数字。

它只是简单地准备一个BitSet 告诉哪个整数是平方数,这样可以快速找到等于或小于某个值的最大平方数。这是一个线性搜索,但是一次可以处理 64 个数字的搜索,使用廉价的整数运算。这避免了任何昂贵的浮点运算。它也没有对Integer 对象的装箱。

【讨论】:

以上是关于找到单个数字的最大完美平方的最快函数?的主要内容,如果未能解决你的问题,请参考以下文章

怎么用python求一个数的平方?

求出100个数组里的最大的前十个数最快的算法,c++

完美平方

Python - 在给定的大数范围内找到所有完美正方形的最快方法

javascript基础程序(算出一个数的平方值算出一个数的阶乘输出!- !- !- !- !- -! -! -! -! -! 函数三个数中的最大数)

BZOJ2440: [中山市选2011]完全平方数