AcWing 0x01. 语法基础课【Python3】版题解-内置数据结构/字符串

AcWing语法基础课【Python3】版题解-内置数据结构/字符串

【AcWing】

【AcWing 语法基础课】

【AcWing 0x00. 语法基础课【Python3】版题解-顺序/判断/循环语句】

【AcWing 0x01. 语法基础课【Python3】版题解-内置数据结构/字符串】

【AcWing 0x02. 语法基础课【Python3】版题解-函数/类和对象/常用库】

列表、元组、字典、集合、数组

例题

【AcWing 737. 数组替换】

X = [int(input()) for i in range(10)]
for i in range(10):
    print(f"X[{i}] = {X[i] if X[i] > 0 else 1}")

解析:先生成列表X,再用三目运算符把非正整数全部替换为1。

X = []
for i in range(10):
    y = int(input())
    X.append(y if y > 0 else 1)
    print(f"X[{i}] = {X[i]}")

解析:在线处理,上下两个代码仅仅是有无使用list的区别。

for i in range(10):
    y = int(input())
    y = y if y > 0 else 1
    print(f"X[{i}] = {y}")

使用array标准库:

import array
X = array.array('b')
for i in range(10):
    y = int(input())
    X.append(y if y > 0 else 1)
    print(f"X[{i}] = {X[i]}")

解析:array仅在创建时和列表不同,需要指定数据类型。

使用匿名表达式:

X = [int(input()) for i in range(10)]
Y = list(map(lambda y: y if y > 0 else 1, X))

for i in range(10):
    print(f"X[{i}] = {Y[i]}")

解析:创建两个列表,第一个列表接受输入值,第二个列表通过一个 map() 把输入值映射为题示输出值,其中映射规则“非正整数全部替换为1”使用匿名表达式实现。

【AcWing 738. 数组填充】

V = int(input())
N = [V * 2 ** i for i in range(10)]
for i in range(10):
    print(f"N[{i}] = {N[i]}")

解析:列表推导式即可,在线处理和上一题一样,略。

【AcWing 739. 数组选择】

A = [float(input()) for i in range(100)]
for i in range(100):
    if A[i] <= 10:
        print(f"A[{i}] = {A[i]}")

解析:列表推导式处理输入数据即可,在线处理和上一题一样,略。

【AcWing 743. 数组中的行】

L = int(input())
K = input()
matrix = [list(map(float, input().split())) for i in range(12)]
if K == "S":
    print(f"{sum(matrix[L]):.1f}")
else:
    print(f"{sum(matrix[L]) / len(matrix[L]):.1f}")

解析:通过列表解析生成矩阵,对于 N × N N\times N N×N的矩阵,用for循环生成N行,用list(mapfloat, input().split()))把这一行输入的数据转变成浮点数列表。

【AcWing 745. 数组的右上半部分】

K = input()
matrix = [list(map(float, input().split())) for i in range(12)]
Sum = 0
for i in range(11):
    Sum += sum(matrix[i][i+1:12])
    # 等价于 Sum += sum(matrix[i][i+1:])
if K == "S":
    print(f"{Sum:.1f}")
else:
    print(f"{Sum / 66:.1f}")

解析:列表切片list[a:b]返回列表下标从a到b的值,注意是左闭右开,只取到b的前一个之值而不包括b。

【AcWing 747. 数组的左上半部分】

K = input()
matrix = [list(map(float, input().split())) for i in range(12)]
Sum = 0
for i in range(11):
    Sum += sum(matrix[i][0:12-i-1])
    # 等价于 Sum += sum(matrix[i][:12-i-1])
if K == "S":
    print(f"{Sum:.1f}")
else:
    print(f"{Sum / 66:.1f}")

解析:和上一题一样,只是切片区域改变。

【AcWing 749. 数组的上方区域】

