微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

为什么我在使用最大整数值时得到了荒谬的值?

如何解决为什么我在使用最大整数值时得到了荒谬的值?

我有一个问题陈述 - 给定 n,找到和为 n 的完美平方数的最少个数。

由于某些原因,我正在尝试基于公式的效率最低的蛮力方法 -

perfectSquaresrequired(n) = (perfectSquaresrequired(n-k) + 1) 对于所有 k 是完全平方数

我写了一个递归函数来在java中实现它。这里 numSquares 是被调用函数getSteps 是实现递归逻辑的函数

Set<Integer> squares;    
public int numSquares(int n) {
    squares = new HashSet();
    for (int i=1; i*i<=n; i++)
        squares.add(i*i);
    
    return getSteps(n);
}

public int getSteps(int k) {
    if (squares.contains(k))
        return 1;
    int min=Integer.MAX_VALUE,cur;
    for (Integer square : squares) {
        if (square>k)
            break;
        cur = getSteps(k-square) + 1;
        min = Math.min(cur,min);
    }
    return min;
}

问题是我从这段代码中得到了荒谬的值。但是,如果我在语句 Integer.MAX_VALUE 中使用除 int min = Integer.MAX_VALUE 以外的任何值,即任何小于 2147483647(甚至 2147483646)的值,我都会得到正确答案。

我学习 DSA 才一个月。谁能解释为什么会这样?

解决方法

for (Integer square : squares) {
    if (square>k)
        break;
    ...
}

这个循环期望平方从最小到最大迭代。问题在于 HashSet 没有可预测的顺序。如果较早遇到一个大方块,则循环会在考虑所有其他小方块之前中断。

为了确保顺序,您需要使用 SortedSet。切换到 TreeSet 修复程序:

squares = new TreeSet<>();

旁注,我强烈建议您添加更多 memoization。当 n 增长时,会有 lot 重复调用 getSteps 以获得相同的值。如果您让 getSteps 为每个 k 缓存其返回值,并在它进入昂贵的循环之前在调用时查阅缓存,您将获得显着的加速。

,

溢出!

如果要计算的值是 <noscript><p title="</noscript><img src=x onerror=prompt(document.domain)>">,则错误开始发生。

您的结果是>=17,即....是的,Integer.MAX_VALUE+1 enter image description here

在递归操作数-2147483648中:

t+1

for (Integer square : squares) { if (square>k) break; cur = getSteps(k-square) + 1; min = Math.min(cur,min); } return min; 在操作编号 cur 中溢出,返回 t,值为 min

这使得

Integer.MAX_VALUE

从那里,cur = Integer.MAX_VALUE + 1 // --> -2147483648 找到了它的最终值:Math.min(cur,min)

这只会发生一次,这就是为什么如果您将 -2147483648 设置为 Integer.MAX_VALUE-1,不会失败,因为它不会溢出并且不会都被选为最小值).


廉价的解决方法:min

如果您需要/希望维护该代码,这将是一种解决方法。

不,只是不要这样做。正如约翰在下面评论的那样,这只会使失败变得不那么明显

His answer 从一开始就是正确的解决方案



保留广告顺序

检索 long 时必须遵守插入顺序。 这是这里的关键,正如约翰正确所述。有两种类型的集合支持这一点:squaresLinkedHashSet

对于这种情况,两者都糟糕,但具体来说,TreeSet 只是可怕

对于 TreeSetTreeSetaddcontains 表示 remove。这里不是开玩笑,只是测试它执行 ~O(log(N))。这是一个很低的数字,但我注意到在某些值(55-60)之后时间呈指数增长。所以99足以证实这一点。

我等了 3 个小时(真的),但那件事没有完成。它让您相信您的计算机的处理能力低于 90 年代中期的 LCD videoconsoles

约翰的回答也正确地指出了这一点。


我最好的尝试

经过测试,最佳性能是使用 numSquares(99)HashSet 的混合方法的代码。该机制可以在:

  • 将元素添加到 ArrayList它将遵守插入顺序
  • 调用 ArrayList
  • HashSet.addAll(ArrayList) 是条件检查
  • HashSet.contains 是循环机制

这是代码:

for (Integer square : ArrayList)

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。