234128 – Introduction to Computing with Python
Question 1: hw3q1.py
Write a function: find_index(L)
The function gets a list of integers as a parameter. The function returns an index such that the sum of elements at lower indexes is equal to the sum of elements at higher indexes. In other words, the function will return the index i which satisfies:
该函数以一个整数列表作为参数。该函数返回一个索引,使得较低索引处元素的总和等于较高索引处元素的总和。换句话说,该函数将返回满足以下条件的索引i:
𝐿[0] + 𝐿[1] + ⋯ + 𝐿[𝑖 − 1] = 𝐿[𝑖 + 1] + 𝐿[𝑖 + 2] + ⋯ + 𝐿[𝑛 − 2] + 𝐿[𝑛 − 1]
If more than one such index exists, return the leftmost one.
如果存在多个这样的索引,则返回最左边的一个。
If such index cannot be found, the function should return -1 (minus one).
如果找不到这样的索引,则该函数应返回-1。
Try to write efficient code without unnecessary loops and statements. Hint: The sum of all elements in the list is constant.
尝试编写高效的代码,避免不必要的循环和语句。提示:列表中所有元素的总和是恒定不变的。
Examples:
L | return explanation | explanation |
---|---|---|
[0,1,10,1] | 2 | 0+1 = 1 |
[6,1,4,1,9,0,2] | 3 | 6+1+4 = 9+0+2 |
[2,-1,2,1,3,-4] | 1 | 2 = 2+1+3-4 |
[6,5,3,2,1] | 1 | 6 = 3+2+1 |
[6,5,3,2] | -1 | No such index exists |
[0,0,0] | 0 | Return leftmost index, even though all satisfy the condition |
print(find_index([0, 1, 10, 1]))
print(find_index([6, 1, 4, 1, 9, 0, 2]))
print(find_index([2, -1, 2, 1, 3, -4]))
print(find_index([6, 5, 3, 2, 1]))
print(find_index([6, 5, 3, 2]))
print(find_index([0, 0, 0]))
这是一个涉及到列表操作的问题,我们要寻找到一个索引使得其左侧所有元素之和等于右侧所有元素之和。首先,我们可以先计算出列表所有元素的总和,然后从列表的左侧开始累加元素值,当某一刻,左侧累加的和的二倍加上当前元素值等于总和时,即找到了我们需要的索引。
以下是Python的实现:
def find_index(L):
total = sum(L)
left_sum = 0
for i in range(len(L)):
if left_sum * 2 + L[i] == total:
return i
left_sum += L[i]
return -1
在上述代码中,我们先计算出列表所有元素的总和total
,然后我们遍历列表,用left_sum
来累计左侧元素的和。遍历的过程中,如果left_sum * 2 + L[i]
等于总和,那么i
就是我们要找的索引。如果遍历结束都没找到满足条件的索引,我们就返回-1
。
这个题目的基本思路是要找到一个索引,使得该索引左侧所有元素的和等于右侧所有元素的和。一种直观的解法可能是遍历每个索引,并分别计算索引左侧和右侧的元素之和,然后比较这两个和是否相等。然而,这样做的时间复杂度是O(n^2),因为对每个索引,我们都要分别计算左侧和右侧的元素之和,这需要两个嵌套的循环。
我们可以使用一种更有效的解法。首先,我们可以计算出列表中所有元素的总和。然后,我们从左到右遍历列表,每次都计算到当前索引为止(包括当前索引)所有元素的和。如果当前索引左侧的元素之和的两倍加上当前索引的元素值等于总和,那么我们就找到了一个满足条件的索引。
具体地,假设列表中所有元素的总和为total
,当前索引为i
,到索引i
为止(包括i
)的所有元素之和为left_sum
。那么,索引i
右侧的所有元素之和就是total - left_sum
。因此,如果2 * left_sum + L[i] == total
,那么就说明left_sum == total - left_sum - L[i]
,即索引i
左侧的所有元素之和等于右侧所有元素之和。
这种解法的时间复杂度是O(n),其中n是列表的长度。这是因为我们只需要遍历列表两次:一次计算总和,一次寻找满足条件的索引。
In [1]: lst = [1, 2, 3, 4, 4, 3, 2, 1]
In [2]: # p = 0
In [3]: left_num = lst[:0]
In [4]: left_num
Out[4]: []
In [5]: lst = [1, 2, 3, 4, 4, 3, 2, 1]
In [6]: clear
In [7]: lst = [1, 2, 3, 4, 4, 3, 2, 1]
In [8]: left_num = sum(lst[:0])
In [9]: left_num
Out[9]: 0
In [10]: right_num = sum(lst[0:])
In [11]: left_num == right_num
Out[11]: False
In [12]: p = 1
In [13]: left_num = sum(lst[:p])
In [14]: left_num
Out[14]: 1
In [15]: right_num = sum(lst[p:])
In [16]: left_num == right_num
Out[16]: False
In [17]: p = 2
In [18]: left_num = sum(lst[:p])
In [19]: right_num = sum(lst[p:])
In [20]: left_num == right_num
Out[20]: False
In [21]: lst
Out[21]: [1, 2, 3, 4, 4, 3, 2, 1]
In [22]: p = 4
In [23]: left_num = sum(lst[:p])
In [24]: right_num = sum(lst[p:])
In [25]: left_num == right_num
Out[25]: True
In [26]: left_num = sum(lst[:p])
In [27]: right_num = sum(lst[p+1:])
In [29]: lst = [0, 1, 10, 1]
In [30]: left_num = sum(lst[:p])
In [31]: right_num = sum(lst[p+1:])
In [32]: left_num == right_num
Out[32]: False
In [33]: p = 2
In [34]: left_num = sum(lst[:p])
In [35]: right_num = sum(lst[p+1:])
In [36]: left_num == right_num
Out[36]: True
def find_index(L):
# 计算列表中所有元素的总和
total = sum(L)
# 初始化左侧元素之和为0
left_sum = 0
# 遍历列表中的每个元素
for i in range(len(L)):
# 检查左侧元素之和的两倍再加上当前元素是否等于总和
# 如果等于,那么就找到了满足条件的索引,返回该索引
if left_sum * 2 + L[i] == total:
return i
# 累加当前元素到左侧元素之和
left_sum += L[i]
# 如果遍历完所有元素都没有找到满足条件的索引,那么返回-1
return -1
当然可以。我们可以用一个简单的例子来理解这个问题。
假设我们有一个列表[1, 2, 3, 4, 10]
,我们需要找到一个索引,使得该索引左侧所有元素的和等于右侧所有元素的和。
根据题目的要求,我们先计算整个列表的总和,得到total = 20
。
然后我们从左到右遍历这个列表,计算到当前索引为止所有元素的和(left_sum
):
- 当
i = 0
时,left_sum = 1
,因为2 * 1 + 1 != 20
,所以i = 0
不是我们要找的索引。 - 当
i = 1
时,left_sum = 3
,因为2 * 3 + 2 != 20
,所以i = 1
也不是我们要找的索引。 - 当
i = 2
时,left_sum = 6
,因为2 * 6 + 3 != 20
,所以i = 2
还不是我们要找的索引。 - 当
i = 3
时,left_sum = 10
,我们发现2 * 10 + 4 = 20
,这个等式成立,所以i = 3
就是我们要找的索引。
所以在这个例子中,索引3
就是我们要找的答案,因为在这个索引位置上,左侧的所有元素之和(1+2+3=6)等于右侧所有元素之和(10)。
希望这个例子能帮助你理解这个问题。
这个乘2的原因在于我们试图找到一个位置,使得该位置左侧的所有元素之和等于右侧所有元素之和。假设我们正在考虑的索引是i
,left_sum
是从索引0到i-1
的所有元素之和,那么2*left_sum
就是左侧所有元素之和的两倍。
现在我们还要加上L[i]
,这是因为我们正在考虑的索引位置也是应该被考虑在内的。但是,我们只能将它考虑一半,因为我们想让这个位置的左侧所有元素的和等于右侧所有元素的和,如果完全把它计算在内,那么左边的和就会超过右边的和。因此,我们加上一半的L[i]
。
最后,如果2*left_sum + L[i]
等于所有元素的总和,那么这个等式两边实际上就是平衡的,左侧所有元素的和等于右侧所有元素的和。这就是为什么我们要乘以2的原因。
Question 2: hw3q2.py
Write a function: count_repeated(L)
The function gets a sorted list of integers as an input argument. The function counts the number of values which appear more than once and returns the result. Meaning, the returned value is the number of integers which appear more than one time.
该函数接收一个已排序的整数列表作为输入参数。该函数计算出出现多次的值的数量,并返回结果。也就是说,返回的值是出现超过一次的整数的数量。
Examples:
L | return | explanation |
---|---|---|
[1, 3, 3, 6, 6, 6, 7] | 5 | 6 appears 3 times 3 appears 2 times 3 + 2 = 5 |
[-2, -1, 0, 1, 2] | 0 | No repeats |
[1,1,1,2,3] | 3 | 1 appears 3 times |
[1,2,3,3,4,9,9,9,9] | 6 | 3 appears 2 times 9 appears 4 times 2 + 4 = 6 |
你的思路是对的,可以用Python的内置函数count
和set
来实现这个功能,不过由于count
函数也是通过循环实现的,所以实际上这种方法仍然涉及到循环。不过使用这种方法可以让代码更简洁。
def count_repeated(L):
return sum(L.count(i) for i in set(L) if L.count(i) > 1)
在这段代码中,首先使用set
函数将列表转化为集合,从而去除重复的元素。然后对于每个在集合中的元素,我们都计算它在原列表中出现的次数,如果次数大于1,那么就将这个次数加入到总和中。
但请注意,这段代码在实际执行时可能会比前面的代码更慢,因为对于集合中的每个元素,我们都要在列表中搜索它出现的次数,这个搜索过程的时间复杂度是O(n)。所以总的时间复杂度是O(n^2)。而前面的代码只需要遍历一次列表,所以时间复杂度是O(n)。在列表很大的情况下,前面的代码可能会更快。
这个问题的基本思路是遍历整个列表,并对每个元素进行计数。当遇到一个新的元素时,检查上一个元素的计数值,如果计数值大于1,说明上一个元素是重复的,那么将计数值加到一个累积变量中。最后,返回这个累积变量的值。
注意:因为输入的列表是已排序的,所以当我们遍历到一个新的元素时,可以确定我们不会再看到上一个元素,所以这时就可以检查上一个元素的计数值。
以下是一个使用Python实现的函数:
def count_repeated(L):
# 初始化累积变量和计数值
total_count = 0
current_count = 0
current_num = None
# 遍历整个列表
for num in L:
if num != current_num:
# 当遇到一个新的元素时,检查上一个元素的计数值
if current_count > 1:
# 如果计数值大于1,说明上一个元素是重复的
# 那么将计数值加到累积变量中
total_count += current_count
# 更新当前元素和当前计数值
current_num = num
current_count = 1
else:
# 如果当前元素和上一个元素相同,那么增加计数值
current_count += 1
# 检查最后一个元素的计数值
if current_count > 1:
total_count += current_count
return total_count
希望这个函数能满足你的需求。
Question 3: hw3q3.py
Part A:
Write a function: count_upper(s)
The function gets as a parameter a string. The function returns as a result the number of uppercase letters in the string.
Requirement: string methods are NOT allowed.
编写一个函数:
count_upper(s)
该函数的参数为一个字符串。函数的返回结果是该字符串中大写字母的数量。
要求:不允许使用字符串方法。
def count_upper(s):
count = 0
for char in s:
if 65 <= ord(char) <= 90:
count += 1
return count
Part B:
Write a function: count_lower(s)
The function gets as a parameter a string. The function returns as a result the number of lowercase letters in the string.
Requirement: string methods are NOT allowed.
编写一个函数:
count_lower(s)
该函数的参数为一个字符串。该函数将返回该字符串中小写字母的数量。
要求:不允许使用字符串方法。
def count_lower(s):
count = 0
for char in s:
if 97 <= ord(char) <= 122:
count += 1
return count
Part C:
Write a function: is_balanced(s)
The function gets a string s as parameter. The function returns True if the number of uppercase letters equals to number of lowercase letters. Such string will be called balanced.
The function ignores everything except English characters.
Use Top-Down design as we’ve seen in class.
编写一个函数:
is_balanced(s)
该函数的参数为一个字符串
s
。如果该字符串中大写字母的数量等于小写字母的数量,则该函数返回True。这样的字符串将被称为平衡的。该函数忽略除英文字母以外的所有内容。
请使用我们在课堂上学到的自顶向下设计方法。
Answer
要编写一个名为 is_balanced(s)
的函数,这个函数接收一个字符串 s
作为参数。如果字符串中的大写字母数量等于小写字母的数量,那么函数返回 True,我们称这样的字符串为“平衡”的。
这个函数会忽略除了英文字符以外的所有其他内容。
我们可以使用自顶向下的设计方法,如我们在课堂上学过的。这意味着我们将问题分解为更小的子问题,然后为每个子问题编写函数。
首先,我们需要一个函数来计算大写字母的数量,我们已经有了 count_upper(s)
,然后我们需要一个类似的函数来计算小写字母的数量,我们也已经有了 count_lower(s)
。
然后,我们可以将这两个函数组合起来,以检查字符串是否“平衡”。
以下是这个 is_balanced(s)
函数的代码:
def count_upper(s):
count = 0
for char in s:
if 65 <= ord(char) <= 90:
count += 1
return count
def count_lower(s):
count = 0
for char in s:
if 97 <= ord(char) <= 122:
count += 1
return count
def is_balanced(s):
return count_upper(s) == count_lower(s)
在 is_balanced(s)
函数中,我们调用了 count_upper(s)
和 count_lower(s)
函数,然后检查它们的结果是否相等。如果相等,那么我们返回 True,表示字符串是“平衡”的。否则,我们返回 False。
什么是自顶向下设计方法?
自顶向下的设计方法(Top-Down design),也被称为分步精化法或者分解法,是一种常用的问题解决和编程方法论。
在自顶向下设计中,我们首先从最抽象的高级任务开始,然后将其分解为更具体的子任务。我们重复这个过程,直到子任务足够简单,可以直接通过编程语言实现。
举个例子,如果我们要设计一个计算机程序来管理一家图书馆,我们可能会从“管理图书馆”这个高级任务开始。然后,我们可以将其分解为几个子任务,例如“管理图书”和“管理借书卡”。然后,我们再将这些子任务分解为更具体的任务,例如“添加新书”、“删除旧书”、“发行新卡”和“注销旧卡”。我们会一直进行这个过程,直到我们得到可以直接用编程语言实现的简单任务。
在编程中,自顶向下设计方法有助于我们组织和管理复杂的问题,使我们能够在更高的抽象级别进行思考,并在适当的时候深入到具体的实现细节中。
Part D:
Write a program as follows:
The program gets as input an infinite sequence of strings, one after the other. Each string will be accepted by pressing <enter>
after typing it. When an empty string is given, this marks the end of input (stops the loop).
The program checks if there are balanced strings in the input.
If yes, the program prints: “xxx is balanced.” where xxx is the string.
If no, the program prints: “xxx is unbalanced.” where xxx is the string.
Each printed message is in a separate line. See attached example (q3in/q3out).
Note:
- All parts of the question should be in the file hw3q3.py.
- The last empty string shouldn’t be checked. It only marks end of input.
编写一个程序,具体如下:
该程序的输入为无限序列的字符串,每个字符串之间用
<enter>
键分隔。当输入一个空字符串时,表示输入结束(停止循环)。该程序检查输入中是否有平衡的字符串。
如果有,则程序打印:“xxx is balanced.”,其中xxx是字符串。
如果没有,则程序打印:“xxx is unbalanced.”,其中xxx是字符串。
每个打印的信息都在单独的一行中。请参见附带的示例(q3in / q3out)。
注意:
- 问题的所有部分都应在文件hw3q3.py中。
- 最后一个空字符串不应被检查。它只表示输入结束。
Answer
要编写一个程序,按照下述规则运行:
程序会不断地接收字符串输入,每输入一个字符串按下<enter>
键确认。当输入空字符串时,标志着输入结束,停止循环。
程序需要检查输入的字符串是否为“平衡”字符串。
如果是,“平衡”的字符串,程序输出:“xxx is balanced.” 其中xxx是输入的字符串。
如果不是,“平衡”的字符串,程序输出:“xxx is unbalanced.” 其中xxx是输入的字符串。
每个打印的信息都在单独的一行。具体请参见附件示例 (q3in/q3out)。
注意:
- 所有的问题部分都应该在 hw3q3.py 文件中。
- 最后的空字符串不应被检查。它只标志着输入的结束。
基于这些信息,以下是 Python 程序的代码:
def count_upper(s):
count = 0
for char in s:
if 65 <= ord(char) <= 90:
count += 1
return count
def count_lower(s):
count = 0
for char in s:
if 97 <= ord(char) <= 122:
count += 1
return count
def is_balanced(s):
return count_upper(s) == count_lower(s)
def main():
while True:
s = input()
if s == "":
break
elif is_balanced(s):
print(f"{s} is balanced.")
else:
print(f"{s} is unbalanced.")
if __name__ == "__main__":
main()
在这个程序中,我们首先定义了 count_upper(s)
,count_lower(s)
,和 is_balanced(s)
函数。然后我们定义了 main()
函数,该函数负责循环接收用户输入,检查每个字符串是否平衡,并打印相应的消息。如果用户输入了一个空字符串,那么程序将结束。最后,我们检查是否直接运行了这个 Python 文件(而不是将其作为模块导入),如果是的话,我们就调用 main()
函数,开始程序的运行。
设计并实现一个 Python 程序,它接受一行字符串作为输入。字符串只包含括号字符,如 "(", ")", "[", "]", "{", "}"。我们将认为一个字符串是“良好”的,如果它的括号是正确匹配的。
括号匹配的规则如下:
- 对于每个 ")", "[", 或 "}",其左边必须有对应的 "(", "]", 或 "{",且在它们之间没有其他的未匹配括号。
- 对于每个 "(", "[", 或 "{",其右边必须有对应的 ")", "]", 或 "}",且在它们之间没有其他的未匹配括号。
例如,以下字符串是“良好”的:
- ""
- "()"
- "[]"
- "{}"
- "([])"
- "[(){}]"
- "({[]})"
以下字符串不是“良好”的:
- "("
- "["
- "{"
- "([)]"
- "[(])"
- "{[}]"
程序应该输出 "The input string is well-formed." 如果输入字符串是“良好”的,否则,程序应该输出 "The input string is not well-formed."。
使用栈(stack)数据结构可以有效地解决这个问题。
注意:
- 输入字符串只包含括号字符。
- 所有的问题部分都应该在 hw5.py 文件中。
- 程序应当忽略空字符串输入,只有当输入 "exit" 时,程序应停止执行。
def is_well_formed(s):
# 创建一个字典来存储括号的配对
matches = {')': '(', ']': '[', '}': '{'}
# 创建一个空栈来存储开括号
stack = []
# 遍历输入字符串中的每个字符
for char in s:
# 如果字符是开括号,那么将其入栈
if char in matches.values():
stack.append(char)
# 如果字符是闭括号
elif char in matches.keys():
# 如果栈已经为空,或者栈顶的开括号与当前的闭括号不匹配,那么字符串不是“良好”的
if not stack or matches[char] != stack.pop():
return False
# 如果栈为空,那么所有的括号都被正确地匹配了,所以字符串是“良好”的
return not stack
def main():
while True:
s = input()
if s == "exit":
break
elif is_well_formed(s):
print("The input string is well-formed.")
else:
print("The input string is not well-formed.")
if __name__ == "__main__":
main()
以下是一些涵盖 Python 基础字符串概念的编程问题:
反转字符串: 编写一个函数,接受一个字符串,并返回反向的字符串。例如,输入 "hello",输出 "olleh"。
计算字符频率: 编写一个函数,接受一个字符串,并返回一个字典,字典的键是字符串中的唯一字符,值是字符在字符串中出现的次数。例如,输入 "hello",输出 {"h": 1, "e": 1, "l": 2, "o": 1}。
检查字符串是否是回文: 编写一个函数,接受一个字符串,并检查它是否是回文(也就是说,它正读和反读都一样)。例如,输入 "level",输出 True;输入 "hello",输出 False。
找到最长的单词: 编写一个函数,接受一个由空格分隔的字符串(一个句子),并返回最长的单词以及其长度。例如,输入 "I love programming in Python",输出 ("programming", 11)。
字母排序: 编写一个函数,接受一个字符串,并返回一个包含同样字符但按字母顺序排列的字符串。例如,输入 "python",输出 "hnopty"。
这些问题涵盖了字符串操作的各种基础概念,包括索引、切片、字符串的不可变性、字符串方法如 split()
和 join()
,以及使用字符串与其他数据类型(如列表和字典)进行交互的方法。
以下是上述问题的 Python 程序实现:
- 反转字符串:
def reverse_string(s):
return s[::-1]
print(reverse_string("hello")) # 输出: "olleh"
- 计算字符频率:
def char_frequency(s):
frequency = {}
for char in s:
if char in frequency:
frequency[char] += 1
else:
frequency[char] = 1
return frequency
print(char_frequency("hello")) # 输出: {"h": 1, "e": 1, "l": 2, "o": 1}
- 检查字符串是否是回文:
def is_palindrome(s):
return s == s[::-1]
print(is_palindrome("level")) # 输出: True
print(is_palindrome("hello")) # 输出: False
- 找到最长的单词:
def longest_word(s):
words = s.split()
longest = max(words, key=len)
return longest, len(longest)
print(longest_word("I love programming in Python")) # 输出: ("programming", 11)
- 字母排序:
def alphabet_sort(s):
return ''.join(sorted(s))
print(alphabet_sort("python")) # 输出: "hnopty"
以上每个程序中的函数都实现了一个具体的功能,然后通过 print()
函数来测试这个函数的功能。
公众号:AI悦创【二维码】

AI悦创·编程一对一
AI悦创·推出辅导班啦,包括「Python 语言辅导班、C++ 辅导班、java 辅导班、算法/数据结构辅导班、少儿编程、pygame 游戏开发、Web、Linux」,全部都是一对一教学:一对一辅导 + 一对一答疑 + 布置作业 + 项目实践等。当然,还有线下线上摄影课程、Photoshop、Premiere 一对一教学、QQ、微信在线,随时响应!微信:Jiabcdefh
C++ 信息奥赛题解,长期更新!长期招收一对一中小学信息奥赛集训,莆田、厦门地区有机会线下上门,其他地区线上。微信:Jiabcdefh
方法一:QQ
方法二:微信:Jiabcdefh
