数据结构算法--字符串高频题目

  1. 字符串简介
  2. 面试题总体分析
  3. 一些例题:
    1. 0-1串交换顺序
    2. 字符的替换与复制
    3. 交换星号
    4. 子串变位词
    5. 单词/字符串翻转
  4. 总结

1. 字符串简介

  1. 尽量转化成字符数组[python中字符串是不可变类型]
  2. 和数组相关–内容广泛
    1. 概念相关:字典序
    2. 简单操作:插入、删除字符、旋转
    3. 规则判断: 罗马数字转换, 是否是合法的整数,浮点数
    4. 数字运算:大数加法,二进制加法
    5. 排序、交换(partition过程)
    6. 字符统计(hash):变位词
    7. 匹配(正则匹配[递归实现], 全串匹配, KMP匹配,周期判断)
    8. 动态规划(LCS【最长公共子序列】, 编辑距离, 最长回文串)
    9. 搜索(单词变换, 排列组合)

0-1交换

把一个0-1串(只包含0和1的串)进行排序,可以交换任意两个位置,请问最少交换的次数?

test = '00000100001101101'
ans = 0
test_list = list(test)
low = 0
high = len(test_list) - 1
while low < high:
    while low < high and test_list[low] == '0':
        low += 1
    while low < high and test_list[high] == '1':
        high -= 1
    if low < high:
        # 不然会陷入到死循环
        low += 1
        high -= 1
        # test_list[low], test_list[high] = test_list[high], test_list[low]
        ans += 1
        
ans

2. 字符串的替换和复制

  1. 删除一个字符串里面所有的a,并且复制所有的b。
  2. 字符数组足够大
test = 'abadcabebfdaba'
print('abadcabebfdaba')
# 先删除a,可以利用原来字符串的空间
test_list = list(test)
n, num_b = 0, 0
for i in range(len(test)):
    if test[i] != 'a':
        test_list[n] = test[i]
        n += 1
    if test[i] == 'b':
        num_b += 1
        
# 先计算字符串中有几个b,然后得到复制后的长度
# 复制---倒着复制
need = (n - 1) + num_b - (len(test) - 1 )
if need > 0:
    test_list = test_list + [0] * need
else:
    # 如果多余的话,就删除掉
    for _ in range(need, 0, 1):
        test_list.pop(_)
j = n - 1
i = len(test_list)-1
while i >= 0:
    test_list[i] = test_list[j]
    i -= 1
    if test_list[j] == 'b':
        # 遇到b的时候,赋值一次,移动两次
        test_list[i] = 'b'
        i -= 1
    j -= 1
    
ret = ''.join(test_list)
## 如何把字符串中的空格变成20%
test = 'aes df fefs   fe fgs'
space_num = 0
for i in test:
    if i.isspace():
        space_num += 1

# 把字符串转化成字符数组
test_list = list(test) + ['0'] * space_num * 2

# 从后向前复制的基本框架
j = len(test) - 1
i = len(test_list) - 1
while i >= 0:
    if test_list[j].isspace():
        test_list[i] = '0'
        i -= 1
        test_list[i] = '2'
        i -= 1
        test_list[i] = '%'
        i -= 1
        
    else:
        test_list[i] = test_list[j]
        i -= 1
    j -= 1
print(''.join(test_list))

交换星号

一个字符串中只包含*和数字请将其*都放在开头

test = '01*8**2*0**1'
test_list = list(test)
n = len(test)
low, high = 0, n - 1
while low < high:
    while low < high and test_list[low] == '*':
        low += 1
    while low < high and test_list[high] != '*':
        high -= 1
    test_list[low], test_list[high] = test_list[high], test_list[low]
print(''.join(test_list))   

# 第一种方法的数字会发生变化,采用循环不变式,数字的位置也发生变化
test = '01*8**2*0**1'
test_list = list(test)
n = len(test)
low, high = 0, 0
while high < n:
    if test_list[high] == '*':
        test_list[low], test_list[high] = test_list[high], test_list[low]
        low += 1       
    high += 1
print(''.join(test_list))

