字符串专题

本文针对几道常见的字符串算法题目提供了解决方案,包括无重复字符的最长子串、最长回文子串、Z字形变换等,通过示例详细解析了各题目的解题思路与代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

3. 无重复字符的最长子串

难度:中等

题目描述

给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。

示例 1:

输入: "abcabcbb"
输出: 3 
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。

示例 2:

输入: "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。

示例 3:

输入: "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
     请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。

def longestSubStr(s):
    ans=''
    t=''
    for i in s:
        if i not in t:
            t+=i
        else:
            t=t[(t.index(i)+1):]
            t+=i
        if(len(ans)<len(t)):
            ans=t
    return len(ans)

5. 最长回文子串

难度:中等

题目描述

给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。

示例 1:

输入: "babad"
输出: "bab"
注意: "aba" 也是一个有效答案。

示例 2:

输入: "cbbd"
输出: "bb"
'''
以i为中心,向两边扩展

'''
def longestPalindrome(s):
    def expandI(l,r):
        while(l>=0 and r<len(s) and s[l]==s[r]):
            l-=1
            r+=1
        return l+1,r-1
    r_s,r_e=0,-1
    for i in range(len(s)):
        l1,r1=expandI(i,i)
        l2,r2=expandI(i,i+1)
        if(r1-l1)>(r_e-r_s):
            r_s,r_e=l1,r1
        if(r2-l2)>(r_e-r_s):
            r_s,r_e=l2,r2
    print(r_s,r_e)
        
    return s[r_s:r_e+1]

6. Z 字形变换

难度:中等

题目描述

将一个给定字符串根据给定的行数,以从上往下、从左到右进行 Z 字形排列。

比如输入字符串为 "LEETCODEISHIRING" 行数为 3 时,排列如下:

L   C   I   R
E T O E S I I G
E   D   H   N

之后,你的输出需要从左往右逐行读取,产生出一个新的字符串,比如:"LCIRETOESIIGEDHN"。

请你实现这个将字符串进行指定行数变换的函数:string convert(string s, int numRows);

示例 1:

输入: s = "LEETCODEISHIRING", numRows = 3
输出: "LCIRETOESIIGEDHN"

示例 2:

输入: s = "LEETCODEISHIRING", numRows = 4
输出: "LDREOEIIECIHNTSG"
解释:

L     D     R
E   O E   I I
E C   I H   N
T     S     G
'''
1、申明nrow的数组,逐次增加字符
2、i记录行号,flag记录向上还是向下移动
3、合并每行
'''

def zConvert(s,n):
    if n<2:
        return s
    
    r=['' for i in range(n)]
    
    i,flag=0,-1
    
    for c in s:
        r[i]+=c
        if i==0 or i==n-1:
            flag=-flag
        i+=flag
    return ''.join(r)

38. 外观数列

难度简单

给定一个正整数 n(1 ≤ n ≤ 30),输出外观数列的第 n 项。

注意:整数序列中的每一项将表示为一个字符串。

「外观数列」是一个整数序列,从数字 1 开始,序列中的每一项都是对前一项的描述。前五项如下:

1.     1
2.     11
3.     21
4.     1211
5.     111221

第一项是数字 1

描述前一项,这个数是 1 即 “一个 1 ”,记作 11

描述前一项,这个数是 11 即 “两个 1 ” ,记作 21

描述前一项,这个数是 21 即 “一个 2 一个 1 ” ,记作 1211

描述前一项,这个数是 1211 即 “一个 1 一个 2 两个 1 ” ,记作 111221

示例 1:

输入: 1
输出: "1"
解释:这是一个基本样例。

示例 2:

输入: 4
输出: "1211"
解释:当 n = 3 时,序列是 "21",其中我们有 "2" 和 "1" 两组,"2" 可以读作 "12",也就是出现频次 = 1 而 值 = 2;类似 "1" 可以读作 "11"。所以答案是 "12" 和 "11" 组合在一起,也就是 "1211"。
'''
1、两个变量pre,cur;pre记录上一个数字的表示,cur记录当前数字的表示
2、start,end指针计数
3、当前cur更新
'''


def countAndShow(n):
    pre=''
    cur='1'
    for i in range(1,n):
        pre=cur
        cur=''
        s,e=0,0
        while(e<len(pre)):
            while(e<len(pre) and pre[s]==pre[e]):
                e+=1
            cur+=str(e-s)+pre[s]
            s=e
    return cur

49. 字母异位词分组

难度:中等

题目描述

给定一个字符串数组,将字母异位词组合在一起。字母异位词指字母相同,但排列不同的字符串。

示例:

输入: ["eat", "tea", "tan", "ate", "nat", "bat"]
输出:
[
  ["ate","eat","tea"],
  ["nat","tan"],
  ["bat"]
]
'''
将列表中的字符串转化为排序字符;根据排序字符进行归类

'''

def groupGrams(s):
    r={}
    for c in s:
        k=''.join(sorted(list(c)))
        if k not in r.keys():
            r[k]=[c] 
        else:
            r[k].append(c)
    return r.values()