K = input()
matrix = [list(map(float, input().split())) for i in range(12)]
Sum = 0
for i in range(5):
    Sum += sum(matrix[i][i+1:12-i-1])
if K == "S":
    print(f"{Sum:.1f}")
else:
    print(f"{Sum / 30:.1f}")

解析:和上一题一样,只是切片区域改变。

【AcWing 751. 数组的左方区域】

K = input()
matrix = [list(map(float, input().split())) for i in range(12)]
Sum = 0
for i in range(5):
    Sum += sum(matrix[i+1][:i+1])
for i in range(5):
    Sum += sum(matrix[i+6][:5-i])
if K == "S":
    print(f"{Sum:.1f}")
else:
    print(f"{Sum / 30:.1f}")

解析:和上一题一样,只是切片区域改变。

【AcWing 753. 平方矩阵 I】

def edgePadding(n, m, matrix):
    if 2 * m - 1 == n:
        matrix[m-1][m-1] = m
        return
    elif 2 * m == n:
        matrix[m-1][m-1:m+1] = matrix[m][m-1:m+1] = [m, m]
        return
    else:
        edgePadding(n, m + 1, matrix)
        length = n - 2 * (m - 1)
        matrix[m-1][m-1:m+length-1] = [m for i in range(length)]
        matrix[m+length-2][m-1:m+length-1] = [m for i in range(length)]
        for row in matrix[m-1:m+length-1]:
            row[m-1] = row[m+length-2] = m
    

while True:
    N = int(input())
    if N == 0:
        break
    else:
        matrix = [[0 for i in range(N)] for i in range(N)]
        edgePadding(N, 1, matrix)
        for row in matrix:
            for col in row:
                print(col, end=" ")
            print()
        print()

解析:记最外层为第一圈,次外层为第二圈,第三层为第三圈…以此类推,递归填充当前递归层数对应的圈,递归到第一层时,把第一圈全填为1,递归到第二层时,把第二圈全填为2…

递归边界需要分奇偶两种情况,当n为奇数时,递归边界为 2 * m - 1 == n ;当n为偶数时,递归边界为 2 * m == n

二维列表切片只能取整行,若要取取整列,则需要使用for循环,在循环中迭代取出每一行,再取出每一行中那一列的元素。以取第二列为例:

for row in matrix:
    print(row[1])

这道题也可以通过观察规律的方法求解:

记每次输入的整数为n,则最内层的数一定是 k = n / 2
打印不同对的n和k的矩阵坐标,寻找规律:

n=3,k=2
1 1 1
1 2 1
1 1 1
(1, 1) (1, 2) (1, 3) 

(2, 1) (2, 2) (2, 3) 

(3, 1) (3, 2) (3, 3)
n=4,k=2
1 1 1 1
1 2 2 1
1 2 2 1
1 1 1 1
(1, 1) (1, 2) (1, 3) (1, 4) 

(2, 1) (2, 2) (2, 3) (2, 4) 

(3, 1) (3, 2) (3, 3) (3, 4) 

(4, 1) (4, 2) (4, 3) (4, 4)
n=5,k=3
1 1 1 1 1
1 2 2 2 1
1 2 3 2 1
1 2 2 2 1
1 1 1 1 1
(1, 1) (1, 2) (1, 3) (1, 4) (1, 5) 

(2, 1) (2, 2) (2, 3) (2, 4) (2, 5) 

(3, 1) (3, 2) (3, 3) (3, 4) (3, 5) 

(4, 1) (4, 2) (4, 3) (4, 4) (4, 5) 

(5, 1) (5, 2) (5, 3) (5, 4) (5, 5)

观察发现,数和坐标的关系为,沿着矩阵的左下角到右上角这条对角线,上方的数一定是坐标中较小的那个数,下方图形则是上方图形沿对角线翻折而得到的,因此只要求出对角线上方的半个矩阵,就可以得到完整矩阵。

代码:

