平方数之和

731 阅读1分钟

给定一个非负整数 c ,你要判断是否存在两个整数 a 和 b,使得 a2 + b2 = c 。

image.png

解析:

求的正整数的平方数之和等于某个树,那么 a 和 b 必然 < c,最先想到的通用求解方法即遍历小于 c 的所有数字,然后分别取平方,再相加,判断是否相等。

采用双指针的方法:分别从0和最大值去进行取平方相加:

设左指针为 left,右指针为 right。 sum = left * left + right * right 则有:

  1. left 始终 <= right

  2. sum = c ,则 return true

  3. sum < c , 则 left++ (如果移动右指针那么 sum 将会更小)

  4. sum > c, 则 right-- (如果移动左指针,那么 sum 将会更大)

图解:

ScreenRecorderProject5.gif

代码:

var judgeSquareSum = function(c) {
   let left = 0
   let right = c
   while(left <= right) {
        const leftNumer = left * left
        const rightNumber = right * right
        const sum = leftNumer + rightNumber
        if (sum === c) {
            return true
        } else if (sum > c) {
            right--
        } else {
            left++
        }
        if (leftNumer > c) {
            return false
        }
   }
   return false
};

这样可以求得正解,代码量也不多,但是不能发现有个非常大的缺点,就是不必要的遍历和计算太多,极大的浪费内存。譬如:c = 13 时, 右指针第一个取 12 * 12,这样的计算实际上是没有必要的。第一个右指针应当是小于C的第一个平方数。c = 13 时,第一个右指针应当指向 3*3 = 9.左指针 0,那么只需要很少的计算就能够求的是否满足条件了。

右侧指针的初始位置应当为 Math.floor(Math.sqrt(c))

可以将计算按照以下优化:

   let right = Math.floor(Math.sqrt(c))

完整代码:

/**
 * @param {number} c
 * @return {boolean}
 */
var judgeSquareSum = function(c) {
   let left = 0
   let right = Math.floor(Math.sqrt(c))
   while(left <= right) {
        const leftNumer = left * left
        const rightNumber = right * right
        const sum = leftNumer + rightNumber
        if (sum === c) {
            return true
        } else if (sum > c) {
            right--
        } else {
            left++
        }
        if (leftNumer > c) {
            return false
        }
   }
   return false
};