LeetCode刷题笔记:字节跳动-挑战字符串

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

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

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

本题我的思路是对字符串进行遍历,声明一个tmp空字符串,如果当前遍历字符未在tmp中,则将该字符加入tmp中,若在tmp中,则利用python字符串自带的index函数找到该字符上一次出现的位置,然后将其后面的字符串与当前字符进行拼接,然后继续进行下一个字符的遍历。代码如下:

tmp = ''
max_ = 0
for i in xrange(len(s)):
    if s[i] not in tmp:
        tmp+=s[i]
    else:
        max_ = max(max_,len(tmp))
        idx = tmp.index(s[i])
        tmp = tmp[idx+1:]+s[i]
    if i==len(s)-1:
        max_=max(max_,len(tmp))
return max_

2.最长公共前缀

编写一个函数来查找字符串数组中的最长公共前缀。

如果不存在公共前缀,返回空字符串 ""。

示例一:
输入: ["flower","flow","flight"]
输出: "fl"
示例二:
输入: ["dog","racecar","car"]
输出: ""
解释: 输入不存在公共前缀。
说明:

所有输入只包含小写字母 a-z 。

本题我的思路用到了两个循环,第一个循环用来遍历第一个字符串的字符,然后将当前遍历到的字符加入到最长公共前缀中,然后内部嵌套一个循环,对余下的字符串进行匹配,如果匹配成功,继续下一个字符的匹配,如果匹配失败,返回当前的最长公共前缀。代码如下:

if not strs:
    return ''
tmp = ''
for i in xrange(len(strs[0])):
    tmp+=strs[0][i]
    for j in xrange(1,len(strs)):
        if tmp!=strs[j][:i+1]:
            return tmp[:i]
return tmp

3.字符串的排列

给定两个字符串 s1 s2,写一个函数来判断 s2 是否包含 s1 的排列。

换句话说,第一个字符串的排列之一是第二个字符串的子串。

示例一:
输入: s1 = "ab" s2 = "eidbaooo"
输出: True
解释: s2 包含 s1 的排列之一 ("ba").
示例二:
输入: s1= "ab" s2 = "eidboaoo"
输出: False
注意:
    1.输入的字符串只包含小写字母
    2.两个字符串的长度都在 [1, 10,000] 之间

本题我最开始的思路是求第一个字符串的全排列,然后依次判断第二个字符串中是否包含第一个全排列中的字符串。代码如下:

s1 = [str(s) for s in s1]
def qpl(s,start,end):
    tmp = []
    if start == end:
        tmp.append(''.join(s))
        return tmp
        for i in range(start,end+1):
            s[i],s[start]=s[start],s[i]
            tmp += qpl(s,start+1,end)
            s[i],s[start]=s[start],s[i]
        return tmp
li = qpl(s1,0,len(s1)-1)
while li:
    tmp = li.pop()
    if tmp in s2:
        return True
return False

但是这种方法问题有点大,实现需要的空间复杂度和时间复杂度都相当高,其实我们并不需要遍历出每一种排列的结果,我们只需要知道这个字符串中,有多少种字符,以及每一个字符包含多少个就行了。那这个就相当简单了。代码如下:

d1= {}
for x in s1:
    d1[x]=d1.get(x,0)+1
l1 = len(s1)
l2 = len(s2)
d2 = {}
for x in s2[:l1]:
    d2[x]=d2.get(x,0)+1
if d2==d1:
    return True
else:
    for i in xrange(l2-l1):
        d2[s2[i]]=d2.get(s2[i])-1
        if d2.get(s2[i])==0:
            d2.pop(s2[i])
        d2[s2[i+l1]]=d2.get(s2[i+l1],0)+1
        if d1==d2:
            return True
return False

4.字符串相乘

给定两个以字符串形式表示的非负整数 num1 和 num2,返回 num1 和 num2 的乘积,它们的乘积也表示为字符串形式。

示例一:
输入: num1 = "2", num2 = "3"
输出: "6"
示例二:
输入: num1 = "123", num2 = "456"
输出: "56088"
说明:
    1.num1 和 num2 的长度小于110。
    2.num1 和 num2 只包含数字 0-9。
    3.num1 和 num2 均不以零开头,除非是数字 0 本身。
    4.不能使用任何标准库的大数类型(比如 BigInteger)或直接将输入转换为整数来处理。

本题一开始我的思路是利用num1和num2中较短的那个,每一位与另一个字符串中的每一位数相乘,然后每一次乘积都储存到一个列表中,而且每一次乘得的乘积还需要向左移位,最后将这个列表求和。其实这个最后是不符合题意的,因为最后我是将列表中的字符串当成了整数进行sum函数运算。不过这种方法在leetcode上无法运行,因为分配的空间不够,导致字符串无法转为整型。最原始的代码如下:

def mul(s1,s2):
    l1 = len(s1)
    l2 = len(s2)
    cin = 0
    if l2>l1:
        s1,s2=s2,s1
        l1,l2=l2,l1
    rs = []
    for i in range(l1-1,-1,-1):
        res = []
        for j in range(l2-1,-1,-1):
            tmp = long(s2[j])*long(s1[i])+cin
            cin = tmp/10
            res = [tmp%10]+res
            if j==0 and cin!=0:
                res = [cin]+res
        res+=[0]*(l1-i-1)
        rs.append(long(''.join([str(x) for x in res])))
    return sum([int(x) for x in rs])

