1.数据结构-字符串问题

242. 有效的字母异位词

题目说明中有提示:小写字母,这种一般想到用一个长度26的数组去做点什么事情
注意用collections里Counter的写法

import collections
Counter(targe_str)

用counter的话很简单,但是体现不出什么思想

def isAnagram(self, s: str, t: str) -> bool:
        arr = [0]*26
        for c in s:
            arr[97-ord(c)] += 1
        for c in t:
            arr[97-ord(c)] -= 1
        for x in arr:
            if x != 0:
                return False
        return True 

相似题目 266
给定一个字符串,判断该字符串中是否可以通过重新排列组合,形成一个回文字符串
思路:奇数字符数量为0或者1

def canBe(s):
    arr = [0]*26
    odd = 0
    for c in s:
        arr[97-ord(c)] += 1
    for num in arr:
        if num & 1 == 1:
            odd += 1
    return odd in (0,1)

相似题目

49. 字母异位词分组

这里用defaultdict方便输出结果

def groupAnagrams(self, strs: List[str]) -> List[List[str]]:
        from collections import defaultdict
        dic = defaultdict(list)
        for s in strs:
            key = ''.join(sorted(list(s)))
            dic[key] += s.split(',')
        return list(dic.values())

相似题目

438. 找到字符串中所有字母异位词

这也是个有趣的题目,人们在日常打字中常容易打出重复字符,这个程序可以判断是否是有效重复,哈哈

925. 长按键入

你的朋友正在使用键盘输入他的名字 name。偶尔,在键入字符 c 时,按键可能会被长按,而字符可能被输入 1 次或多次。
你将会检查键盘输入的字符 typed。如果它对应的可能是你的朋友的名字(其中一些字符可能被长按),那么就返回 True。

def isLongPressedName(self, name: str, typed: str) -> bool:
        l1,l2=len(name),len(typed)
        p1=p2= 0 #双指针
        while p1<l1 and p2<l2:
            if name[p1]==typed[p2]:
                c=name[p1]
                cl1,cl2=p1,p2
                while cl1<l1 and name[cl1]==c:
                    cl1+=1
                while cl2<l2 and typed[cl2]==c:
                    cl2+= 1
                if cl2-p2<cl1-p1: 
                    return False
                else:
                    p1,p2=cl1,cl2
            else:
                return False
        if p1<l1 or p2<l2: #判断是否还有一个串有值
            return False 
        return True

重点:
第一次没有写出来的几个点:

  • while cl1<l1 and name[cl1]==c: 中的cl1<l1 定义的递增变量一定要注意判断是否越界,属于程序基本功
  • 最后判断是否还有一个串有值,这个是业务逻辑上考虑不周密

百度面试遇到的:求子串重复数目

def getCount(s,substr):
    ans = 0
    p1 = p2 = 0
    while(p1 < len(s)):
        if  p2<len(substr) and s[p1]==substr[p2]: #第一次写的时候没有写p2<len(str) 导致当len(substr)==1的时候判断substr[p2]会越界
            if p2 == len(substr)-1:
                ans += 1
                p2 = 0
            p1 += 1
            p2 += 1 
        else:
            p2 = 0 
            if s[p1]!=substr[p2]:
                p1 += 1      
    return ans

1464 直接用sorted , 当然自己还是要会写快排

无论如何,第一次成功做出树类型的题目还是很开心,加油加油,继续继续

1002. 查找常用字符

给定仅有小写字母组成的字符串数组 A,返回列表中的每个字符串中都显示的全部字符(包括重复字符)组成的列表。例如,如果一个字符在每个字符串中出现 3 次,但不是 4 次,则需要在最终答案中包含该字符 3 次。
你可以按任意顺序返回答案。
输入:["bella","label","roller"]
输出:["e","l","l"]
输入:["cool","lock","cook"]
输出:["c","o"]
提示:
1 <= A.length <= 100
1 <= A[i].length <= 100
A[i][j] 是小写字母

def commonChars(self, A: List[str]) -> List[str]:
        if not A: return []
        if len(A) == 1: return list(A)
        ans, c =[], Counter(A[0])
        for i in range(1,len(A)):
            c = Counter(A[i]) & c #精华
        for k in c:
            ans.extend([k]*c[k])
        return ans

知识点:counter的牛逼用法

763. 划分字母区间

做出来了但是复杂度是N^2 需要优化

def partitionLabels(self, S: str) -> List[int]:
        if not S: return [0]
        if len(S)==1: return [1]
        dic,ans={},[]
        for c in S:
            if c in dic:
                index = dic[c]
                tmp = ''.join(ans[index:])+c #这里是debug出来第一次忘记加当前字符
                ans = ans[:index]
                ans.append(tmp)
                for c1 in tmp:#这里也是debug出来,要把改片区所有字符对应的下标改掉
                    dic[c1] = index
            else:
                dic[c] = (len(ans))
                ans.append(c)
        return [len(s) for s in ans]

官方的思路更加正点,第一次遍历记住每个字符的最右端
第二次遍历根据这个左右端分段就行 贪心算法

