【Leetcode】精选算法top200道(一)

一、简单题

163、缺失的区间【简单】

给定一个排序的整数数组 nums ,其中元素的范围在 闭区间 [lower, upper] 当中,返回不包含在数组中的缺失区间。

class Solution:
    def findMissingRanges(self, nums: List[int], lower: int, upper: int) -> List[str]:
        length = len(nums)
        new_list = []
        if length == 0:
            if upper - lower >= 1:
                strr = str(lower) +"->"+str(upper)
            else:
                strr = str(lower)
            new_list.append(strr)
            return new_list
        if nums[0] - lower >= 2:
            strr = str(lower) + "->" + str(nums[0]-1)
            lower = nums[0]
            new_list.append(strr)
        elif nums[0] - lower == 1:
            strr = str(lower)
            lower = nums[0]
            new_list.append(strr)
        for i in range(1, length):
            strr = ""
            if nums[i] - lower > 2:
                strr = str(lower+1) + "->" + str(nums[i]-1)
                lower = nums[i]
            elif nums[i] - lower == 2:
                strr = str(lower+1)
                lower = nums[i]
            elif nums[i] - lower == 1:
                lower = nums[i]
                continue
            else:
                continue
            new_list.append(strr)
        if upper - nums[length-1]>= 2:
            strr = str(nums[length-1]+1) + "->" + str(upper)
            new_list.append(strr)
        elif upper - nums[length-1] == 1:
            strr = str(upper)
            new_list.append(strr)
        return new_list

1099、小于k的两数之和【简单】

给你一个整数数组 nums 和整数 k ,返回最大和 sum ,满足存在 i < j 使得 nums[i] + nums[j] = sum 且 sum < k 。如果没有满足此等式的 i,j 存在,则返回 -1 。

class Solution:
    def twoSumLessThanK(self, nums: List[int], k: int) -> int:
        max_sum = 0
        length = len(nums)
        for i in range(length-1):
            for j in range(i+1, length):
                sum_n = nums[i] + nums[j]
                if sum_n >= k:
                    continue
                elif sum_n > max_sum:
                    # print(k, sum_n)
                    max_sum = sum_n
        if max_sum == 0:
             return -1
        return max_sum

170、两数之和【简单】

设计一个接收整数流的数据结构,该数据结构支持检查是否存在两数之和等于特定值。

实现 TwoSum 类:

TwoSum() 使用空数组初始化 TwoSum 对象
void add(int number) 向数据结构添加一个数 number
boolean find(int value) 寻找数据结构中是否存在一对整数,使得两数之和与给定的值相等。如果存在,返回 true ;否则,返回 false 。

class TwoSum:

    def __init__(self):
        self.nums = []
        # self.sums = []
        self.sorted = False
    def add(self, number: int) -> None:
        self.nums.append(number)
        self.sorted = False
        return None
	
    def find(self, value: int) -> bool:
        # length = len(self.nums)
        ## 二分查找
        if self.sorted == False:
            self.nums.sort()
            self.sorted = True
        low, high = 0, len(self.nums)-1
        while low < high:
            num = self.nums[low] + self.nums[high]
            if num < value:
                low+=1
            elif num > value:
                high-=1
            else:
                return True
        return False



# Your TwoSum object will be instantiated and called as such:
# obj = TwoSum()
# obj.add(number)
# param_2 = obj.find(value)

270、最接近的二叉搜索树值【简单】

给定一个不为空的二叉搜索树和一个目标值 target,请在该二叉搜索树中找到最接近目标值 target 的数值。

注意:

给定的目标值 target 是一个浮点数
题目保证在该二叉搜索树中只会存在一个最接近目标值的数

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def closestValue(self, root: Optional[TreeNode], target: float) -> int:
        if not root:
            return None
        small_diff = float("inf")
        close_num = root.val
        while root:
            diff = abs(root.val - target)
            if diff < small_diff:
                small_diff = diff
                close_num = root.val
            if root.val > target:
                root = root.left
            elif root.val < target:
                root = root.right
            else:
                return root.val
        return close_num

1119、删去字符串中的元音【简单】

给你一个字符串 s ,请你删去其中的所有元音字母 ‘a’,‘e’,‘i’,‘o’,‘u’,并返回这个新字符串。

class Solution:
    def removeVowels(self, s: str) -> str:
        l = len(s)
        ss = "aeiou"
        new_s = ""
        for i in range(l):
            if s[i] not in ss:
                new_s += s[i]
        return new_s

243、最短单词距离

给定一个字符串数组 wordDict 和两个已经存在于该数组中的不同的字符串 word1 和 word2 。返回列表中这两个单词之间的最短距离。

class Solution:
    def shortestDistance(self, wordsDict: List[str], word1: str, word2: str) -> int:
        index1, index2 = -1,-1
        index = len(wordsDict)
        for idx,x in enumerate(wordsDict):
            if x == word1:
                index1=idx
            if x == word2:
                index2=idx
            if index1 != -1 and index2 != -1:
                reduce = abs(index1 - index2)
                if reduce < index:
                    index = reduce
        return index

246. 中心对称数

中心对称数是指一个数字在旋转了 180 度之后看起来依旧相同的数字(或者上下颠倒地看)。

请写一个函数来判断该数字是否是中心对称数,其输入将会以一个字符串的形式来表达数字。

class Solution:
    def isStrobogrammatic(self, num: str) -> bool:
        dic = {"0":"0","1":"1", "6":"9", "9":"6", "8":"8"}
        dic1 = {"0":"0", "1":"1", "8":"8"}

        if len(num) <= 1:
            if num in dic1.keys():
                return True
            else:
                return False
        new_num = ""
        for i in range(len(num)):
            if num[i] not in dic.keys():
                return False
            else:
                new_num = dic[num[i]] + new_num
        if str(new_num) == num:
            return True
        return False

找出变位映射 【简单】

class Solution:
    def anagramMappings(self, nums1: List[int], nums2: List[int]) -> List[int]:
        res = []
        for x in nums1:
            res.append(nums2.index(x))
        return res

259、日志速率限制器

请你设计一个日志系统,可以流式接收消息以及它的时间戳。每条 不重复 的消息最多只能每 10 秒打印一次。也就是说,如果在时间戳 t 打印某条消息,那么相同内容的消息直到时间戳变为 t + 10 之前都不会被打印。

所有消息都按时间顺序发送。多条消息可能到达同一时间戳。

实现 Logger 类:

Logger() 初始化 logger 对象
bool shouldPrintMessage(int timestamp, string message) 如果这条消息 message 在给定的时间戳 timestamp 应该被打印出来,则返回 true ,否则请返回 false 。

链接:https://leetcode.cn/problems/logger-rate-limiter

