Python 计算 1 到 100 的和

140 阅读9分钟

07. 计算 1 到 100 的和

你的源代码如下所示:

python
复制
def get_int(prompt):
    while True:
        try:
            return int(input(prompt))
        except ValueError:
            print("please input an integer")

def sum_between(num1, num2):
    if num1 > num2:
        num1, num2 = num2, num1  # Swap to ensure num1 <= num2

    result = 0
    for i in (num1, num2 + 1):  # This should be 'range(num1, num2 + 1)' instead of a tuple
        result += i
    return result

if __name__ == "__main__":
    num1 = get_int("请输入整数1: ")
    num2 = get_int("请输入整数2: ")
    print(sum_between(num1, num2))

代码解析:

  1. get_int(prompt)
    • 这是一个输入验证函数,确保用户输入的是整数。如果用户输入的不是整数,则会提示用户重新输入,直到输入正确。
  2. sum_between(num1, num2)
    • 该函数计算从 num1num2(包括 num1num2)之间的所有整数的和。它首先检查 num1 是否大于 num2,如果是,则交换它们的位置,然后用 for 循环遍历这个范围,并计算总和。
  3. if __name__ == "__main__":
    • 这是 Python 的标准方式,用来保证只有在直接运行脚本时才会执行主程序中的代码。如果该脚本被导入到其他模块中,则不会执行主程序部分。

小问题:

  • 你的代码中 sum_between 函数的 for 循环应该用 range(num1, num2 + 1),而不是 for i in (num1, num2 + 1),因为 (num1, num2 + 1) 只是一个元组,而 range(num1, num2 + 1) 会生成一个数字序列。

result = 0 for i in (num1, num2 + 1): 那这个代码会怎么运行呢

在这段代码中:

python
复制
result = 0
for i in (num1, num2 + 1):
    result += i

for i in (num1, num2 + 1) 这行代码会将 num1num2 + 1 作为元组元素传递给 for 循环。所以它并不会遍历 num1num2 之间的所有数,而是把 num1num2 + 1 当作两个单独的值。

执行流程:

  1. (num1, num2 + 1) 形成一个元组(num1num2 + 1),例如如果 num1 是 3,num2 是 5,那么这个元组就是 (3, 6)
  2. 循环会遍历这个元组里的元素:
    • 第一次迭代,i = num1(即 3)。
    • 第二次迭代,i = num2 + 1(即 6)。
  3. 然后将 i 累加到 result 变量中。

举个例子:

假设 num1 = 3num2 = 5,这段代码的执行结果会是:

python
复制
result = 0
for i in (3, 6):  # 元组(3, 6)
    result += i

  1. 第一次迭代,i = 3result = 0 + 3 = 3
  2. 第二次迭代,i = 6result = 3 + 6 = 9

最终,result 的值是 9

应该使用 range(num1, num2 + 1), range的作用又是什么呢

range(num1, num2 + 1) 是 Python 中生成整数序列的函数,它返回一个可迭代对象,允许你遍历从 num1num2 之间的所有整数。

range() 函数的参数解释:

range() 函数可以有 1 到 3 个参数:

  1. start(起始值,默认为 0): 序列的起始位置(包括该值)。
  2. stop(结束值):序列的结束位置(不包括该值)。
  3. step(步长,默认为 1):控制每次递增的步长。

range(num1, num2 + 1) 具体说明:

  • num1:这是你希望生成的序列的起始数,且会包含这个值。
  • num2 + 1:这是你希望序列结束的数。range 函数生成的序列不包含stop,所以为了让序列包含 num2,我们传递 num2 + 1 作为结束值。

举个例子:

假设 num1 = 3num2 = 5,那么 range(3, 5 + 1) 等于 range(3, 6),这将生成一个从 3 到 5 的整数序列(包括 3 和 5)。

python
复制
# 生成从 3 到 5 的数的序列
for i in range(3, 6):
    print(i)

输出

复制
3
4
5

总结:

  • range(num1, num2 + 1) 会生成从 num1num2(包括 num1num2)的所有整数。
  • range()start 是包含的,而 stop 是不包含的,所以通过传递 num2 + 1 来确保 num2 被包含在内。

这个题目有没有更好的解法

你提到的题目是计算两个整数之间(包括这两个整数)的和。现有的解法通过循环逐个加起来是有效的,但还有其他更简洁、高效的解法。

更好的解法:使用数学公式

计算两个整数 num1num2 之间所有整数的和,我们可以利用数学公式来求解。对于连续整数的和,我们使用等差数列求和公式

S=n(a1+an)2S = \frac{n(a_1 + a_n)}{2}

S=2n(a1+an)

其中:

  • nnn 是整数个数(即 num2 - num1 + 1)。
  • a1a_1a1 是起始数(即 num1)。
  • ana_nan 是结束数(即 num2)。

公式的使用:

  1. 计算从 num1num2 之间的整数个数:n = num2 - num1 + 1
  2. 使用等差数列求和公式直接计算和:

Sum=(num2−num1+1)×(num1+num2)2\text{Sum} = \frac{(num2 - num1 + 1) \times (num1 + num2)}{2}

Sum=2(num2−num1+1)×(num1+num2)

优点:

  • 效率更高:这个方法直接通过公式计算出结果,不需要循环遍历每一个数,时间复杂度为 O(1)O(1)O(1)。
  • 更简洁:通过简单的数学运算解决问题,代码更加简洁且直观。

实现代码:

python
复制
def get_int(prompt):
    while True:
        try:
            return int(input(prompt))
        except ValueError:
            print("please input an integer")

def sum_between(num1, num2):
    # 使用等差数列求和公式
    return (num2 - num1 + 1) * (num1 + num2) // 2

if __name__ == "__main__":
    num1 = get_int("请输入整数1: ")
    num2 = get_int("请输入整数2: ")
    print(f"结果是: {sum_between(num1, num2)}")

代码解释:

  1. sum_between(num1, num2):使用了等差数列求和公式,计算从 num1num2 的和。
    • (num2 - num1 + 1) 计算的是数列中的数字个数。
    • (num1 + num2) 是数列的首尾和。
    • // 2 是为了按照公式除以 2。
  2. get_int(prompt):仍然用于输入验证,确保用户输入的是有效的整数。

// 2 什么意思,怎么不是/2

在 Python 中,/// 都是除法操作符,但它们的作用是不同的。

/ 和 // 的区别:

  • /(普通除法):进行浮点数除法,结果是一个浮动的小数。
    • 例如,5 / 2 会得到 2.5
  • //(整数除法):进行整数除法,结果是向下取整的整数。即使两个数字的结果是一个小数,它会自动将其截断为整数部分(即丢弃小数部分)。
    • 例如,5 // 2 会得到 2,它会舍去余数。

代码中 // 2 的含义:

python
复制
return (num2 - num1 + 1) * (num1 + num2) // 2

在这个公式中,// 2 表示:

  • (num2 - num1 + 1) * (num1 + num2) 计算出的结果除以 2,并且强制转换为整数,舍弃余数部分。
  • 这是因为我们想要得到的是整数结果(因为求和的结果通常是一个整数),不需要小数部分。

那这里改成/2 会怎样?假设 num1 = 3 和 num2 = 5,我们按照公式来计算: 最后是24/2 结果也是12呀

区别:

  • / 2:返回 浮点数,即使结果是整数,它也会返回一个浮点数。例如,24 / 2 会返回 12.0
  • // 2:强制返回 整数,即使结果是整数,它也会返回整数类型。例如,24 // 2 会返回 12

为什么使用 // 2?

  1. 整数除法的要求
    • 在这个公式中,我们知道结果应该是一个整数,因此使用 // 更符合需求,确保返回的结果是整数。
    • 如果使用 / 2,它会返回 12.0(浮点数),你可以通过转换类型来得到整数,但这样做不够直

时间复杂度O1 是什么意思,我如果循环遍历每一个数,时间复杂度又是多少呢

时间复杂度 O(1)O(1)O(1) 是什么意思?

时间复杂度 O(1)O(1)O(1),也称为常数时间复杂度,意味着算法的运行时间不依赖于输入的规模大小,始终是一个固定的时间,和输入的元素数量无关。无论你输入多少数据,算法执行的步骤数都是相同的,或者是常数级别的。

举个例子:

  1. 常数时间操作

    python
    复制
    def constant_time_example(x):
        return x * 2  # 只有一条语句,执行时间不会随着x的大小变化
    
    

    这里,无论输入 x 是什么,函数的执行时间始终是固定的。

  2. 查找数组中的第一个元素

    python
    复制
    def get_first_element(arr):
        return arr[0]  # 获取第一个元素,始终是O(1)
    
    

    无论数组的长度是多少,访问数组中的第一个元素的时间始终是固定的,即 O(1)O(1)O(1)。

时间复杂度 O(n)O(n)O(n) 是什么意思?

时间复杂度 O(n)O(n)O(n),也称为线性时间复杂度,意味着算法的运行时间会随着输入规模 nnn 的增大而线性增加,时间复杂度与输入的元素数量成正比。

举个例子:

  1. 遍历数组中的每个元素

    python
    复制
    def sum_elements(arr):
        total = 0
        for i in arr:
            total += i  # 遍历每个元素,执行n次
        return total
    
    

    在这个例子中,算法需要遍历数组中的每个元素,因此如果数组的长度是 nnn,算法的时间复杂度就是 O(n)O(n)O(n),意味着执行时间随着数组的长度线性增长。

对比 O(1)O(1)O(1) 和 O(n)O(n)O(n) 的差异:

  • O(1)O(1)O(1):表示执行步骤数是固定的,输入规模大小不会影响执行时间。比如访问数组中的某个元素、基本的算术运算等。
  • O(n)O(n)O(n):表示执行时间与输入规模成线性关系。如果你有一个包含 nnn 个元素的列表,算法需要遍历每个元素,那么时间复杂度是 O(n)O(n)O(n)。

时间复杂度为 O(n)O(n)O(n) 的例子:

假设我们要遍历一个列表中的每个元素:

python
复制
def print_elements(arr):
    for i in arr:  # 遍历每个元素
        print(i)    # 每个元素的输出,执行n次

在这个例子中,程序需要遍历列表中的每个元素,执行了 nnn 次操作。因此,这个函数的时间复杂度是 O(n)O(n)O(n),其中 nnn 是输入列表的长度。

总结:

  • O(1)O(1)O(1):表示算法的执行时间是常数,不会随着输入的规模变化而变化。
  • O(n)O(n)O(n):表示算法的执行时间会随着输入规模的增大而线性增加。

当你遍历每个元素时,时间复杂度通常是 O(n)O(n)O(n),其中 nnn 是你遍历的元素个数。如果是常数操作,不依赖于输入大小,时间复杂度就是 O(1)O(1)O(1)。