while True:
    n = int(input())
    if n == 0:
        break;
    for i in range(1, n + 1):
        for j in range(1, n + 1):
            if i + j < n + 2:
                print(min(i, j), end=" ")
            else:
                d = i + j - (n + 1)
                print(min(i - d, j - d), end=" ")
        print()
    print()

【AcWing 3592. 矩阵转置】

N = int(input())
matrix = [list(map(int, input().split())) for i in range(N)]

for j in range(N):
    for row in matrix:
        print(row[j], end=" ")
    print()

解析:

  1. 先通过列表解析生成矩阵,对于 N × N N\times N N×N的矩阵,用for循环生成N行,用list(map(int, input().split()))把这一行输入的数据转变成整数列表。
  2. 然后通过双重循环输出在线(原地)转置,对于N列,输出每行的第j个元素。

这道题如果不限制不能使用额外数组,则Python3里通过列表解析可以快速生成一个矩阵(嵌套列表)的转置:

N = int(input())
matrix = [list(map(int, input().split())) for i in range(N)]
matrix_T = [[row[j] for row in matrix] for j in range(N)]

for i in range(N):
    for j in range(N):
        print(matrix_T[i][j], end=" ")
    print()

解析:官方文档【5.1.4. 嵌套的列表推导式】对此有详细讲解。

也可以使用Python3内置的zip(*iterables, strict=False)函数:

N = int(input())
matrix = [list(map(int, input().split())) for i in range(N)]
matrix_T = list(zip(*matrix))

for i in range(N):
    for j in range(N):
        print(matrix_T[i][j], end=" ")
    print()

解析:参考官方文档【内置函数zip】,zip() 返回元组的迭代器,其中第i个元组包含的是每个参数迭代器的第i个元素,它会把行变成列,把列变成行。这类似于矩阵转置。

习题

【AcWing 740. 数组变换】

M = [int(input()) for i in range(20)]
N = [M[20-i-1] for i in range(20)]
for i in range(20):
    print(f"N[{i}] = {N[i]}")

解析:第一种方法是新开一个数组,倒着把原数组的元素放到新数组里去,然后在输出新数组。

原地反转的方法是:

N = [int(input()) for i in range(20)]
for i in range(10):
    N[i], N[20-i-1] = N[20-i-1], N[i]
for i in range(20):
    print(f"N[{i}] = {N[i]}")

解析:原地反转是通过交换下标相加为列表长度加1的两个元素的值实现的。

这道题最简便是使用列表的reverse()方法来做:

N = [int(input()) for i in range(20)]
N.reverse()
for i in range(20):
    print(f"N[{i}] = {N[i]}")

解析:列表的reverse()方法把列表元素反转。

也可以使用列表切片的方法来做:

N0 = [int(input()) for i in range(20)]
N = N0[::-1]
for i in range(20):
    print(f"N[{i}] = {N[i]}")

解析:列表[::n]的含义是每n个元素取一个,[::2] 是每两个元素取一个的操作,其实就是隔一个取一个元素;[::-1]等价于反转操作。

【AcWing 742. 最小数和它的位置】

N = int(input())
X = list(map(int, input().split()))
print(f"Minimum value: {min(X)}")
print(f"Position: {X.index(min(X))}")

解析:使用min()函数求列表最小值,使用index()方法求列表指定元素的下标。

如果不使用内置函数或方法做这道题:

N = int(input())
X = list(map(int, input().split()))
min = X[0]
pos = 0
for i in range(N):
    if min > X[i]:
        min = X[i]
        pos = i
print(f"Minimum value: {min}")
print(f"Position: {pos}")

解析:for循环遍历列表,如果当前值小于最小值,则更新最小值及其位置。

【AcWing 744. 数组中的列】

C = int(input())
K = input()
M = [list(map(float, input().split())) for i in range(12)]
Sum = 0
for row in M:
    Sum += row[C]
if K == "S":
    print(f"{Sum:.1f}")