class Logger:

    def __init__(self):
        self.dic = dict()


    def shouldPrintMessage(self, timestamp: int, message: str) -> bool:
        if message not in self.dic.keys():
            self.dic[message] = timestamp + 10
            return True
        else:
            if timestamp >= self.dic[message]:
                self.dic[message] = timestamp + 10
                return True
            else:
                return False



# Your Logger object will be instantiated and called as such:
# obj = Logger()
# param_1 = obj.shouldPrintMessage(timestamp,message)

604、迭代压缩字符串

设计并实现一个迭代压缩字符串的数据结构。给定的压缩字符串的形式是,每个字母后面紧跟一个正整数,表示该字母在原始未压缩字符串中出现的次数。

设计一个数据结构,它支持如下两种操作: next 和 hasNext。

next() - 如果原始字符串中仍有未压缩字符,则返回下一个字符,否则返回空格。
hasNext() - 如果原始字符串中存在未压缩的的字母,则返回true,否则返回false。

链接:https://leetcode.cn/problems/design-compressed-string-iterator

class StringIterator:

    def __init__(self, compressedString: str):
        tmp = ""
        nums = ""
        self.compressedString = []
        self.nums = []
        for s in compressedString:
            if s.isdigit():
                nums+=s
            else:
                if tmp!="" and nums!="":
                    num = 0
                    for ss in nums:
                        num = num*10 + int(ss)
                    self.compressedString.append(tmp) 
                    self.nums.append(num)
                nums = ""
                tmp = s
        if nums!="":
            num = 0
            for ss in nums:
                num = num*10 + int(ss)
            self.compressedString.append(tmp) 
            self.nums.append(num)
        

    def next(self) -> str:
        if not self.nums:
            return " "
        if len(self.compressedString) >= 1 and self.nums[0]!=0:
            a = self.compressedString[0]
            self.nums[0]-=1
            if self.nums[0]==0:
                self.nums.pop(0)
                self.compressedString.pop(0)
            return a


    def hasNext(self) -> bool:
        if len(self.compressedString)>=1: return True
        return False

734、句子相似性

