【数学】C030_平方数之和(双循环枚举 | 开平方单循环 | 双指针)

一、题目描述

Given a non-negative integer c, your task is to decide
whether there're two integers a and b such that a^2 + b^2 = c.

Example 1:
Input: 5
Output: True
Explanation: 11 + 22 = 5
 
Example 2:
Input: 3
Output: False

二、题解

(1) 暴力枚举(超时)

/**
 * 超时:输入1000000000
 * @param c
 * @return
 */
public boolean judgeSquareSum1(int c) {
  int n = (c >>> 1) + 1;
  for (int i = 0; i <= n; i++)
  for (int j = i; j <= n; j++)
   if(i*i + j*j == c)
    return true;
  return false;
}

(2) 开平方计算

/**
 * 将两次循环变利用算数运算变为一次循环
 * 执行用时 8 ms 击败了 12.25% 的java用户
 * 内存消耗 33MB 击败了 81% 的java用户
 */
public boolean judgeSquareSum2(int c) {
  double sqrtC = Math.sqrt(c);
  for(int a = 0; a <= sqrtC; a++) {
    // 为什么这样减?如果c减去正在枚举的a的平方后开方,得到的仍然是一个整数,那么c一定是个平方数
    double b = Math.sqrt(c - a*a);
    if(b == (int)b) return true;
  }
  return false;
}

开平方的算法还可以写成这样

/*
 * 6ms 击败30.88%
 */
public boolean judgeSquareSum2(int c) {
 for(long a = 0; a*a <= c ; a++) {
   double b = Math.sqrt(c - a*a);
   if(b == (int)b) return true;
 }
 return false;
}

为什么要用long?如果用int,在输入2147483646后会超时

  • 分析:当a最后等于2147483646这个数时,a++会变成负数,然后又进入了循环,最终无限循环。

(3) 双指针

既然第一种做法从一段开始超时,不如我们从数字c的两端向中间逼近,这样可以减少计算的规模。

/**
 * 执行用时 3 ms 击败了 75% 的java用户
 * 内存消耗 32.8MB 击败了 82.5% 的java用户
 * @param c
 * @return
 */
public boolean judgeSquareSum3(int c) {

  int l=0, r=(int)Math.sqrt(c);
  while(l <= r) {
    int sum = l*l + r*r;
    if(sum > c)  r--;
    else if(sum < c)  l++;
    else return true;
  }
  return false;
}

while 循环的条件为什么使用<=

  • 因为当c==2时,l=0,r==1,等下一次循环,l=1,r=1,如果不是<=,则会退出循环,返回false,不符合题意。
发布了300 篇原创文章 · 获赞 48 · 访问量 8060

猜你喜欢

转载自blog.csdn.net/qq_43539599/article/details/104011347