else:
    print(f"{Sum/12:.1f}")

解析:矩阵是嵌套列表,单次for循环迭代的是外层列表,元素是内层列表。

【AcWing 748. 数组的右下半部分】

K = input()
M = [list(map(float, input().split())) for i in range(12)]
Sum = 0
for i in range(1, 12):
    Sum += sum(M[i][12-i:])
if K == "S":
    print(f"{Sum:.1f}")
else:
    print(f"{Sum / 66:.1f}")

解析:找准切片位置,加到总和里即可,注意列表切片是左闭右开的。

【AcWing 746. 数组的左下半部分】

K = input()
M = [list(map(float, input().split())) for i in range(12)]
Sum = 0
for i in range(1, 12):
    Sum += sum(M[i][:i])
if K == "S":
    print(f"{Sum:.1f}")
else:
    print(f"{Sum / 66:.1f}")

解析:和上一题一样,只是切片区域改变。

【AcWing 750. 数组的下方区域】

K = input()
M = [list(map(float, input().split())) for i in range(12)]
Sum = 0
for i in range(7, 12):
    Sum += sum(M[i][12-i:i])
if K == "S":
    print(f"{Sum:.1f}")
else:
    print(f"{Sum / 30:.1f}")

解析:和上一题一样,只是切片区域改变。

【AcWing 752. 数组的右方区域】

K = input()
M = [list(map(float, input().split())) for i in range(12)]
Sum = 0
for i in range(5):
    Sum += sum(M[i+1][11-i:])
for i in range(5):
    Sum += sum(M[i+6][i+7:])
if K == "S":
    print(f"{Sum:.1f}")
else:
    print(f"{Sum / 30:.1f}")

解析:和上一题一样,只是切片区域改变。

【AcWing 754. 平方矩阵II】

while True:
    N = int(input())
    if N == 0:
        break
    else:
        matrix = [[0 for i in range(N)] for j in range(N)]
    for i in range(N):
        for j in range(N - i):
            matrix[j+i][i] = j+1
            matrix[i][j+i] = j+1
    for row in matrix:
        for col in row:
            print(col, end=" ")
        print()
    print()

解析:从主对角线开始依次向上向下遍历其余对角线并填充数字即可。

【AcWing 755. 平方矩阵III】

while True:
    N = int(input())
    if N == 0:
        break
    else:
        matrix = [[2 ** (i + j) for i in range(N)] for j in range(N)]
    for row in matrix:
        for col in row:
            print(col, end=" ")
        print()
    print()

解析:根据题意直接使用列表推导式即可。

【AcWing 756. 蛇形矩阵】

n, m = map(int, input().split())
matrix = [[0 for i in range(m)] for j in range(n)]
# "up": (-1, 0), "right": (0, 1), "down": (1, 0), "left": (0, -1)
directions = [(-1, 0), (0, 1), (1, 0), (0, -1)]
x, y, dire = 0, 0, 1
for i in range(n * m):
    matrix[x][y] = i + 1
    x0, y0 = x + directions[dire][0], y + directions[dire][1]
    if x0 < 0 or x0 >= n or y0 < 0 or y0 >= m or matrix[x0][y0] > 0:
        dire = (dire + 1) % 4
        x0, y0 = x + directions[dire][0], y + directions[dire][1]
    x, y = x0, y0
    
for row in matrix:
    for col in row:
        print(col, end=" ")
    print()

解析:先创建一个全0的n行m列矩阵,然后按照题示路径遍历矩阵并把当前矩阵元素改为遍历到的索引。遍历时,右左移动列坐标加减1,行坐标不变;上下移动行坐标加减1,列坐标不变,记 (dx, dy) 为行,列坐标的增量元组,则上下左右移动对应的元组为 "up": (-1, 0), "right": (0, 1), "down": (1, 0), "left": (0, -1) 。令 dire 的值分别对应 0: "up", 1: "right", 2: "down", 3: "left" ,则每次走到边界或走到已经标记过的地方时,移动方向顺时针转向90°,记为 dire = (dire + 1) % 4 ,且在上一步位置重新走一次,如此遍历即可。

