为向量中足够大的输入获取负输出

问题描述

我正在为一个问题编写一个算法,如下所示:

考虑一个将正整数 n 作为输入的算法。如果 n 是偶数,则算法将其除以 2,如果 n 是奇数,则算法将其乘以 3 并加 1。该算法重复此操作,直到 n 为 1。例如,n=3 的序列如下: 3→10→5→16→8→4→2→1

原始问题可以在here

我为它写的算法如下:

#include <iostream>
#include<vector>
using namespace std;
void check(long int n,vector<int> &arr);
int main(){
    long int n;
    cin>>n;
    vector<int> arr; //Vector to store values of n
    check(n,arr);
    for(unsigned int i=0;i<arr.size();i++){
      cout<<arr[i]<<' ';    //Printing the final values of n
    }
    return 0;
}

void check(long int n,vector<int> &arr){
    arr.push_back(n);
    if(n%2==0){   //if n is even
      n=n/2;
      if(n!=1){
        check(n,arr);
      }
      else if(n==1){
        arr.push_back(1);
      }
    }
    else{         //if n is odd
      n=(n*3)+1;
      if(n!=1){
        check(n,arr);
      }
      else if(n==1){
        arr.push_back(1);
      }
    }
    return;
}

我的解决方案适用于较小的 n 值。然而,当 n 变得足够大时——尤其是在 138367 附近的某个地方(这是根据编译器给出错误答案时的第一个测试用例),最后打印的 n 的值也开始包括一些“负数”,这有点不合理。

例如,如果我在开头输入 n=986089625,那么在最终结果中紧随其后的下一个数字是 -1336698420。而正确的数字应该是2958268876。令人惊讶的是,接下来的下一个数字是正确的,但在某些(随机)间隔内,这些数字变成了负数。

我知道算法可以进一步简化,但我无法理解这个算法的问题。我想我遗漏了一些微妙的东西!

解决方法

典型的 int(有符号的 32 位长)最多只能存储 2,147,483,647 (2**31 - 1) 的数字,而数字 2958268876 超过了这个限制。

您使用 long int 进行计算,因此您也应该将其用于 vector 的元素。

换句话说,三个 vector<int> 应替换为 vector<long int>

,

你可以通过这个简单的例子看到它是如何工作的

#include <limits.h>
#include <iostream>

int main()
{
    int n = INT_MAX;
    std::cout << "n=" << n << '\n';
    std::cout << "n+1=" << n + 1 << '\n';

    unsigned m = UINT_MAX;
    std::cout << "m=" << m << '\n';
    std::cout << "m+1=" << m + 1 << '\n';
}

给予

n=2147483647
n+1=-2147483648
m=4294967295
m+1=0

当达到限制时,INT_MIN 或零发生回绕,具体取决于整数类型的符号。

同样的情况当然也发生在相反的方向,从 INT_MIN 到 INT_MAX 或从零到 UINT_MAX。