class Solution:
    def partitionLabels(self, S: str) -> List[int]:
        last = [0] * 26
        for i, ch in enumerate(S):
            last[ord(ch) - ord("a")] = i
        
        partition = list()
        start = end = 0
        for i, ch in enumerate(S):
            end = max(end, last[ord(ch) - ord("a")])
            if i == end:
                partition.append(end - start + 1)
                start = end + 1
        
        return partition

76. 最小覆盖子串

def minWindow(self, s: str, t: str) -> str:
        ls,lt=len(s),len(t)
        if(ls==lt): return s if s==t else ""
        elif(ls<lt): return ""
        else:
            left,right=-10**9,10**9
            low,high=0,0
            tmp=t
            while(high<ls):
                if(s[high] in tmp):
                    tmp=tmp.replace(s[high],"")
                if(not tmp):
                    if(high-low)<(right-left):
                        left,right=low,high
                    tmp=t
                high+=1
            return s[left:right+1]

这里把自己困住的主要原因是不知道怎么去判断滑动窗口包含了T中所有的元素,这个时候要想到计数counter,那么自然也就可以想到字典了,于是滑动窗口+字典的组合出炉了

def minWindow(self, s: str, t: str) -> str:
        ls,lt=len(s),len(t)
        if(ls<lt): return ""
        else:
            low,high,num,mlen,start=0,0,0,ls+1,0 #num表示滑动窗口中出现t中字符的个数,mlen表示最小子串长度,start起始位置
            windic,tdic={},dict(Counter(t)) #滑动窗口字典和待查找字符串字典
            while(high<ls):
                highCount=windic.get(s[high],0) #抽取出来之后速度是有明显提升的
                if(highCount<tdic.get(s[high],0)):#待查找字符出现,+1
                    num+=1
                windic[s[high]]=highCount+1 #字符频次+1
                high+=1 #注意是每次先和待查找字典对比后再+1
                while(num==lt): #表示滑动窗口包含了t中所有字符,开始移动左边界
                    lowCount=windic.get(s[low],0);#抽取出来之后速度是有明显提升的
                    if((high-low)<mlen): #移动左边界的过程中记录最小子串
                        mlen,start=high-low,low
                    if(lowCount==tdic.get(s[low],0)):#待查找字符出现,频次-1     
                        num-=1
                    windic[s[low]]=lowCount-1 #字符频次-1
                    low+=1
            return "" if mlen==ls+1 else s[start:start+mlen]

1. 43. 字符串相乘

def multiply(self, num1: str, num2: str) -> str:
        if(num1=="0" or num2=="0"): return "0"
        else:
            ans=0
            l1,l2=len(num1),len(num2)
            for i in range(l1):
                for j in range(l2):
                    a = int(num1[i])*pow(10,l1-1-i)  
                    b = int(num2[j])*pow(10,l2-1-j)
                    ans += (a*b)
            return str(ans)

submit successfully but the time is 334ms , not that fast
a = int(num1[i])pow(10,l1-1-i) can be moved to the outer loop , 100ms decreased
you can find return str(int(num1)
int(num2)) only cost 40 ms what's the purpose of the problem?

3. 剑指 Offer 67. 把字符串转换成整数

搞定

4. 剑指 Offer 20. 表示数值的字符串

这个有点难,虽然理性分析了良久,但是最终还是有漏掉的case,可以看下最后一次的面条代码

def isNumber(self, s: str) -> bool:
        pool='+-.e0123456789'
        num_pool=pool[4:]
        s = s.lower().strip()
        if(len(s)==1 and num_pool.find(s[0])==-1):return False
        dic = {}
        epos, dotpos, addpos, negpos = -1,-1,-1,-1
        for i in range(len(s)):
            dic[s[i]] = dic.get(s[i],0) + 1
            if pool.find(s[i]) == -1: return False
            if(dic.get('.',0) > 1 or dic.get('e',0) > 1 or dic.get('+',0) > 1): return False
            if(s[i] == '.'): dotpos = i
            if(s[i] == 'e'): epos = i
            if(s[i] == '+'): addpos = i
            if(s[i] == '-'): negpos = i

        if(addpos!=-1 and addpos!=0): return False #正号必须在第一位
        if(epos!=-1 and dotpos!=-1 and epos-dotpos<2): return False #e至少要在.后两位
        if(epos==0 or epos==len(s)-1): return False #e不能出现在首尾
        #判断.前后数字的逻辑
        if(dotpos==len(s)-1 and num_pool.find(s[dotpos-1])==-1): return False 
        if(dotpos==0 and num_pool.find(s[1])==-1): return False 
        if(dotpos!=-1 and dotpos!=len(s)-1 and dotpos!=0):
            if(num_pool.find(s[dotpos+1])==-1): return False #.后面一定是数字 前面可以是小数点和数字

        if(negpos!=-1):
            if(negpos==0 or s[negpos-1]=='e'): return True #负号判断应该放在最后
            else: return False
        return True

疯了有没有。。。。只能看答案了,有限状态机!
同时学习了python中枚举的用法和dic中包含dic的巧妙使用
Python 优先状态机题解
a = Enum('status',['status1','status2'])
a.status1
a.status2

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,185评论 6 503
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,652评论 3 393
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,524评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,339评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,387评论 6 391
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,287评论 1 301
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,130评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,985评论 0 275
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,420评论 1 313
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,617评论 3 334
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,779评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,477评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,088评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,716评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,857评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,876评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,700评论 2 354