n, m = map(int, input().split())
arr = [[0 for i in range(m)] for j in range(n)]

# d是方向,0,1,2,3分别代表右、下、左、上
# x和y是当前位置的行和列的坐标
d = x = y = 0

# 从初始坐标出发
for i in range(1, n * m + 1):
    arr[x][y] = i
    
    # 现在向右走
    if d == 0 and x < n and y < m:
        # 如果到达右边界或者下一个位置已经被填充
        if y + 1 >= m or (y + 1 < m and arr[x][y + 1] != 0):
            d = (d + 1) % 4 # 改变方向
            x += 1
        else: # 继续向右走
            y += 1
            
    # 现在向下走
    elif d == 1 and x < n and y < m:
        # 如果到达下边界或者下一个位置已经被填充
        if x + 1 >= n or (x + 1 < n and arr[x + 1][y] != 0):
            d = (d + 1) % 4
            y -= 1
        else: # 继续向下走
            x += 1
            
    # 现在向左走
    elif d == 2 and x < n and y >= 0:
        # 如果到达左边界或者下一个位置已经被填充
        if y - 1 < 0 or arr[x][y - 1] != 0:
            d = (d + 1) % 4
            x -= 1
        else: # 继续向左走
            y -= 1
            
    # 现在向上走
    elif d == 3 and x >= 0 and y < m:
        # 如果到达上边界或者下一个位置已经被填充
        if x - 1 < 0 or arr[x - 1][y] != 0:
            d = (d + 1) % 4
            y += 1
        else: # 继续向上走
            x -= 1
            
for row in arr:
    for col in row:
        print(col, end=" ")
    print()

解析:由题意,从初始位置开始模拟走法,开始先向右走,每当遇到边界或下一个位置已被填充的时候就改变前进方向,前进方向依次为右、下、左、上,直到走到尽头

字符串

例题

【AcWing 760. 字符串长度】

str = input()
print(len(str))

解析:直接使用Python3内置函数len()求字符串长度。

【AcWing 761. 字符串中的数字个数】

str = input()
conut = 0
for s in str:
    if s.isdigit():
        conut += 1
print(conut)

解析:使用字符串的isdigit()方法判断字符串是否只由数字组成。

【AcWing 763. 循环相克令】

T = int(input())

def Judge(s):
    flag = 2
    if s[0] == s[1]:
        flag = 0
    elif s[0] == "Hunter" and s[1] =="Gun":
        flag = 1
    elif s[0] == "Gun" and s[1] == "Bear":
        flag = 1
    elif s[0] == "Bear" and s[1] =="Hunter":
        flag = 1
    return flag
    
def Result(flag):
    if flag == 0:
        print("Tie")
    elif flag == 1:
        print("Player1")
    else:
        print("Player2")
        
while T:
    s = input().split()
    Result(Judge(s))
    T -= 1

解析:直接模拟即可。

更简单的方法是:

T = int(input())
winner = {"Hunter": "Gun", "Gun": "Bear", "Bear": "Hunter"}
while T:
    s = input().split()
    if s[0] == s[1]:
        print("Tie")
    elif s[1] == winner[s[0]]:
        print("Player1")
    else:
        print("Player2")
    T -= 1

解析:用字典保存赢的顺序,然后对字符串列表索引判断。

【AcWing 765. 字符串加空格】

s = list(input())
print(' '.join(s))

解析:先把输入的字符串强制转换为列表,再调用 join() 方法, join() 方法用于将序列中的元素以指定的字符连接生成一个新的字符串。

【AcWing 769. 替换字符】

str = input()
s = input()
print(str.replace(s, '#'))