# 不改变数字的位置,达到相同的效果 
# 不改变数字的位置,只能使用这种方法
test = '01*8**2*0**1'
test_list = list(test)
n = len(test)
i, j = n-1, n-1
while j >= 0:
    if test_list[j] != '*':
        test_list[i] = test_list[j]
        i -= 1
    j -= 1
for _ in range(i-1, -1, -1):
    test_list[_] = '*'
print(''.join(test_list))

子串变位词

  1. 给定两个串a和b,问b是否是a的子串的变位词。例如输入a=hello,b=lel,lle,ello都是True
    , 但是b=elo,是false
  2. 滑动窗口思想
    1. 动态维护一个“窗口”
    2. 比如b的长度为3, 我们考察a[0…2], [1…3],[2…4]是否和b是变位词
    3. 如何与b比较-----对两个都进行排序,比较排完序之后的词
  3. Hash思想:
    1. 使用一个hash,基于字符串的特殊性,我们可以用[0, 255]或者[0…65535]的数组成,我们暂且认为他们都是小写英文字母,用[0…25],就是以下代码段中的num表示b中的单词出现了多少次【就是26个字母每个出现多少次】;
    2. 可以存一下有多少个非0次出现的,以后有用
    int nonzero = 0
    for i in range(0, len(b)):
        tmp = num[b[i] - 'a']
        tmp += 1
        if  tmp== 1:
            nonzero += 1
    
    1. 我们用b中的次数减去a中一个“窗口”内的字符串种类,如果结果全是0,则找到这样的子串。注意:num[]的含义变为字符串的种类差
    2. 第一个窗口[0…len(b)-1]【lena < lenb无解】
    3. 窗口如何滑动?向右一定一位
      1. 新窗口a[i-lenb+1: i]
      2. 旧窗口a[i-lenb: i+1]
        1. 扔掉a[i-lenb]
        2. 加入a[i]
a = 'hello'
b = 'lel'
array = [0] * 26
no_zero = 0
for i in range(len(b)):
    # 就是一个归一化操作,将c变成0-25期间
    c = ord(a[i]) - ord('a')
    array[c] -= 1
    if array[c] == 0:
        # 把一个非0值变成了0, 非0值减1
        no_zero -= 1
    elif array[c] == -1:
        no_zero += 1

        
if no_zero == 0:
    print(True)
else:
    print(False)
        
for i in range(len(b), len(a)):
    c = ord(a[i-len(b)]) - ord('a')
    array[c] += 1
    if array[c] == 1: no_zero += 1
    elif array[c] == 0: no_zero -= 1
    
    c = ord(a[i]) - ord('a')
    array[c] -= 1
    if array[c] == 0: no_zero -= 1
    elif array[c] == 0: no_zero -= 1
    if no_zero == 0:
        print('True')
        
"""Leetcode 3"""

单词翻转

  1. 翻转句子中的全部单词,单词内容不变
    1. 例如:I’m a student,变为 student a I’m;
    2. in-place翻转,字符串第i位到第j位
      1. while i<j: swap(s[i++], s[j–])
    3. 有什么用?
      1. 翻转整个句子: tneduts a m’I
      2. 每个单词单独翻转:student a I’m
    4. 难点?如何区分单词?找空格,split
    5. 思考题:字符串循环移位abcd
      1. U移动一次变为bcda
      2. 移动2次,变为cdab
      3. 移动3次,变为dabc
      4. 结论:长度为n,移动m次,相当于移动了m%n次
        1. 前m%n位翻转,后n-m%n位翻转
        2. 总体在翻转一次,实验一下?
test = 'abcd'
x = test[: 2]
y = test[2: ]
print(x, y)
u = x[::-1]
v= y[::-1]
tmp = u+v
tmp1 = tmp[::-1]
print(tmp1)

总结

  1. 我理解的in-place
    1. 本身O(1)空间
    2. 递归,堆栈空间可以不考虑
  2. 原地相关的问题
    1. 字符串循环左移、右移动
    2. 快拍partition相关
  3. 滑动窗口
    1. 能够达到O(n)的时间复杂度
    2. O(1)的空间复杂度
  4. 规则相关:细致
  5. 匹配(暴力)–KMP比较少见
  6. Manacher–要求比较高的面试
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值