卢小七的刷题笔记(js)

题目来源: Codewars

题目: Is my friend cheating?

题目难度: 5kyu(不是很难)

  • A friend of mine takes a sequence of numbers from 1 to n (where n > 0).
  • Within that sequence, he chooses two numbers, a and b.
  • He says that the product of a and b should be equal to the sum of all numbers in the sequence, excluding a and b.
  • Given a number n, could you tell me the numbers he excluded from the sequence?

The function takes the parameter: n (don't worry, n is always strictly greater than 0 and small enough so we shouldn't have overflow) and returns an array of the form:

[(a, b), ...] or [[a, b], ...] or {{a, b}, ...} or or [{a, b}, ...]

with all (a, b) which are the possible removed numbers in the sequence 1 to n.

[(a, b), ...] or [[a, b], ...] or {{a, b}, ...} or ...will be sorted in increasing order of the "a".

It happens that there are several possible (a, b). The function returns an empty array if no possible numbers are found which will prove that my friend has not told the truth! (Go: in this case return nil).

#Examples:

removNb(26) should return [(15, 21), (21, 15)]

or

removNb(26) should return { {15, 21}, {21, 15} }

or

removeNb(26) should return [[15, 21], [21, 15]]

or

removNb(26) should return [ {15, 21}, {21, 15} ]

or

in C:
removNb(26) should return  **an array of pairs {{15, 21}{21, 15}}**
tested by way of strings.

个人理解(翻译一下)

1-n的的n个数中找到2个数a,b,使得除去a,b剩下的数之和与a,b之积相等.

解法1 (最粗暴的解法):双重循环遍历

function removeNb(n){
    var res = []
    //等差数列求和
    var sum = ( n + 1 ) * n / 2
    for (var a = 1; a <= n; a++) {
        for(var b = 1; b <= n; b++){
            if (a * b == sum - a - b) {
                res.push([a , b])
            }
        }
    }
    return res
}

结果:几个简单的测试能过,比较大的数字n,超出给定运行时间,报错.

思考1:能不能单循环

需要观察给定的要求,即(sum = (1+n)*n/2):

a*b=sum-a-b

稍微转化一下:

(a+1)*(b+1)=sum+1

思路就有了:

b=(sum+1)/(a+1)-1

改进2:单循环

function removeNb(n){
    var res = []
    //等差数列求和
    var sum = ( n + 1 ) * n / 2
    for (var a = 1; a <= n; a++) {
        var b = ( sum + 1) / ( a + 1 ) - 1
            if ( Number.isInteger(b)&&b<=n) {
                res.push([a , b])
            }
        }
    return res
}

思考二:有无改进空间

单循环的起始位置一定要从1开始么?不.
分析比较小的那个数,不妨认为是a
假设去掉的两个数是n,n-1,则剩下的数之和为:

sumOfRest = sum-2*n-1

此时a应不小于start=[sumOfRest/n]+1,
a的下限为start.并且根据题意,如果[a,b]算一对,[b,a]也算一对.
那么当a>b时,直接将已有的结果加以处理即可.

改进三:利用分析处理循环开始与中间结果

function removeNb(n){
    var res = []
    //等差数列求和
    var sum = ( n + 1 ) * n / 2
    var start = Math.ceil((sum - 2 * n - 1) / n)
    for (var a = start; a <= n; a++) {
        var b = ( sum + 1) / ( a + 1 ) - 1
        if ( Number.isInteger(b) && b <= n && a< b) {
            res.push([a , b])
        }
    }
    var len = res.length
    for (var i = len - 1; i >= 0; i--) {
        var [a, b] = res[i]
        res.push([a, b].reverse())
    }
    return res
}

应该还有改进空间,懒得想了.结束.

再说几句:
提交后也查看了Codewars网站上其他网友的答案,基本都是改进2的做法,其中Number.isInteger(b)用来判断整数,其他做法还有b % 1===0等等,正如题目难度一样,可能并不需要想太多.

你可能感兴趣的:(卢小七的刷题笔记(js))