151. 翻转字符串里的单词

难度中等

给定一个字符串,逐个翻转字符串中的每个单词。

说明:

  • 无空格字符构成一个 单词 。
  • 输入字符串可以在前面或者后面包含多余的空格,但是反转后的字符不能包括。
  • 如果两个单词间有多余的空格,将反转后单词间的空格减少到只含一个。

示例 1:

输入:"the sky is blue"
输出:"blue is sky the"

示例 2:

输入:"  hello world!  "
输出:"world! hello"
解释:输入字符串可以在前面或者后面包含多余的空格,但是反转后的字符不能包括。

示例 3:

输入:"a good   example"
输出:"example good a"
解释:如果两个单词间有多余的空格,将反转后单词间的空格减少到只含一个。
'''
1、使用split分割,反转
2、空格拼接

'''

def reverse(s):
    r=' '.join([c for c in s.split()[::-1]])
    return r

165. 比较版本号

难度:中等

题目描述

比较两个版本号 version1 和 version2。 如果 version1 > version2 返回 1,如果 version1 < version2 返回 -1, 除此之外返回 0。

你可以假设版本字符串非空,并且只包含数字和 . 字符。

. 字符不代表小数点,而是用于分隔数字序列。

例如,2.5 不是“两个半”,也不是“差一半到三”,而是第二版中的第五个小版本。

你可以假设版本号的每一级的默认修订版号为 0。例如,版本号 3.4 的第一级(大版本)和第二级(小版本)修订号分别为 3 和 4。其第三级和第四级修订号均为 0。

示例 1:

输入: version1 = "0.1", version2 = "1.1"
输出: -1

示例 2:

输入: version1 = "1.0.1", version2 = "1"
输出: 1

示例 3:

输入: version1 = "7.5.2.4", version2 = "7.5.3"
输出: -1

示例 4:

输入:version1 = "1.01", version2 = "1.001"
输出:0
解释:忽略前导零,“01” 和 “001” 表示相同的数字 “1”。

示例 5:

输入:version1 = "1.0", version2 = "1.0.0"
输出:0
解释:version1 没有第三级修订号,这意味着它的第三级修订号默认为 “0”。
'''
双指针i_s,j_s分别遍历v1,v2,以.为分割寻找数字的终点i_e,j_e
x=int(v1[i_s:i_e])
y=int(v1[j_s:j_e])


'''

def f(v1,v2):
    l1,l2=len(v1),len(v2)
    s1,s2=0,0
    print(v1,v2,l1,l2)
    while(s1<l1 and s2<l2):
        e1,e2=s1,s2
        while(e1<l1 and v1[e1]!='.'):
            e1+=1
        while(e2<l2 and v2[e2]!='.'):
            e2+=1
        print(s1,e1,s2,e2)
        x1=int(v1[s1:e1]) if s1!=e1 else 0
        x2=int(v2[s2:e2]) if s2!=e2 else 0
        s1, s2 = e1+1, e2+1
        print('x:',x1,x2)
        if x1>x2:
            return 1
        if x1<x2:
            return -1
    return 0

929. 独特的电子邮件地址

难度:简单

题目描述

每封电子邮件都由一个本地名称和一个域名组成,以 @ 符号分隔。

例如,在 alice@leetcode.com中, alice 是本地名称,而 leetcode.com 是域名。

除了小写字母,这些电子邮件还可能包含 '.' 或 '+'。

如果在电子邮件地址的本地名称部分中的某些字符之间添加句点('.'),则发往那里的邮件将会转发到本地名称中没有点的同一地址。例如,"alice.z@leetcode.com” 和 “alicez@leetcode.com” 会转发到同一电子邮件地址。 (请注意,此规则不适用于域名。)

如果在本地名称中添加加号('+'),则会忽略第一个加号后面的所有内容。这允许过滤某些电子邮件,例如 m.y+name@email.com 将转发到 my@email.com。 (同样,此规则不适用于域名。)

可以同时使用这两个规则。

给定电子邮件列表 emails,我们会向列表中的每个地址发送一封电子邮件。实际收到邮件的不同地址有多少?

示例:

输入:["test.email+alex@leetcode.com","test.e.mail+bob.cathy@leetcode.com","testemail+david@lee.tcode.com"]
输出:2
解释:实际收到邮件的是 "testemail@leetcode.com" 和 "testemail@lee.tcode.com"。
'''
1、找到邮件位置,找到须符合规则的字符段
2、遇到'+'不计后面的;遇到'.'跳过

'''

def uniqueEmail(emails):
    
    res=set()
    for email in emails:
        t=''
        i=0
        indexAt=email.index('@')
        print(indexAt)
        while(i<indexAt and email[i]!='+'):
            if(email[i]=='.' ):
                i+=1
                continue
            t+=email[i]
            i+=1
        t+=email[indexAt:]
        res.add(t)
    print(res)
    
    return len(res)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值