解析:replace(old, new) 方法把字符串中的 old(旧字符串) 替换成 new(新字符串),如果指定第三个参数max,则替换不超过 max 次。

【AcWing 773. 字符串插入】

while True:
    try:
        Input = input().split()
        m = max(Input[0])
        strlist = list(Input[0])
        for i in range(len(strlist)):
            if strlist[i] == m:
                strlist.insert(i + 1, Input[1])
                break
        print(''.join(strlist))
    except:
        break

解析:用max()函数找到str 中 ASCII 码最大的那个字符,再用insert() 方法把substr 插入到该字符后面。

另一种模拟文件读入的方法是使用sys库,可参考【AcWing 773. python七行解决】

【AcWing 772. 只出现一次的字符】

str = input()
flag = 1
for s in str:
    if str.count(s) == 1:
        print(s)
        flag = 0
        break
if flag == 1:
    print("no")

注:这种方法(暴力)理论可行,但提交后会Time Limit Exceeded,因为这个算法在遇到长字符串的时候需要时间太长。

str = input()
dic = {}
flag = 1
for s in str:
    if s in dic:
        dic[s] +=1
    else:
        dic[s] = 1
for s in str:
    if dic[s] == 1:
        print(s)
        flag = 0
        break
if flag:
    print("no")

解析:使用字典来计数字符出现的次数,计数完后查找字符串中只出现一次的字符并输出。

习题

【AcWing 762. 字符串匹配】

proportion = float(input())
s1 = input()
s2 = input()
length = len(s1)
count = 0
for i in range(length):
    if s1[i] == s2[i]:
        count += 1
if count/length >= proportion:
    print("yes")
else:
    print("no")

解析:直接遍历对比即可。

【AcWing 768. 忽略大小写比较字符串大小】

s1 = input().lower()
s2 = input().lower()
if s1 < s2:
    print('<')
elif s1 > s2:
    print('>')
else:
    print('=')

解析:使用字符串对象的lower()方法把输入的字符串改为全部小写再比较。

【AcWing 766. 去掉多余的空格】

str = input().split()
for i in range(len(str)):
    print(str[i]+' ',end='')

解析:

  1. 先把输入的字符串按空格分割成列表,然后再遍历并输出列表元素,同时输出单个空格。
  2. print()函数不换行的方法是指定print()函数中参数end为空。
  3. 注意这里行末有空格,本题没卡行末空格,但有的题可能会卡行末空格(即输出的行的末尾不允许有空格)。

更简单的方法是:

str = input().split()
print(' '.join(str))

解析:先把输入字符串按空格分割成列表,然后再调用 join() 方法, join() 方法用于将序列中的元素以指定的字符连接生成一个新的字符串。

【AcWing 767. 信息加密】

strlist = list(input())
for s in strlist:
    num = ord(s)
    if (num >= 65 and num < 90) or (num >= 97 and num < 122):
        s = chr(num+1)
    elif num == 90 or num == 122:
        s = chr((num+1)-26)
    print(s,end="")

解析:Python3的两个内置函数,chr()函数和ord()函数的用法。chr()函数用一个范围在range(256)内的(就是0~255)整数作参数,返回一个对应的字符;ord()函数接受一个字符作参数,并返回一个范围在range(256)内的整数。

【AcWing 764. 输出字符串】

a = input()
b = []
for i in range(len(a)-1):
    b.append(chr(ord(a[i])+ord(a[i+1])))
b.append(chr(ord(a[len(a)-1])+ord(a[0])))
print(''.join(b))

解析:Python3的两个内置函数,chr()函数和ord()函数的用法。

【AcWing 770. 单词替换】

strlist = input().split()
old = input()
new = input()
list = [new if s == old else s for s in strlist]
print(' '.join(list))

解析:用带三目运算符的列表推导式生成一个替换过后的字符串列表然后再输出。

【AcWing 771. 字符串中最长的连续出现的字符】

