Python笔试题记录——字符串类笔试题自记

目录

字符串距离

思路整理

完整代码

字符串提取

思路自记

 计算重复字符串长度

思路自记

字符串连连看

思路自记

字符串匹配

思路自记

完整代码


字符串类笔试题总结

字符串距离

给出两个相同长度的由字符 a 和 b 构成的字符串,定义它们的距离为对应位置不同的字符 的数量。如串”aab”与串”aba”的距离为 2;串”ba”与串”aa”的距离为 1;串”baa”和串”baa”的 距离为 0。下面给出两个字符串 S 与 T,其中 S 的长度不小于 T 的长度。我们用|S|代表 S 的 长度,|T|代表 T 的长度,那么在 S 中一共有|S|-|T|+1 个与 T 长度相同的子串,现在你需要计 算 T 串与这些|S|-|T|+1 个子串的距离的和。

思路整理

首先理解完这个题目之后,感觉还是很简单的,想到的思路就是,我把S字符串每一动一个字符,就切出一个长度为T的子字符串,再拿这个子字符串跟T字符串计算距离,再把距离累加,很快,就能得出结果了。

S = raw_input().split()
T = raw_input().split()
num = 0
s = len(S[0])
t = len(T[0])

if s == t:
    for x,y in zip(S[0],T[0]):
        if x != y:
            num += 1
else:
    for i in range(s-t+1):
        for x,y in zip(S[0][i:(i+t)],T[0]):
            if x != y:
                num+=1
print num

但一弄完就掉坑里面了,按这么普通的思路,一下子就导致超出时间了。

所以,得换个思路,但怎么都没办法把时间给缩小,没辙之后,看牛客大神的做法,发现,还是人家的脑子好使啊!

思路如下:人家的境界没我这么low,上来就直接切,而是用数字的方式代替,首先,构造一个长度比S大1的的新列表,初始元素为0,从第二位起,计算出现过的'a'的个数,出现'a'就加一,出现‘b’就维持上一个元素的值进行填充。

  temp = [0]
    for i in range(len(arr1)):
        if arr1[i] == 'a':
            temp.append(temp[-1] + 1)
        else:
            temp.append(temp[-1])

这样,就构造好了一个新列表,接下来就开始对T开始遍历:

再反复的琢磨后,总算是读懂了人家的思路,刚才所建立的新列表,实际上是保留了a的个数信息,下面开始对T中的每个元素进行遍历,如果当前元素是‘b’,那么就拿新序列中取跟T等长的段中出现的a的次数,因为当前比较元素是‘b’,所以,当a出现几次,就意味着距离是几;同理,如过当前元素是‘a’,那么拿这个段的长度减去a出现所占的次数,就是b出现的次数了,也就是距离了。依次类推,不断遍历,最终就把距离累加出来了。

PS:这里的delta估计并不是指一个S中有多少个T,而是指两个字串之间对应字符的间隔。

    delta = len(arr1) - len(arr2) + 1
    res = 0
    for i in range(len(arr2)):
        if arr2[i] == 'b':
            res += temp[i + delta] - temp[i]
        else:
            res += delta - (temp[i + delta] - temp[i])

反思,每写一道题会耗费很长时间,要是不总结清楚就太可惜了。反观这道题,利用字符串只包含ab两种字符的特点来设计,而且,拿第二个字符串跟他进行遍历,小串比大串。 

完整代码

def get_count(arr1, arr2):
    temp = [0]
    for i in range(len(arr1)):
        if arr1[i] == 'a':
            temp.append(temp[-1]+1)
        else:
            temp.append(temp[-1])
    delta = len(arr1) - len(arr2) + 1
    res = 0
    for i in range(len(arr2)):
        if arr2[i] == 'b':
            res += temp[i+delta] - temp[i]
        else:
            res += delta - (temp[i+delta] - temp[i])
    return res
 
if __name__=='__main__':
    arr1 = raw_input()
    arr2 = raw_input()
    print get_count(arr1, arr2)

 

字符串提取

请从字符串中提取以最后一个[img]开头、以最后一个[\img]结尾的字符串,未找到匹配的字符串返回"null" 

思路自记

此题比较简单,直接一次遍历再加上两个判断就可以实现。这个需要警记的只需要一个,就是[img]的索引要比[\img]小才行,否则是要返回null的。

def get(arr):
    index1 = 0
    index2 = 0
    if '[img]' not in arr or '[\img]' not in arr:
        return 'null'
    else:
        for i in range(len(arr)):
            if arr[i:i+5] == '[img]':
                index1=max(i,index1)
            elif arr[i:i+6] == '[\img]':
                index2 = max(i, index2)
    if index1 < index2:
       return arr[index1:index2+6]
    else:
        return 'null'

arr = raw_input()
print get(arr)

 计算重复字符串长度

请从字符串中找出至少重复一次的子字符串的最大长度

思路自记