我们可以将一个句子表示为一个单词数组,例如,句子 “I am happy with leetcode” 可以表示为 arr = [“I”,“am”,happy",“with”,“leetcode”]

给定两个句子 sentence1 和 sentence2 分别表示为一个字符串数组,并给定一个字符串对 similarPairs ,其中 similarPairs[i] = [xi, yi] 表示两个单词 xi and yi 是相似的。

如果 sentence1 和 sentence2 相似则返回 true ,如果不相似则返回 false 。

两个句子是相似的,如果:

它们具有 相同的长度 (即相同的字数)
sentence1[i] 和 sentence2[i] 是相似的
请注意,一个词总是与它自己相似,也请注意,相似关系是不可传递的。例如,如果单词 a 和 b 是相似的,单词 b 和 c 也是相似的,那么 a 和 c 不一定相似 。
链接:https://leetcode.cn/problems/sentence-similarity

class Solution:
    def areSentencesSimilar(self, sentence1: List[str], sentence2: List[str], similarPairs: List[List[str]]) -> bool:
        if len(sentence1)!=len(sentence2):
            return False
        for x, y in zip(sentence1, sentence2):
            if x!=y:
                if [x,y] not in similarPairs and [y,x] not in similarPairs:
                    return False
        return True

808、相似RGB颜色

RGB 颜色 “#AABBCC” 可以简写成 “#ABC” 。

例如,“#15c” 其实是 “#1155cc” 的简写。
现在,假如我们分别定义两个颜色 “#ABCDEF” 和 “#UVWXYZ”,则他们的相似度可以通过这个表达式 -(AB - UV)^2 - (CD - WX)^2 - (EF - YZ)^2 来计算。

那么给你一个按 “#ABCDEF” 形式定义的字符串 color 表示 RGB 颜色,请你以字符串形式,返回一个与它相似度最大且可以简写的颜色。(比如,可以表示成类似 “#XYZ” 的形式)

任何 具有相同的(最大)相似度的答案都会被视为正确答案。

链接:https://leetcode.cn/problems/similar-rgb-color

class Solution:
    def similarRGB(self, color: str) -> str:
        nums = [str(i) for i in range(10)] + ["a","b","c","d","e","f"]
        def str2int(s):
            num = 0
            for ss in s:
                num = num*16 + nums.index(ss)
            return num
        
        AB = (color[1:3])
        a = str2int(AB)
        CD = (color[3:5])
        b = str2int(CD)
        EF = (color[5:7])
        c = str2int(EF)
        
        def str2list(s):
            if s[0] == str(0):
                return ["0","1"]
            elif s[0] == "f":
                return ["e","f"]
            else:
                index = nums.index(s[0])
                return [nums[index-1], nums[index], nums[index+1]]
        minm = float("inf")
        ans = ""
        for x in str2list(AB):
            for y in nums:
                for z in nums:
                    u = str2int(x*2)
                    v = str2int(y*2)
                    w = str2int(z*2)
                    tmp = -(a-u)**2-(b-v)**2-(c-w)**2
                    if abs(tmp) < minm:
                        # print(a,u,b,v,c,w)
                        minm = abs(tmp)
                        ans = x*2+y*2+z*2
        return "#" + ans

1056、易混淆数

给定一个数字 N,当它满足以下条件的时候返回 true:
原数字旋转 180° 以后可以得到新的数字。
如 0, 1, 6, 8, 9 旋转 180° 以后,得到了新的数字 0, 1, 9, 8, 6 。
2, 3, 4, 5, 7 旋转 180° 后,得到的不是数字。
易混淆数 (confusing number) 在旋转180°以后,可以得到和原来不同的数,且新数字的每一位都是有效的。

链接:https://leetcode.cn/problems/confusing-number

class Solution:
    def confusingNumber(self, n: int) -> bool:
        dic = {"0":"0","1":"1","6":"9","8":"8","9":"6"}
        s = str(n)
        new_s = ""
        for idx,ss in enumerate(s):
            if ss not in dic:
                return False
            new_s += dic[ss]
        if new_s[::-1] == s:
            return False
        return True

1064、不动点

class Solution:
    def fixedPoint(self, arr: List[int]) -> int:
        n = len(arr)
        for i in range(n):
            if i == arr[i]:
                return arr[i]
        return -1

1085、最小元素个数位之和

class Solution:
    def sumOfDigits(self, nums: List[int]) -> int:
        nums.sort()
        num = nums[0]
        s = str(num)
        res = 0
        for ss in s:
            res += int(ss)
        if res%2 == 0:
            return 1
        else: return 0

1065、字符串的索引对

给出 字符串 text 和 字符串列表 words, 返回所有的索引对 [i, j] 使得在索引对范围内的子字符串 text[i]…text[j](包括 i 和 j)属于字符串列表 words。

链接:https://leetcode.cn/problems/index-pairs-of-a-string

class Solution:
    def indexPairs(self, text: str, words: List[str]) -> List[List[int]]:
        res = []
        n = len(text)
        for i in range(n):
            for j in range(i,n):
                for word in words:
                    if text[i:j+1] == word:
                        res.append([i,j])
                        break
        return res

1086、前五科的均分

给你一个不同学生的分数列表 items,其中 items[i] = [IDi, scorei] 表示 IDi 的学生的一科分数,你需要计算每个学生 最高的五科 成绩的 平均分。

返回答案 result 以数对数组形式给出,其中 result[j] = [IDj, topFiveAveragej] 表示 IDj 的学生和他 最高的五科 成绩的 平均分。result 需要按 IDj 递增的 顺序排列 。

学生 最高的五科 成绩的 平均分 的计算方法是将最高的五科分数相加,然后用 整数除法 除以 5 。

链接:https://leetcode.cn/problems/high-five

class Solution:
    def highFive(self, items: List[List[int]]) -> List[List[int]]:
        dic = defaultdict(list)
        for it in items:
            dic[it[0]].append(it[1])
        res = []
        for k,v in dic.items():
            tmp = dic[k]
            tmp.sort(key=lambda x:-x)
            res.append([k, sum(tmp[:5])//5])
        res.sort(key = lambda x:x[0])
        return res

1118、一月有多少天

闰年是公历中的名词。闰年分为普通闰年和世纪闰年,闰年的定义:
普通闰年:公历年份是 4 的倍数,且不是 100 的倍数的,为闰年(如 2004 年就是闰年)。
世纪闰年:公历年份是整百数的,必须是 400 的倍数才是世纪闰年(如 1900 年不是世纪闰年,2000 年是世纪闰年)。

class Solution:
    def numberOfDays(self, year: int, month: int) -> int:
        
        Id = 1
        if (year % 100 != 0 and year % 4 == 0) or (year % 400 == 0):
            Id = 1
        else:
            Id = 0
        month1 = [1,3,5,7,8,10,12]
        month2 = [2,4,6,8,10]
        if month == 2:
            if Id == 1:
                return 29
            else:
                return 28
        else:
            if month in month1:
                return 31
            else:
                return 30

1133、最大唯一数

给你一个整数数组 A,请找出并返回在该数组中仅出现一次的最大整数。

如果不存在这个只出现一次的整数,则返回 -1。

class Solution:
    def largestUniqueNumber(self, nums: List[int]) -> int:
        dic = defaultdict(int)
        for num in nums:
            dic[num] += 1
        # print(dic)
        l = []
        for k,v in dic.items():
            if v==1:
                l.append(k)
        if not l:
            return -1
        l.sort()
        return l[-1]

1134、阿姆斯特朗数

给你一个整数 n ,让你来判定他是否是 阿姆斯特朗数,是则返回 true,不是则返回 false。

假设存在一个 k 位数 n ,其每一位上的数字的 k 次幂的总和也是 n ,那么这个数是阿姆斯特朗数 。
链接:https://leetcode.cn/problems/armstrong-number

class Solution:
    def isArmstrong(self, n: int) -> bool:
        k = len(str(n))
        nums = []
        for s in str(n):
            nums.append(int(s))
        m = 0
        for x in nums:
            m += x**k

        return m==n

1150、检查一个数是否在数组中占绝大多数

给出一个按 非递减 顺序排列的数组 nums,和一个目标数值 target。假如数组 nums 中绝大多数元素的数值都等于 target,则返回 True,否则请返回 False。

所谓占绝大多数,是指在长度为 N 的数组中出现必须 超过 N/2 次。
链接:https://leetcode.cn/problems/check-if-a-number-is-majority-element-in-a-sorted-array

class Solution:
    def isMajorityElement(self, nums: List[int], target: int) -> bool:
        dic = defaultdict(int)
        tmp = 0
        for num in nums:
            dic[num] += 1
            if dic[num]>len(nums)//2:
                tmp = num
        return tmp == target

1165、单行键盘

我们定制了一款特殊的键盘,所有的键都 排列在一行上 。

给定一个长度为 26 的字符串 keyboard ,来表示键盘的布局(索引从 0 到 25 )。一开始,你的手指在索引 0 处。要输入一个字符,你必须把你的手指移动到所需字符的索引处。手指从索引 i 移动到索引 j 所需要的时间是 |i - j|。

您需要输入一个字符串 word 。写一个函数来计算用一个手指输入需要多少时间。
链接:https://leetcode.cn/problems/single-row-keyboard

class Solution:
    def calculateTime(self, keyboard: str, word: str) -> int:
        dic = defaultdict(int)
        for idx,num in enumerate(keyboard):
            dic[num] = idx
        tmp = 0
        time = 0
        for s in word:
            time += abs(dic[s]-tmp)
            tmp = dic[s]
        return time

1176、健身评估计划

你的好友是一位健身爱好者。前段日子,他给自己制定了一份健身计划。现在想请你帮他评估一下这份计划是否合理。

他会有一份计划消耗的卡路里表,其中 calories[i] 给出了你的这位好友在第 i 天需要消耗的卡路里总量。

为了更好地评估这份计划,对于卡路里表中的每一天,你都需要计算他 「这一天以及之后的连续几天」 (共 k 天)内消耗的总卡路里 T:

如果 T < lower,那么这份计划相对糟糕,并失去 1 分;
如果 T > upper,那么这份计划相对优秀,并获得 1 分;
否则,这份计划普普通通,分值不做变动。
请返回统计完所有 calories.length 天后得到的总分作为评估结果。
注意:总分可能是负数。
链接:https://leetcode.cn/problems/diet-plan-performance

class Solution:
    def dietPlanPerformance(self, calories: List[int], k: int, lower: int, upper: int) -> int:
        res = 0
        idx = 0
        cur = sum(calories[:k])
        pre = calories[idx+k-1]
        tmp = calories[idx+k-1]
        while idx + k <= len(calories):
            tmp = calories[idx+k-1]
            cur = cur - pre + tmp
            pre = calories[idx]
            if cur < lower:
                res -= 1
            elif cur > upper:
                res += 1 
            idx += 1
        return res

1180、统计只含单一字母的子串

给你一个字符串 s,返回 只含 单一字母 的子串个数 。

class Solution:
    def countLetters(self, s: str) -> int:
        ans = 0
        dic = defaultdict(int)
        for i in range(len(s)):
            cur = s[i]
            dic[cur] += 1
            for j in range(i+1, len(s)):
                if s[j]!=cur:
                    break
                dic[s[i:j+1]] += 1
        for k,v in dic.items():
            ans += v
        return ans

1196、最多可以买到的苹果数量

你有一些苹果和一个可以承载 5000 单位重量的篮子。

给定一个整数数组 weight ,其中 weight[i] 是第 i 个苹果的重量,返回 你可以放入篮子的最大苹果数量 。

链接:https://leetcode.cn/problems/how-many-apples-can-you-put-into-the-basket

class Solution:
    def maxNumberOfApples(self, weight: List[int]) -> int:
        weight.sort()
        ans = 0
        cur = 0
        print(weight)
        for w in weight:
            cur += w
            if cur > 5000:
                return ans
            ans += 1
        return ans

1213、三个有序数组的交集

class Solution:
    def arraysIntersection(self, arr1: List[int], arr2: List[int], arr3: List[int]) -> List[int]:
        res = []
        for x in arr1:
            if x in arr2 and x in arr3:
                res.append(x)
        return res

1228、等差数列中缺失的数字

在某个数组 arr 中,值符合等差数列的数值规律:在 0 <= i < arr.length - 1 的前提下,arr[i+1] - arr[i] 的值都相等。

我们会从该数组中删除一个 既不是第一个 也 不是最后一个的值,得到一个新的数组 arr。

给你这个缺值的数组 arr,返回 被删除的那个数 。

链接:https://leetcode.cn/problems/missing-number-in-arithmetic-progression

class Solution:
    def missingNumber(self, arr: List[int]) -> int:
        d = (arr[-1] - arr[0])//len(arr)
        print(d)
        for i in range(1, len(arr)):
            if arr[i] - arr[i-1] != d:
                return arr[i-1]+d
        return arr[0]
        

1243、数组变换

首先,给你一个初始数组 arr。然后,每天你都要根据前一天的数组生成一个新的数组。

第 i 天所生成的数组,是由你对第 i-1 天的数组进行如下操作所得的:

假如一个元素小于它的左右邻居,那么该元素自增 1。
假如一个元素大于它的左右邻居,那么该元素自减 1。
首、尾元素 永不 改变。
过些时日,你会发现数组将会不再发生变化,请返回最终所得到的数组。

链接:https://leetcode.cn/problems/array-transformation

class Solution:
    def transformArray(self, arr: List[int]) -> List[int]:
        tmp = []
        while arr != tmp:
            tmp = arr
            cur = arr[:]
            for i in range(1, len(arr)-1):
                if arr[i-1]>arr[i] and arr[i]<arr[i+1]:
                    cur[i] += 1
                elif arr[i-1]<arr[i] and arr[i]>arr[i+1]:
                    cur[i] -= 1
            arr = cur
        return arr

1271、十六进制魔术数字

你有一个十进制数字,请按照此规则将它变成「十六进制魔术数字」:首先将它变成字母大写的十六进制字符串,然后将所有的数字 0 变成字母 O ,将数字 1 变成字母 I 。

如果一个数字在转换后只包含 {“A”, “B”, “C”, “D”, “E”, “F”, “I”, “O”} ,那么我们就认为这个转换是有效的。

给你一个字符串 num ,它表示一个十进制数 N,如果它的十六进制魔术数字转换是有效的,请返回转换后的结果,否则返回 “ERROR” 。

链接:https://leetcode.cn/problems/hexspeak

class Solution:
    def toHexspeak(self, num: str) -> str:
        dic = {'0':'O','1':'I'}
        l = ['0','1','a','b','c','d','e','f']
        res = ''
        s = 0
        for x in num:
            s = s*10 + int(x)
        num = s
        num_new = hex(num)[2:]
        for ss in num_new:
            if ss not in l:
                return 'ERROR'
            if ss in dic:
                res += dic[ss]
            else:
                res += ss.upper()
        return res

二、中等题

254、因子的组合

整数可以被看作是其因子的乘积。

例如:

8 = 2 x 2 x 2;
= 2 x 4.
请实现一个函数,该函数接收一个整数 n 并返回该整数所有的因子组合。

链接:https://leetcode.cn/problems/factor-combinations

class Solution:
    def getFactors(self, n: int) -> List[List[int]]:
        def dfs(l, m):
            res = []
            for i in range(l, int(sqrt(m))+1):
                if m%i == 0:
                    res.append([i, m//i])
                    for sub in dfs(i, m//i):
                        res.append([i] + sub)
            return res
        if n<=3:
            return []
        return dfs(2, n)

249、移位字符串分组

给定一个字符串,对该字符串可以进行 “移位” 的操作,也就是将字符串中每个字母都变为其在字母表中后续的字母,比如:“abc” -> “bcd”。这样,我们可以持续进行 “移位” 操作,从而生成如下移位序列:

“abc” -> “bcd” -> … -> “xyz”
给定一个包含仅小写字母字符串的列表,将该列表中所有满足 “移位” 操作规律的组合进行分组并返回
链接:https://leetcode.cn/problems/group-shifted-strings


class Solution:
    def groupStrings(self, strings: List[str]) -> List[List[str]]:
        def hash(string):
            if len(string)>1:
                return tuple((ord(string[i])-ord(string[i-1]))%26 for i in range(1,len(string)))
            else:
                return 0
        
        res = defaultdict(list)
        for l in strings:
            res[hash(l)].append(l)
        return list(res.values())

261、以图判树

给定编号从 0 到 n - 1 的 n 个结点。给定一个整数 n 和一个 edges 列表,其中 edges[i] = [ai, bi] 表示图中节点 ai 和 bi 之间存在一条无向边。

如果这些边能够形成一个合法有效的树结构,则返回 true ,否则返回 false 。

链接:https://leetcode.cn/problems/graph-valid-tree

class Solution:
    def validTree(self, n: int, edges: List[List[int]]) -> bool:
        arr = [i for i in range(n)]
        cluster = n
        def findFather(i):
            if arr[i] == i:
                return i
            return findFather(arr[i])
        def union(x, y):
            x = findFather(x)
            y = findFather(y)
            if x == y:
                return True
            else:
                arr[y] = x
                return False
        for i,j in edges:
            res = union(i, j)
            if res: 
                return False
            else:
                cluster -= 1
        return False if cluster != 1 else True

323、无向图中连通分量的数目

你有一个包含 n 个节点的图。给定一个整数 n 和一个数组 edges ,其中 edges[i] = [ai, bi] 表示图中 ai 和 bi 之间有一条边。

返回 图中已连接分量的数目 。

链接:https://leetcode.cn/problems/number-of-connected-components-in-an-undirected-graph

class Solution:
    def countComponents(self, n: int, edges: List[List[int]]) -> int:
        arr = [i for i in range(n)]
        def findFather(i):
            if arr[i] == i:
                return i
            return findFather(arr[i])
        def isConnect(i,j):
            x = findFather(i)
            y = findFather(j)
            if x==y: return True
            else: 
                arr[y] = x
                return False
        cluster = n
        for i,j in edges:
            if not isConnect(i, j):
                cluster -= 1
        return cluster

277. 搜寻名人

假设你是一个专业的狗仔,参加了一个 n 人派对,其中每个人被从 0 到 n - 1 标号。在这个派对人群当中可能存在一位 “名人”。所谓 “名人” 的定义是:其他所有 n - 1 个人都认识他/她,而他/她并不认识其他任何人。

现在你想要确认这个 “名人” 是谁,或者确定这里没有 “名人”。而你唯一能做的就是问诸如 “A 你好呀,请问你认不认识 B呀?” 的问题,以确定 A 是否认识 B。你需要在(渐近意义上)尽可能少的问题内来确定这位 “名人” 是谁(或者确定这里没有 “名人”)。

在本题中,你可以使用辅助函数 bool knows(a, b) 获取到 A 是否认识 B。请你来实现一个函数 int findCelebrity(n)。

派对最多只会有一个 “名人” 参加。若 “名人” 存在,请返回他/她的编号;若 “名人” 不存在,请返回 -1。
链接:https://leetcode.cn/problems/find-the-celebrity

# The knows API is already defined for you.
# return a bool, whether a knows b
# def knows(a: int, b: int) -> bool:

class Solution:
    def findCelebrity(self, n: int) -> int:
        for i in range(n):
            for j in range(n):
                if i!=j:
                    if knows(i, j): break
                    if not knows(j, i): break
                else:
                    if j==n-1: return i 
                    continue
                if j==n-1: return i 
        return -1

280、摆动排序

给你一个的整数数组 nums, 将该数组重新排序后使 nums[0] <= nums[1] >= nums[2] <= nums[3]…

class Solution:
    def wiggleSort(self, nums: List[int]) -> None:
        """
        Do not return anything, modify nums in-place instead.
        """
        nums.sort()
        for idx,x in enumerate(nums):
            if idx %2 == 0 and idx != 0:
                tmp = nums[idx-1]
                nums[idx-1] = nums[idx]
                nums[idx] = tmp
        return nums

298、二叉树最长连续序列

给你一棵指定的二叉树的根节点 root ,请你计算其中 最长连续序列路径 的长度。

最长连续序列路径 是依次递增 1 的路径。该路径,可以是从某个初始节点到树中任意节点,通过「父 - 子」关系连接而产生的任意路径。且必须从父节点到子节点,反过来是不可以的。
链接:https://leetcode.cn/problems/binary-tree-longest-consecutive-sequence

class Solution:
    def longestConsecutive(self, root: TreeNode) -> int:
        self.res = 0
        def dfs(root):
            if not root:
                return 0
            l,r = dfs(root.left),dfs(root.right)
            ans = 1
            if root.left and root.left.val == root.val+1:
                ans = max(ans, l+1)
            if root.right and root.right.val == root.val+1:
                ans = max(ans, r+1)
            self.res = max(ans, self.res)
            return ans
        dfs(root)
        return self.res

314、二叉树的垂直遍历

给你一个二叉树的根结点,返回其结点按 垂直方向(从上到下,逐列)遍历的结果。

如果两个结点在同一行和列,那么顺序则为 从左到右。

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def verticalOrder(self, root: Optional[TreeNode]) -> List[List[int]]:
        d = [root]
        c = []
        # i, j = 0, 0
        if not root:
            return []
        dic = {root.val:[0,0]}
        dic_new = defaultdict(list)
        dic_new[0] = [root.val ]
        while d:
            c = d
            d = []
            while c:
                a = c.pop(0)
                i,j = dic[a.val]
                if a.left:
                    dic[a.left.val] =[i+1, j-1]
                    dic_new[j-1].append(a.left.val)
                    d.append(a.left)
                if a.right:
                    dic[a.right.val] = [i+1, j+1]
                    dic_new[j+1].append(a.right.val)
                    d.append(a.right)
            
        dic_new = sorted(dic_new.items(), key=lambda x:x[0])
        res = []
        for k, v in dic_new:
            res.append(v)

        return res
        

325. 和等于 k 的最长子数组长度

给定一个数组 nums 和一个目标值 k,找到和等于 k 的最长连续子数组长度。如果不存在任意一个符合要求的子数组,则返回 0。

class Solution:
    def maxSubArrayLen(self, nums: List[int], k: int) -> int:
        n = len(nums)
        indexs = defaultdict(int)
        indexs[0] = 0
        sums = 0 
        res = 0
        for i in range(n):
            sums = sums + nums[i]
            if sums not in indexs:
                indexs[sums] = i+1
            if sums-k in indexs:
                res = max(res, i - indexs[sums-k] + 1)
        return res

区间加法

假设你有一个长度为 n 的数组,初始情况下所有的数字均为 0,你将会被给出 k​​​​​​​ 个更新的操作。

其中,每个操作会被表示为一个三元组:[startIndex, endIndex, inc],你需要将子数组 A[startIndex … endIndex](包括 startIndex 和 endIndex)增加 inc。

请你返回 k 次操作后的数组。
链接:https://leetcode.cn/problems/range-addition

class Solution:
    def getModifiedArray(self, length: int, updates: List[List[int]]) -> List[int]:
        nums = [0]*length
        dic = defaultdict(int)
        dic2 = defaultdict(str)
        for l in updates:
            dic[str(l)] += 1
            dic2[str(l)] = l
        # print(dic)
        for k,v in dic.items():
            s,e,i = dic2[k]
            for j in range(s, e+1):
                nums[j] += i*v
        return nums

给单链表加一

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def plusOne(self, head: ListNode) -> ListNode:
        nums = 0
        arr = []
        head0 = ListNode(0)
        while head:
            nums = nums*10 + head.val
            head = head.next
        nums+=1
        while nums != 0:
            a = nums%10
            nums = nums//10
            arr.insert(0, a)
        head = head0
        while arr:
            head0.next = ListNode()
            head0 = head0.next
            a = arr.pop(0)
            head0.val = a
            # tmp = ListNode()
        return head.next

寻找二叉树的叶子节点

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def findLeaves(self, root: Optional[TreeNode]) -> List[List[int]]:
        ans = defaultdict(list)
        def dfs(root):
            if not root:
                return 0
            l, r = dfs(root.left), dfs(root.right)
            depth = max(l, r) + 1
            ans[depth].append(root.val)
            return depth
        dfs(root)
        return [v for k,v in ans.items()]

285、二叉搜索树中的中序后继

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def inorderSuccessor(self, root: 'TreeNode', p: 'TreeNode') -> 'TreeNode':
        res = []
        def mid(root):
            if not root:
                return
            mid(root.left)
            res.append(root)
            mid(root.right)
        mid(root)
        for i in range(len(res)):
            if i+1 < len(res) and res[i] == p:
                return res[i+1]
        return None

536、从字符串生成二叉树

你需要用一个包括括号和整数的字符串构建一棵二叉树。

输入的字符串代表一棵二叉树。它包括整数和随后的 0 、1 或 2 对括号。整数代表根的值,一对括号内表示同样结构的子树。

若存在子结点,则从左子结点开始构建。
链接:https://leetcode.cn/problems/construct-binary-tree-from-string

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def str2tree(self, s: str) -> TreeNode:
        if len(s) == 0:
            return None
        if "(" not in s:
            return TreeNode(int(s[:]))
        pos = s.index('(')
        # print(s, s.index('('))
        root = TreeNode(int(s[:pos]))
        start = pos
        cnt = 0
        for i in range(pos, len(s)):
            if s[i] == '(': cnt+=1
            if s[i] == ')': cnt-=1
            if cnt==0 and start == pos:
                root.left = self.str2tree(s[start+1:i])
                start = i+1
            elif cnt==0 and start != pos:
                root.right = self.str2tree(s[start+1:i])
        return root

582、杀掉进程

class Solution:
    def killProcess(self, pid: List[int], ppid: List[int], kill: int) -> List[int]:
        subprocess = {kill}
        res = {kill}
        # tmp = subprocess
        while subprocess:
            tmp = set()
            for i in range(len(pid)):
                if ppid[i] in subprocess:
                    tmp.add(pid[i])
            res = res.union(tmp)
            subprocess = tmp
        return list(res)

531、孤独元素

给你一个大小为 m x n 的图像 picture ,图像由黑白像素组成,‘B’ 表示黑色像素,‘W’ 表示白色像素,请你统计并返回图像中 黑色 孤独像素的数量。

黑色孤独像素 的定义为:如果黑色像素 ‘B’ 所在的同一行和同一列不存在其他黑色像素,那么这个黑色像素就是黑色孤独像素。

链接:https://leetcode.cn/problems/lonely-pixel-i

class Solution:
    def findLonelyPixel(self, picture: List[List[str]]) -> int:
        dic_x = []
        dic_y = []
        m = len(picture)
        n = len(picture[0])
        res = 0
        row = defaultdict(int)
        col = defaultdict(int)
        for i in range(m):
            for j in range(n):
                if picture[i][j] == "B" :
                    row[i] += 1
                    col[j] += 1
        
        for i in range(m):
            for j in range(n):
                if picture[i][j] == "W":
                    continue
                elif picture[i][j] == "B" and (row[i]==1 and col[j]==1):
                    res+=1
        return res

有序数组中的确实元素

现有一个按 升序 排列的整数数组 nums ,其中每个数字都 互不相同 。

给你一个整数 k ,请你找出并返回从数组最左边开始的第 k 个缺失数字。

class Solution:
    def missingElement(self, nums: List[int], k: int) -> int:
        if len(nums)<=1:
            return nums[0]+1
        pre = nums[0]
        for x in nums:
            diff = x - pre - 1
            if diff >= k:
                return pre + k
            elif diff == -1 and x == nums[0]:
                continue
            else:
                k -= diff
                pre = x
        return nums[-1] + k

至多包含K个不同字符的最长子串

给你一个字符串 s 和一个整数 k ,请你找出 至多 包含 k 个 不同 字符的最长子串,并返回该子串的长度。

class Solution:
    def lengthOfLongestSubstringKDistinct(self, s: str, k: int) -> int:
        hash_map = defaultdict(int)
        left, right = 0, 0
        n = len(s)
        res = 0
        if len(s) <= k:
            return len(s)
        while right < n:
            hash_map[s[right]] = right
            right += 1
            if len(hash_map) == k+1:
                index = min(hash_map.values())
                del hash_map[s[index]]
                left = index + 1
            res = max(res, right-left)
        return res

562、矩阵中最长的连续1线段

给定一个 m x n 的二进制矩阵 mat ,返回矩阵中最长的连续1线段。
这条线段可以是水平的、垂直的、对角线的或者反对角线的。

class Solution:
    def longestLine(self, mat: List[List[int]]) -> int:
        m, n = len(mat), len(mat[0])
        self.res = 0
        for i in range(m):
            for j in range(n):
                if mat[i][j] == 1:
                    for dr, dc in [(1,0),(1,-1),(1,1),(0,1)]:
                        tmp = 1
                        nr, nc = dr+i, dc+j
                        while 0<=nr<m and 0<=nc<n and mat[nr][nc]==1:
                            tmp += 1
                            nr += dr
                            nc += dc
                        self.res = max(self.res, tmp)
        return self.res

244、最短单词距离二

请设计一个类,使该类的构造函数能够接收一个字符串数组。然后再实现一个方法,该方法能够分别接收两个单词,并返回列表中这两个单词之间的最短距离。

实现 WordDistanc 类:

WordDistance(String[] wordsDict) 用字符串数组 wordsDict 初始化对象。
int shortest(String word1, String word2) 返回数组 worddict 中 word1 和 word2 之间的最短距离。

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/shortest-word-distance-ii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

class WordDistance:

    def __init__(self, wordsDict: List[str]):
        self.wordsDict = wordsDict
        self.word = defaultdict(list)
        for idx, word in enumerate(self.wordsDict):
            self.word[word].append(idx)

    def shortest(self, word1: str, word2: str) -> int:
        res = float("inf")
        index1 = self.word[word1]
        index2 = self.word[word2]
        i, j = 0, 0
        while i<len(index1) and j<len(index2):
            res = min(res, abs(index1[i]-index2[j]))
            if index1[i] > index2[j]:
                j+=1
            else:
                i+=1
        return res

247、中心对称数

给定一个整数 n ,返回所有长度为 n 的 中心对称数 。你可以以 任何顺序 返回答案。

中心对称数 是一个数字在旋转了 180 度之后看起来依旧相同的数字(或者上下颠倒地看)。

链接:https://leetcode.cn/problems/strobogrammatic-number-ii

class Solution:
    def findStrobogrammatic(self, n: int) -> List[str]:
        dic1 = {"0":"0", "1":"1", "6":"9", "8":"8", "9":"6"}
        dic2 = {"0":"0", "1":"1", "8":"8"}
        def dfs1(ans):
            if len(ans) == n:
                self.res.append(ans)
                return
            for k,v in dic1.items():
                dfs1(k+ans+v)
        def dfs2(ans):
            if len(ans) == n:
                self.res.append(ans)
                return
            for k,v in dic1.items():
                dfs2(k+ans+v)
        self.res = []
        if n%2 == 0:
            dfs1("")
        else:
            for k,v in dic2.items():
                dfs2(k)
        if n > 1:
            for idx,x in enumerate(self.res):
                if x[0]=="0":
                    self.res.pop(idx)
        return self.res
        

161、相隔为1的编辑距离

给定两个字符串 s 和 t ,如果它们的编辑距离为 1 ,则返回 true ,否则返回 false 。

字符串 s 和字符串 t 之间满足编辑距离等于 1 有三种可能的情形:

往 s 中插入 恰好一个 字符得到 t
从 s 中删除 恰好一个 字符得到 t
在 s 中用 一个不同的字符 替换 恰好一个 字符得到 t

链接:https://leetcode.cn/problems/one-edit-distance

class Solution:
    def isOneEditDistance(self, s: str, t: str) -> bool:
        if abs(len(s)-len(t)) > 1:
            return False
        if s == t:
            return False

        i, j = 0, 0
        while i<len(s) and j<len(t) and s[i] == t[j] :
            i+=1
            j+=1
        if len(s) == len(t):
            for z in range(i+1,len(s)):
                if s[z] != t[z]:
                    return False
        elif len(s) > len(t):
            for z in range(j, len(t)):
                if s[z+1] != t[z]:
                    return False
        else:
            for z in range(i, len(s)):
                if s[z] != t[z+1]:
                    return False
        return True

250、统计同值子树

给定一个二叉树,统计该二叉树数值相同的子树个数。

同值子树是指该子树的所有节点都拥有相同的数值。

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def countUnivalSubtrees(self, root: Optional[TreeNode]) -> int:
        self.res = 0
        def dfs(root):
            if not root: return None
            if not root.right and not root.left:
                self.res += 1
                return root.val
            left = dfs(root.left)
            right = dfs(root.right)
            if left == right == root.val or (right is None and left == root.val) or (left is None and right ==root.val):
                self.res += 1
                return root.val 
            return inf
        dfs(root)
        return self.res

251、展开二维向量

请设计并实现一个能够展开二维向量的迭代器。该迭代器需要支持 next 和 hasNext 两种操作。

class Vector2D:

    def __init__(self, vec: List[List[int]]):
        self.vec = [x for l in vec for x in l]
    def next(self) -> int:
        return self.vec.pop(0)

    def hasNext(self) -> bool:
        if len(self.vec) > 0:
            return True
        else: return False


# Your Vector2D object will be instantiated and called as such:
# obj = Vector2D(vec)
# param_1 = obj.next()
# param_2 = obj.hasNext()

259、较小的三数之和

给定一个长度为 n 的整数数组和一个目标值 target ,寻找能够使条件 nums[i] + nums[j] + nums[k] < target 成立的三元组 i, j, k 个数(0 <= i < j < k < n)。
链接:https://leetcode.cn/problems/3sum-smaller

class Solution:
    def threeSumSmaller(self, nums: List[int], target: int) -> int:
        self.res = 0
        nums.sort()
        if len(nums)<3: 
            if len(nums)==3 and sum(nums)<target:
                return 1
            else: return 0
        if nums[0]>0 and nums[0]>target: return 0
        def dfs(l, idx):
            if len(l) == 3:
                if sum(l) < target:
                    self.res+=1
                return
            for i in range(idx, len(nums)):
                dfs(l+[nums[i]], i+1)
        dfs([], 0)
        return self.res

271、字符串的编码与解码

class Codec:
    def encode(self, strs: List[str]) -> str:
        """Encodes a list of strings to a single string.
        """
        encoded_str = ""
        self.index = []
        tmp = 0
        for x in strs:
            encoded_str += x 
            tmp += len(x)
            self.index.append(tmp)
        return encoded_str
        

    def decode(self, s: str) -> List[str]:
        """Decodes a single string to a list of strings.
        """
        decoded_str = []
        pre = 0
        for idx in self.index:
            tmp = s[pre:idx]
            pre = idx
            decoded_str.append(tmp)
        return decoded_str

281、锯齿迭代器

给出两个一维的向量,请你实现一个迭代器,交替返回它们中间的元素。

class ZigzagIterator:
    def __init__(self, v1: List[int], v2: List[int]):
        self.v = []
        i, j = 0, 0
        while i<len(v1) and j<len(v2):
            self.v.append(v1[i])
            self.v.append(v2[j])
            i+=1
            j+=1
        if i!=len(v1):
            self.v += v1[i:]
        if j!=len(v2):
            self.v += (v2[j:])
        

    def next(self) -> int:
        return self.v.pop(0)

    def hasNext(self) -> bool:
        if len(self.v)>0: return True
        else: return False

# Your ZigzagIterator object will be instantiated and called as such:
# i, v = ZigzagIterator(v1, v2), []
# while i.hasNext(): v.append(i.next())

276、栅栏涂色

有 k 种颜色的涂料和一个包含 n 个栅栏柱的栅栏,请你按下述规则为栅栏设计涂色方案:

每个栅栏柱可以用其中 一种 颜色进行上色。
相邻的栅栏柱 最多连续两个 颜色相同。
给你两个整数 k 和 n ,返回所有有效的涂色 方案数 。

链接:https://leetcode.cn/problems/paint-fence

class Solution:
    def numWays(self, n: int, k: int) -> int:
        if k == 1:
            if n<=2:
                return 1
            else:
                return 0
        # if n == 1:
        #     return k
        # dp[i][0]:与上一个颜色不一样
        # dp[i][0] = dp[i-1][0]*(k-1) + dp[i-1][1]*k
        # dp[i][1]:与上一个颜色一样
        # dp[i][1] = dp[i-1][0]
        dp = [[0, 0] for _ in range(n)]
        dp[0][0], dp[0][1] = k, 0
        for i in range(1, n):
            dp[i][0] = (dp[i-1][0]+ dp[i-1][1])*(k-1)
            dp[i][1] = dp[i-1][0]
            print(dp[i])
        return dp[n-1][0] + dp[n-1][1]        

286、墙与门

class Solution:
    def wallsAndGates(self, rooms: List[List[int]]) -> None:
        """
        Do not return anything, modify rooms in-place instead.
        """
        #### DFS
        # inf = 2**(31)-1
        # m, n = len(rooms), len(rooms[0])
        # # self.res = [[inf for _ in range(n)] for _ in range(m)]
        # # res = [[inf for _ in range(n)] for _ in range(m)]
        # # for i in range(m):
        # #     for j in range(n):
        # #         res[i][j] = rooms[i][j]

        # def dfs(cur_i, cur_j, nums, vistied):
        #     if nums > rooms[cur_i][cur_j]:
        #         return
        #     rooms[cur_i][cur_j] = min(rooms[cur_i][cur_j], nums)
        #     print(nums, rooms[cur_i][cur_j], cur_i, cur_j)
        #     pathway = [(1,0),(0,1),(-1,0),(0,-1)]
        #     for i in range(4):
        #         dr, dc = pathway[i]
        #         nr, nc = dr+cur_i, dc+cur_j
        #         if 0<=nr
        #             vistied[nr][nc] = True
        #             dfs(nr, nc, nums+1, vistied)
        #             vistied[nr][nc] = False
       
        # for i in range(m):
        #     for j in range(n):
        #         if rooms[i][j] == 0:
        #             vistied = [[False for _ in range(n)] for _ in range(m)]
        #             print(i, j)
        #             dfs(i, j, 0, vistied)
        # # rooms = res.copy()
        
        #### BFS
        queue = []
        m, n = len(rooms), len(rooms[0])
        inf = 2**(31)-1
        for i in range(m):
            for j in range(n):
                if rooms[i][j] == 0:
                    queue.append([i, j, 1])
        while queue:
            cur_i, cur_j, dist = queue.pop(0)
            pathway = [(1,0),(0,1),(-1,0),(0,-1)]
            for i in range(4):
                dr, dc = pathway[i]
                nr, nc = dr+cur_i, dc+cur_j
                if 0<=nr<m and 0<=nc<n and rooms[nr][nc]==inf:
                    queue.append([nr, nc, dist+1])
                    rooms[nr][nc] = dist

288、单词的唯一缩写

单词的 缩写 需要遵循 <起始字母><中间字母数><结尾字母> 这样的格式。如果单词只有两个字符,那么它就是它自身的 缩写 。

以下是一些单词缩写的范例:

dog --> d1g 因为第一个字母 ‘d’ 和最后一个字母 ‘g’ 之间有 1 个字母
internationalization --> i18n 因为第一个字母 ‘i’ 和最后一个字母 ‘n’ 之间有 18 个字母
it --> it 单词只有两个字符,它就是它自身的 缩写

实现 ValidWordAbbr 类:

ValidWordAbbr(String[] dictionary) 使用单词字典 dictionary 初始化对象
boolean isUnique(string word) 如果满足下述任意一个条件,返回 true ;否则,返回 false :
字典 dictionary 中没有任何其他单词的 缩写 与该单词 word 的 缩写 相同。
字典 dictionary 中的所有 缩写 与该单词 word 的 缩写 相同的单词都与 word 相同 。

链接:https://leetcode.cn/problems/unique-word-abbreviation

class ValidWordAbbr:

    def __init__(self, dictionary: List[str]):
        self.dic1 = defaultdict(int)
        self.dic2 = defaultdict(list)

        for word in dictionary:
            if len(word) == 2:
                s = word
            else:
                s = word[0] + str(len(word)-2) + word[-1]
            self.dic1[s] += 1
            self.dic2[s].append(word)

    def isUnique(self, word: str) -> bool:
        if len(word) == 2:
            s = word
        else:
            s = word[0] + str(len(word)-2) + word[-1]
        if s not in self.dic1:
            return True
        else:
            words = self.dic2[s]
            for w in words:
                if w!=word:
                    return False
            return True


# Your ValidWordAbbr object will be instantiated and called as such:
# obj = ValidWordAbbr(dictionary)
# param_1 = obj.isUnique(word)

294、翻转游戏二

你和朋友玩一个叫做「翻转游戏」的游戏。游戏规则如下:

给你一个字符串 currentState ,其中只含 ‘+’ 和 ‘-’ 。你和朋友轮流将 连续 的两个 “++” 反转成 “–” 。当一方无法进行有效的翻转时便意味着游戏结束,则另一方获胜。默认每个人都会采取最优策略。

请你写出一个函数来判定起始玩家 是否存在必胜的方案 :如果存在,返回 true ;否则,返回 false 。
链接:https://leetcode.cn/problems/flip-game-ii
经典回朔

class Solution:
    def canWin(self, currentState: str) -> bool:
        s = list(currentState)
        for i in range(len(s)-1):
            if s[i] == '+' and s[i+1] == '+':
                s[i] = '-'
                s[i+1] = '-'
                if self.canWin(''.join(s)) == False:
                    return True
                s[i] = '+'
                s[i+1] = '+'
        return False

311、稀疏矩阵的乘法

给定两个 稀疏矩阵 :大小为 m x k 的稀疏矩阵 mat1 和大小为 k x n 的稀疏矩阵 mat2 ,返回 mat1 x mat2 的结果。你可以假设乘法总是可能的。

链接:https://leetcode.cn/problems/sparse-matrix-multiplication

class Solution:
    def multiply(self, mat1: List[List[int]], mat2: List[List[int]]) -> List[List[int]]:
        m, k = len(mat1), len(mat1[0])
        n = len(mat2[0])
        res = [[0 for _ in range(n)]for _ in range(m)] 

        for i in range(m):
            for j in range(n):
                for h in range(k):
                    if (len(set(mat1[i][h:]))== 1 and sum(mat1[i][h:])==0) or (len(set(mat2[:][j]))== 1 and sum(mat2[:][j])==0):
                        break
                    res[i][j] += (mat1[i][h]*mat2[h][j])

        return res

320、列举单词的全部缩写

单词的 广义缩写词 可以通过下述步骤构造:先取任意数量的 不重叠、不相邻 的子字符串,再用它们各自的长度进行替换。

例如,“abcde” 可以缩写为:
“a3e”(“bcd” 变为 “3” )
“1bcd1”(“a” 和 “e” 都变为 “1”)
“5” (“abcde” 变为 “5”)
“abcde” (没有子字符串被代替)
然而,这些缩写是 无效的 :
“23”(“ab” 变为 “2” ,“cde” 变为 “3” )是无效的,因为被选择的字符串是相邻的
“22de” (“ab” 变为 “2” , “bc” 变为 “2”) 是无效的,因为被选择的字符串是重叠的
给你一个字符串 word ,返回 一个由 word 的所有可能 广义缩写词 组成的列表 。按 任意顺序 返回答案。

链接:https://leetcode.cn/problems/generalized-abbreviation

class Solution:
    def generateAbbreviations(self, word: str) -> List[str]:
        self.res = set()
        def dfs(ans, idx, flag):
            if idx>=len(word):
                self.res.add(ans)
                return
            for j in range(idx, len(word)):
                if flag == True:
                    dfs(ans+word[idx:j+1], j+1, False)
                else:
                    dfs(ans+str(j-idx+1), j+1, True)
                    dfs(ans+word[idx:j+1], j+1, False)
                    
        dfs('', 0, False)
        return list(self.res)

你可能感兴趣的:(leetcode专栏,算法,leetcode,数据结构)