N = int(input())
for i in range(N):
    str = input() + "."
    max = ("", 0)
    char = str[0]
    count = 0
    for s in str:
        if s == char:
            count += 1
        else:
            if count > max[1]:
                max = (char, count)
            char = s
            count = 1
    print(f"{max[0]} {max[1]}")

解析:对字符串最后加上一个"."表示结尾,然后遍历字符串,在连续字符结束时判断是否需要更新最长字符。

【AcWing 774. 最长单词】

strlist = input().strip(".").split()
dic = {}
for s in strlist:
    if s in dic:
        pass
    else:
        dic[s] = len(s)
max = ("", 0)
for i in dic.items():
    if max[1] < i[1]:
        max = i
print(max[0])

解析:先用strip()方法删除开始或结尾的".",然后遍历字符串列表,把单词和对应长度填入字典中,再遍历字典找出长度最长的单词。字典的items()方法返回的是可遍历的(键, 值) 元组数组。

这道题可以优化为单循环:

strlist = input().strip(".").split()
max = ("", 0)
for s in strlist:
    l = len(s)
    if max[1] < l:
        max = (s, l)
print(max[0])

【AcWing 775. 倒排单词】

strlist = input().split()
strlist.reverse()
print(" ".join(strlist))

解析:转化为Python3列表反转问题即可。

【AcWing 776. 字符串移位包含问题】

s1, s2 = input().split()
if len(s1) < len(s2):
    s1, s2 = s2, s1
length = len(s1)
flag = False
for i in range(length):
    j = i
    for s in s2:
        if s1[j % length] == s:
            flag = True
        else:
            flag = False
            break
        j += 1
    if flag == True:
        print("true")
        break
if flag == False:
    print("false")

解析:先判断 s 1 s_1 s1 s 2 s_2 s2 哪个短,并把短的作为子串。用取模运算模拟一个循环队列,遍历循环队列的每一项并判断短的字符串是不是从该项开始的子串。模拟循环队列也可以不使用取模运算,而是把长字符串复制一遍也可。

【AcWing 777. 字符串乘方】

def cut(str, length, i):
    step = length // i
    for j in range(i-1):
        if str[j:j+step] != str[j+step:j+step*2]:
            return False
    return True