PS:我本来觉得会很难,因为我隐隐约约记得好像有个叫求最长公共字串题目,但我当时没做出来,因为我能想到的就只有遍历了,但害怕超时,就直接翻看答案了,结果,,, 真tm就是直接遍历就行了!!!!

用两个循环i,j,i当作开头,j当作结尾,然后开始让j循环一遍,记录下来,如果有重复的设置一个计数器加一,再更改i,然后再循环一遍j,然后设置一个最大值,始终记录计数器的最大值。就可以了。

arr = raw_input().strip()
s = len(arr)

ss = 0
for i in range(s):
    num = 0
    for j in range(i+1, len(arr)):
        if arr.count(arr[i:j]) > 1:
            s = len(arr[i:j])
            if  s > ss:
                ss = s

print ss


PS:中间纠结了一番,把最大长度看成了,最大次数,看来逻辑缜密能力还有待提高。

字符串连连看

对于输入的字符串,从左到右扫描字符串,如果存在由三个以上(包括三个)连续相同字符组成的子串,就将这个子串从原串中去掉,并将原有字符串剩下的部分拼接到一起。重复上述过程,直到无法去掉任何子串。

思路自记

理解完题意之后就觉得很简单,马上开始编程,本着,找三连续的思想,开始,很快就写出来了:

arr = raw_input().strip()
arr = list(arr)
new_index = []

for i in range(len(arr)-4):
    if arr[i] == arr[i+1] and arr[i+1] == arr[i+2]:
        new_index.append(i)
        new_index.append(i+1)
        new_index.append(i+2)
    if arr[i] == arr[i+4] and arr[i+4] == arr[i+5]:
        new_index.append(i)
        new_index.append(i+4)
        new_index.append(i+5)
    if arr[i] == arr[i+1] and arr[i+1] == arr[i+4]:
        new_index.append(i)
        new_index.append(i+1)
        new_index.append(i+4)

new_index.reverse()
for x in new_index:
    del[arr[x]]
new_index = []

print ''.join(arr)

但本着看着越容易,坑越多的经验,还是写错了,为啥呢?人家要求 是不断重复,直到无法去掉任何子串,但我的思路是只进行一次,而且,无法控制循环的数量,经过一次后,的确能把当前序列的三连续给去掉,但去掉之后剩下的竟然又能重新组成三连续。

又是琢磨了很久,看了看人家的,才恍然大悟,原来应该是动态的去调整啊!就设置一个temp去存放不重复的元素,然后,每一次跟这个比,重复了就用pop跳出,这个思路真妙!

 

arr = raw_input().strip()
arr = list(arr)
temp = []

for x in arr:
    if len(temp) <= 1:
        temp.append(x)
    else:
        if temp[-1] == x and temp[-2] == x:
            temp.pop()
            temp.pop()
        else:
            temp.append(x)
print ''.join(temp)


字符串匹配

牛牛有两个字符串A和B,其中A串是一个01串,B串中除了可能有0和1,还可能有'?',B中的'?'可以确定为0或者1。 寻找一个字符串T是否在字符串S中出现的过程,称为字符串匹配。牛牛现在考虑所有可能的字符串B,有多少种可以在字符串A中完成匹配。
例如:A = "00010001", B = "??"
字符串B可能的字符串是"00","01","10","11",只有"11"没有出现在字符串A中,所以输出3

思路自记

这个思路刚开始我没想出来,看了人家的思路,解清迷惑,先判断两个字符串的长度如果B的字符串长度大于A,那么这个问题就没意义了,接着,初始化为零一个计数器,再设置一个空列表。

    if len(B)>len(A):
        return 0
    length_B = len(B)
    count = 0
    res = []

 接着,开始遍历,(len(A)-len(B)+1:表示B中有多少个A),从0开始遍历,首先判断A中一个与B字符串等长的字符串,来跟B来比较,这两个字符串逐个字符比较,如果B中的字符为‘?’,或者与对应的子串的对应字符相等,就计数器temp加1,最后,如果这两个字符串相等可以匹配,那么tmp肯定是等于B的长度的(因为每个字符都可加1)。那么,如果相对,就把这个从A中找出的字串,保存在res中。最后,读取出来就行。

for i in range(len(A) - length_B + 1):
        tmp = 0
        for j in range(length_B):
            if B[j] == '?' or B[j] == A[i:i+length_B][j]:
                tmp += 1
                if tmp == length_B:
                    res.append(A[i:i+length_B])
            else:
                break

完整代码

def solution(A,B):
    if len(B)>len(A):
        return 0
    length_B = len(B)
    count = 0
    res = []
    for i in range(len(A) - length_B + 1):
        tmp = 0
        for j in range(length_B):
            if B[j] == '?' or B[j] == A[i:i+length_B][j]:
                tmp += 1
                if tmp == length_B:
                    res.append(A[i:i+length_B])
            else:
                break
    return len(set(res))
if __name__=='__main__':
    A = raw_input().strip()
    B = raw_input().strip()
    print solution(A,B)

 

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值