从标准输入中读取自然数n。找到小于或等于n的最大完美平方

时间:2018-10-24 20:11:57

标签: c

#include <stdio.h>
#include <stdlib.h>

int main() {
  int i, j, n, maxi = 0;
  printf("\n Introduce the number:\n");
  scanf("%d", &n);

  for (j = 1; j <= n; j++)
  {
    i = 0;
    while (i < j) {
      i++;

      if (j == i * i) {
        if (j > maxi) {
          maxi = j;
          printf("%d", maxi);
        }
      }
    }
  }
  return 0;
}

我必须找到小于数字n的最大完美平方,我成功找到了小于数字n的所有完美平方,但是因为每次找到一个完美平方它显示了它,我想不出任何办法来比较找到的所有完美平方(或者至少这就是我认为的问题所在),所以我将不胜感激。我已经知道您也可以使用更简单的方法(例如下面的方法)解决此问题,如果您对解决方法有任何其他想法,我想听听他们的看法。

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

int main()
{
  int n,j;
  printf("\n Your number:\n");
  scanf("%d",&n);
  j=(int)sqrt(n);
  printf("%d",j*j);
  return 0;
}

3 个答案:

答案 0 :(得分:2)

这里您只需要一个循环。检查是否i*i <= n。如果是这样,请将maxi设置为i*i并递增i

int n, i = 1, sq = 1;

printf("\n Introduce the number:\n");
scanf("%d", &n);

while (i*i <= n) {
    sq = i*i;
    i++;
}

printf("sq=%d\n", sq);

答案 1 :(得分:1)

  

找到小于或等于n的最大完美平方

对于n>=0,这类似于找到n整数平方根。

unsigned greatest_perfect_square(unsigned x) {
  unsigned root = usqrt(x);
  return root * root;
}

  

如果您还有其他解决方法的想法,我想听听他们的想法。

查找平方根的复杂度顺序为O(bit-width-of-type-n)。例如16次迭代。

#include <limits.h>
unsigned usqrt(unsigned x) {
  unsigned y = 0;
  unsigned xShifted = 0;

  const unsigned MSBit = UINT_MAX - UINT_MAX/2;
  // This  constant relies on no padding and bit width even
  const unsigned TwoBitCount_N = sizeof(x) * CHAR_BIT / 2;
  for (unsigned TwoBitCount = TwoBitCount_N; TwoBitCount > 0; TwoBitCount--) {
    // Shift `xShifted` 2 places left while shifting in the 2 MSbits of x
    xShifted <<= 1;
    if (x & MSBit) {
      xShifted |= 1;
    }
    x <<= 1;
    xShifted <<= 1;
    if (x & MSBit) {
      xShifted |= 1;
    }
    x <<= 1;
    // Shift the answer 1 bit left
    y <<= 1;
    // Form test value as y*2 + 1
    unsigned Test = (y << 1) | 1;
    // If xShifted big enough ...
    if (xShifted >= Test) {
      xShifted -= Test;
      // Increment answer
      y |= 1;
    }
  }
  return y;
}

OP的方法要慢得多。甚至内部循环也需要O(sqrt(n))时间。

注意:
OP的代码:j == i * i可能会溢出,并且在j较大时会导致错误的答案。
j/i == i执行类似的测试,没有溢出。


@Jonathan Leffler建议使用Newton-Raphson approximation方法。下面一些经过严格测试的代码可以非常快速地运行,通常只需进行几次迭代。
我怀疑这主要是O(log(bit-width-of-type-n)),但是O(log(bit-width-of-type-n))当然仍然是bit_width()
这两个功能都可以改进。

unsigned bit_width(unsigned x) {
  unsigned width = 0;
  while (x) {
    x /= 2;
    width++;
  }
  return width;
}

unsigned usqrt_NR(unsigned x) {
  if (x == 0) {
    return 0;
  }
  unsigned y = 1u << bit_width(x)/2;
  unsigned y_previous;
  unsigned diff;
  unsigned diff1count = 0;;
  do {
    y_previous = y;
    y = (y + x/y)/2;
    diff = y_previous < y ? y - y_previous : y_previous - y;
    if (diff == 1) diff1count++;
  } while (diff > 1 || (diff == 1 && diff1count <= 1));
  y = (y_previous + y)/2;
  return y;
}

答案 2 :(得分:0)

这样可以最大程度地减少乘法次数:它会查找第一个大于n的正方形,这意味着紧接其前的完美正方形是解。

for (i = 1; i <= n; i++) {
    if (i*i > n) {
        break;
    }
}
i--;
// i*i is your answer

在某些平台上,利用(i+1)*(i+1) = i*i + 2*i + 1或换句话说,如果您已经拥有i ^ 2,则可以通过将i加两次来获得(i + 1)^ 2,并增加1;在开始时,0 ^ 2为0以启动循环。

for (i = 0, sq = 0; i < n; i++) {
    sq += i; // Or on some platforms sq += i<<1 instead of two sums
    sq += i; // Some compilers will auto-optimize "sq += 2*i" for the platform
    sq++;    // Or even sq += ((2*i)|1) as adding 1 to even numbers is OR'ing 1
    if (sq > n) {
        break;
    }
    // if sq is declared as signed integer, a possible overflow will
    // show it as being negative. This way we can still get a "correct" result
    // with i the smallest root that does not overflow.
    // In 16-bit arithmetic this is 181, root of 32761; next square would be
    // 33124 which cannot be represented in signed 16-bit space.
    if (sq < 0) {
        break;
    }
}
// (i*i) is your answer