while True:
    s = input()
    if s == ".":
        break
    n = 1
    length = len(s)
    half = int(length ** 0.5)
    for i in range(1, half + 1):
        if length % i == 0:
            if cut(s, length, i) == True and n < i:
                n = i
            if cut(s, length, length // i) == True and n < length // i:
                n = length // i
    print(n)

解析:只需要判断字符串能最大被几等分,令字符串长度为length,则只需遍历length的所有因数,输出令字符串能被等分为最多字串的因数即可。

【AcWing 778. 字符串最大跨距】

s, s1, s2 = map(str, input().split(","))
l = s.find(s1)
r = s.rfind(s2)
l_end = l + len(s1) - 1

if l == -1 or r == -1:
    print(-1)
elif l_end >= r:
    print(-1)
else:
    print(r - l_end - 1)

解析:l是使用find函数查找到的子串第一次出现的位置,r是使用rfind函数查找到的子串最后一次出现的位置,l_end是子串第一次出现时候的末尾下标的位置,若子串未在字符串中出现过,则find/rfind函数返回-1;若l_end的位置越过r,则两个子串交叉,不符合题意;符合题意时子字符串最大跨距即为r - l_end - 1

s, s1, s2 = map(str, input().split(","))

l = 0
# 手动求子串s1第一次出现时候的下标
while l + len(s1) <= len(s):
    k = 0
    # 遍历查看当前位置子串是否合法
    while k < len(s1):
        if s[l + k] != s1[k]:
            break
        k += 1
    if k == len(s1):
        break
    l += 1
    
r = len(s) - len(s2)
# 手动求子串s2最后一次出现时候的下标
while r >= 0:
    k = 0;
    while k < len(s2):
        if (s[r + k] != s2[k]):
            break
        k += 1
    if k == len(s2):
        break
    r -= 1

# 将l移到子串s1第一次出现时候的末尾位置
l = l + len(s1) - 1
if (len(s) < len(s1) or len(s) < len(s2)):
    print(-1)
# 如果两个子串交叉,则不合题意
elif l >= r:
    print(-1)
else:
    print(r - l - 1)

解析:思路同上,将查找子串下标的过程手写了一遍。

【AcWing 779. 最长公共字符串后缀】

while True:
    n = int(input())
    if n == 0:
        break
    
    # 接收该组字符串并存储其反转
    strs = [input()[::-1] for i in range(n)]
    # 记录该组最短字符串的长度
    l = len(min(strs))
    
    m = 0
    # 对所有字符串从上往下比较该列的所有字符
    for i in range(l):
        cnt = 0
        # 判断该列所有字符是否均相同
        for j in range(n):
            if strs[0][i] == strs[j][i]:
                cnt += 1
            else:
                break
        # 如果该列的所有字符均相同,则前缀加1
        if cnt == n:
            m += 1
        else:
            break
    
    # 输出前缀
    print(strs[0][0:m][::-1])

解析:对每组字符串,将其中每个字符串的反转存储到列表中,然后从第一列开始(下标为0),对所有字符串从上往下比较该列的所有字符,判断该列的所有字符是否均相同,如若相同,则前缀加1,最后输出首个字符串的该前缀即可。

因为Python提供了直接索引后缀的方法,所以这道题可以无需反转,直接索引后缀:

while True:
    n = int(input())
    if n == 0:
        break
    
    # 接收该组字符串
    strs = [input() for i in range(n)]
    # 记录该组最短字符串的长度
    l = len(min(strs))
    
    m = 0
    # 对所有字符串从上往下比较该列的所有字符
    for i in range(-1, -l-1, -1):
        cnt = 0
        # 判断该列所有字符是否均相同
        for j in range(n):
            if strs[0][i] == strs[j][i]:
                cnt += 1
            else:
                break
        # 如果该列的所有字符均相同,则后缀加1
        if cnt == n:
            m += 1
        else:
            break
    
    # 输出后缀
    if m > 0:
        print(strs[0][-m:])
    else:
        print()

解析:将每组字符串存储到列表中,然后从最后一列开始(下标为-1),对所有字符串从上往下比较该列的所有字符,判断该列的所有字符是否均相同,如若相同,则后缀加1,最后输出首个字符串的后缀即可。

也可以采用暴力的方法,每一次都更新一遍最长公共字符串后缀:

def suffix(s1, s2):
    s = ""
    if len(s1) > len(s2):
        s1, s2 = s2, s1
    for i in range(len(s1)):
        j = - (i + 1)
        if s1[j] == s2[j]:
            s = s1[j] + s
        else:
            return s
    return s

while True:
    N = int(input())
    if N == 0:
        break
    elif N == 1:
        s0 = input()
        print(s0)
        continue
    strlist = [input() for i in range(N)]
    str = suffix(strlist[0], strlist[1])
    for i in range(2, len(strlist)):
        if str > strlist[i]:
            str = suffix(strlist[i], str)
        else:
            str = suffix(str, strlist[i])
    print(str)

解析:求两个字符串最长公共后缀的算法为暴力思路,设置一个空字符串存储后缀,从后往前比较两个字符串的每个字符,若相等就归入后缀字符串,若不相等或有一个字符串被遍历完,就说明找到了最长公共后缀。

N为0时结束循环,N为1时最长公共后缀为本身,N大于等于2时,用字符串列表存放输入的字符串,首先求出前两个字符串的最长公共后缀,遍历剩下的字符串,用当前最长公共后缀和下一个字符串的最长公共后缀更新最长公共后缀。

你可能感兴趣的:(AcWing题解,python)