后来发现其实可以存储相乘后每一位的结果,最后一位乘以最后一位就是最后一位的结果,而最后一位和倒数第二位,与另一个数的最后一位和倒数第二位的乘积,都属于倒数第二位的结果,而且还要加上前一位的进位。不过这样想来思路就很清晰,只需要将res[i+j+1]+=int(num1[i])*int(num2[j]),然后加上进位就行了,通过的代码如下:

if num1=='0' or num2=='0':
    return '0'
l1 = len(num1)
l2 = len(num2)
k = [0]*(l1+l2)
for i in range(l1-1,-1,-1):
    for j in range(l2-1,-1,-1):
        k[i+j+1]+=int(num1[i])*int(num2[j])
cin = 0
for i in range(l1+l2-1,-1,-1):
    k[i] += cin 
    cin = k[i]/10
    k[i] = k[i]%10
for i in range(l1+l2):
    if k[i]!=0:
        return ''.join([str(x) for x in k[i:]])

5.翻转字符串里的单词

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

示例一:
输入: "the sky is blue"
输出: "blue is sky the"
示例二:
输入: "  hello world!  "
输出: "world! hello"
解释: 输入字符串可以在前面或者后面包含多余的空格,但是反转后的字符不能包括。
示例三:
输入: "a good   example"
输出: "example good a"
解释: 如果两个单词间有多余的空格,将反转后单词间的空格减少到只含一个。
说明:
    1.无空格字符构成一个单词。
    2.输入字符串可以在前面或者后面包含多余的空格,但是反转后的字符不能包括。
    3.如果两个单词间有多余的空格,将反转后单词间的空格减少到只含一个。

本题按照题目的意思,可以遍历当前字符串,如果当前字符不是空格,则加入tmp数组,如果是空格,将tmp数组加入res数组,然后清空tmp数组,最后反向输出res数组即可。代码如下:

res = []
tmp = ''
for i in range(len(s)):
    print s[i]
    if i==len(s)-1 and s[i]!=' ':
        tmp+=s[i]
        res.append(tmp)
    elif s[i]!=' ':
        tmp+=s[i]
    else:
        if tmp!='':
            res.append(tmp)
        tmp = ''
re = ''
while res:
    tmp = res.pop()
    re += tmp+' '
return re[:-1]

但其实本题还有更简便的解法,利用python str的split函数,即可非常轻松完成这个任务。代码如下:

return ' '.join(s.split()[::-1])

6.简化路径

以 Unix 风格给出一个文件的绝对路径,你需要简化它。或者换句话说,将其转换为规范路径。

在 Unix 风格的文件系统中,一个点(.)表示当前目录本身;此外,两个点 (..) 表示将目录切换到上一级(指向父目录);两者都可以是复杂相对路径的组成部分。更多信息请参阅:Linux / Unix中的绝对路径 vs 相对路径

请注意,返回的规范路径必须始终以斜杠 / 开头,并且两个目录名之间必须只有一个斜杠 /。最后一个目录名(如果存在)不能以 / 结尾。此外,规范路径必须是表示绝对路径的最短字符串。

示例一:
输入:"/home/"
输出:"/home"
解释:注意,最后一个目录名后面没有斜杠。
示例二:
输入:"/../"
输出:"/"
解释:从根目录向上一级是不可行的,因为根是你可以到达的最高级。
示例三:
输入:"/home//foo/"
输出:"/home/foo"
解释:在规范路径中,多个连续斜杠需要用一个斜杠替换。
示例四:
输入:"/a/./b/../../c/"
输出:"/c"
示例五:
输入:"/a/../../b/../c//.//"
输出:"/c"
示例六:
输入:"/a//b////c/d//././/.."
输出:"/a/b/c"

本题按照题目的意思,我最初的想法是遍历当前字符串,如果不是'/'符号,则将当前字符加入tmp,如果遇到'/'符号,则对tmp进行处理,如果tmp不是'..',tmp入栈,清空tmp。如果tmp是'..',弹出栈顶元素,然后清空tmp,如果遍历到最后一个字符,则将当前tmp压栈,然后返回栈。但是后来发现有更简单的方法,即不用一个一个遍历字符,直接靠'/'对字符串进行分割,然后对每一个子串进行处理,返回栈即可。代码如下:

res = []
x = path.split('/')
for i in x:
    if i == '' or i == '.':
        continue
    elif i == '..':
        if res:
            res.pop()
    else:
        res.append(i)
return '/'+'/'.join(res)  

7.复原IP地址

给定一个只包含数字的字符串,复原它并返回所有可能的 IP 地址格式。

示例一:
输入: "25525511135"
输出: ["255.255.11.135", "255.255.111.35"]

本题思路就是通过递归,遍历字符串中的每一个位置,然后插入'.',一共需要插入3个点,然后将符合规则的分割方法添加到res,最后返回res即可。代码如下:

def restoreIpAddresses(self, s):
    res = [] 
    def isval(s):
        a = int(s)
        if 0<=a<=255 and (len(s)==1 or s[0]!='0'):
            return True
        return False
    def dfs(a,s,k):
        if k==3:
            if isval(s):
                res.append(a+s)
            return
        else:
            for i in range(1,min(4,len(s))):
                tmp=s[:i]
                if isval(tmp):
                    dfs(a+tmp+'.',s[i:],k+1)
    dfs('',s,0)
    return res

最近其实一直在刷leetcode的题目,感觉自己的编程能力也有一定的提升,希望能保持这种刷题热情,让自己更加优秀。

点赞

发表评论

[2;3Rer>