LeetCode刷题之路(python)

1.两数之和

给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素不能使用两遍。

def twoSum(self, nums: List[int], target: int) -> List[int]:
	hashmap={}
	for i,num in enumerate(nums):
	    if hashmap.get(target - num) is not None:
	        return [hashmap.get(target - num), i]
	    hashmap[num] = i #这句不能放在if语句之前,解决list中有重复值或target-num=num的情况

在这里插入图片描述

2.两数相加

给出两个 非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字。
如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。
您可以假设除了数字 0 之外,这两个数都不会以 0 开头。

def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode:
        dummy = p = ListNode(None) #保存头结点,返回结果
        s = 0 #每一步的求和暂存变量
        while l1 or l2 or s:           #循环条件:l1 或者l2(没有遍历完成),s(进位)不为0
            s += (l1.val if l1 else 0) + (l2.val if l2 else 0)           #这其实是好多代码,我自己写了好多行,但是作者这样写非常简洁,赞
            p.next = ListNode(s % 10)             #构建新的list存储结果,其实用较长的加数链表存也可以,%10:求个位
            p = p.next                        
            s //= 10                                         #求进位
            l1 = l1.next if l1 else None           
            l2 = l2.next if l2 else None
        return dummy.next

在这里插入图片描述

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

系列:滑动窗口

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

if not s:return 0
        left = 0
        lookup = set()
        n = len(s)
        max_len = 0
        cur_len = 0
        for i in range(n):
            cur_len += 1
            while s[i] in lookup:
                lookup.remove(s[left])
                left += 1
                cur_len -= 1
            if cur_len > max_len:max_len = cur_len
            lookup.add(s[i])
        return max_len

在这里插入图片描述

4.寻找两个正序数组的中位数

系列:归并排序、二分查找

给定两个大小为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。
请你找出这两个正序数组的中位数,并且要求算法的时间复杂度为 O(log(m + n))。
你可以假设 nums1 和 nums2 不会同时为空。

nums1.extend(nums2)
        nums1.sort()
        n = len(nums1)
        if n % 2 == 0:
            return (nums1[int(n/2) - 1] + nums1[int(n/2)])/2
        else:
            return float(nums1[int((n + 1) / 2) - 1])

在这里插入图片描述

5.最长回文子串

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

  • 这个算法巧妙之处是找到了start,max_len和循环i的关系
  • even搜索【0:2】,若不是,则继续搜索【1:3】,与此同时odd加入其中,搜索【0:3】,接下来搜索的是【2:4】和【1:4】,以此类推
  • even搜索【0:2】,若是,max_len+1,even继续搜索【0:3】,然后搜索【1:4】,与此同时odd加入搜索【0:4】
  • 随便假设一个场景,odd在搜索【3:6】时是回文串,则下一循环,even将搜索【3:7】,odd搜索【2:7】.所以,不会漏掉更长回文串
  • 总结起来:
    若不是回文串:even一直搜索max_len+1,odd一直搜索max_len+2。
    若是回文串:even对当前回文串向后扩充一个,odd则向前和后都扩充一个。
    寻找最长回文串,故不用搜索更短的串。
def longestPalindrome(self, s: str) -> str:
        if not s: return ""
        length = len(s)
        if length == 1 or s == s[::-1]: return s
        max_len,start = 1,0
        for i in range(1, length):
        	# 一直搜索长为max_len+1
            even = s[i-max_len:i+1]
            # 一直搜索长为max_len+2
            odd = s[i-max_len-1:i+1]
            if i - max_len - 1 >= 0 and odd == odd[::-1]:
                start = i - max_len - 1
                max_len += 2
                continue
            if i - max_len >= 0 and even == even[::-1]:
                start = i - max_len
                max_len += 1
                continue
        return s[start:start + max_len]

在这里插入图片描述
动态规划(比上面好理解)

def longestPalindrome(self, s: str) -> str:
        n = len(s)
        dp = [[False] * n for _ in range(n)]
        ans = ""
        # 枚举子串的长度 l+1
        for l in range(n):
            # 枚举子串的起始位置 i,这样可以通过 j=i+l 得到子串的结束位置
            for i in range(n):
                j = i + l
                if j >= len(s):
                    break
                if l == 0:
                    dp[i][j] = True
                elif l == 1:
                    dp[i][j] = (s[i] == s[j])
                else:
                    dp[i][j] = (dp[i + 1][j - 1] and s[i] == s[j])
                if dp[i][j] and l + 1 > len(ans):# l+1是回文串长度,因为l从0开始
                    ans = s[i:j+1]
        return ans

在这里插入图片描述

6.Z字形变换

将一个给定字符串根据给定的行数,以从上往下、从左到右进行 Z 字形排列。
比如输入字符串为 “LEETCODEISHIRING” 行数为 3 时,排列如下:
L C I R
E T O E S I I G
E D H N
之后,你的输出需要从左往右逐行读取,产生出一个新的字符串,比如:“LCIRETOESIIGEDHN”。

def convert(self, s: str, numRows: int) -> str:
        if numRows < 2: return s
        res = ["" for _ in range(numRows)]
        i, flag = 0, -1
        for c in s:
            res[i] += c
            # 两个翻转条件
            if i == 0 or i == numRows - 1:
            	flag = -flag
            i += flag
        return "".join(res)

在这里插入图片描述

7.整数反转

给出一个 32 位的有符号整数,你需要将这个整数中每位上的数字进行反转。

def reverse(self, x: int) -> int:
        if x >= 0:
            s = list(str(x))
            s.reverse()
            l = int(''.join(s))
            if l > (2**31 - 1):
                return 0
            return l
        else:
            x = abs(x)
            s = list(str(x))
            s.reverse()
            l = int('-'+''.join(s))
            if l < -2**31:
                return 0
            return l

在这里插入图片描述

8.字符串转换成整数(atoi)

import re
class Solution:
    def myAtoi(self, str: str) -> int:
        INT_MAX = 2147483647    
        INT_MIN = -2147483648
        str = str.lstrip()      #清除左边多余的空格
        num_re = re.compile(r'^[\+\-]?\d+')   #设置正则规则
        num = num_re.findall(str)   #查找匹配的内容
        num = int(*num) #由于返回的是个列表,解包并且转换成整数
        return max(min(num,INT_MAX),INT_MIN)    #返回值

缩成一句,绝了

class Solution:
    def myAtoi(self, s: str) -> int:
        return max(min(int(*re.findall('^[\+\-]?\d+', s.lstrip())), 2**31 - 1), -2**31)

在这里插入图片描述

9.回文数

判断一个整数是否是回文数。回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。

记住这个数学方法:反转一个数
b不断获取个位,a不断移走个位暴露新个位

def isPalindrome(self, x: int) -> bool:
        #方法一,转成字符串
        '''
        return str(x) == str(x)[::-1]
        '''
        #方法二,不用转成字符串的方式
        if x < 0: return False
        a, b = x, 0
        while a != 0:
            b = b * 10 + a % 10
            a = a // 10
        return b == x

在这里插入图片描述

10.正则表达式匹配

给你一个字符串 s 和一个字符规律 p,请你来实现一个支持 ‘.’ 和 ‘’ 的正则表达式匹配。
‘.’ 匹配任意单个字符
'
’ 匹配零个或多个前面的那一个元素
所谓匹配,是要涵盖 整个 字符串 s的,而不是部分字符串。

def isMatch(self, s: str, p: str) -> bool:
        # 装饰符实现记忆化搜索,等价于Top-Down动态规划
        @lru_cache(None)
        def recur(i,j):
            # 结束条件
            if j==len(p): return i==len(s)
            # 首字母匹配
            first_match = (len(s) > i) and (p[j] == s[i] or p[j] == '.')
            # 处理 `*`
            if len(p) >=j+2 and p[j+1] == '*':
                return recur(i, j+2) or (first_match and recur(i+1, j))
            # 处理首字母匹配
            return first_match and recur(i+1, j+1)
        return recur(0,0)

在这里插入图片描述

11.盛最多水的容器

系列:双指针

给你 n 个非负整数 a1,a2,…,an,每个数代表坐标中的一个点 (i, ai) 。在坐标内画 n 条垂直线,垂直线 i 的两个端点分别为 (i, ai) 和 (i, 0)。找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。

def maxArea(self, height: List[int]) -> int:
        i, j, res = 0, len(height) - 1, 0
        while i < j:
            if height[i] < height[j]:
                res = max(res, height[i] * (j - i))
                i += 1
            else:
                res = max(res, height[j] * (j - i))
                j -= 1
        return res

在这里插入图片描述

12.整数转罗马数字

字典+减法 VS 元组+求余
def intToRoman(self, num: int) -> str:
        d = {1000:'M',900:'CM', 500:'D', 400:'CD', 100:'C', 90:'XC', 50:'L', 40:'XL', 10:'X',               9:'IX', 5:'V', 4:'IV', 1:'I'}
        result = ''
        for i in d:
            while num >= i:
                num -= i
                result += d[i]
        return result
def intToRoman(self, num: int) -> str:
	digits = [(1000, "M"), (900, "CM"), (500, "D"), (400, "CD"), (100, "C"), (90, "XC"), 
	          (50, "L"), (40, "XL"), (10, "X"), (9, "IX"), (5, "V"), (4, "IV"), (1, "I")]
    roman_digits = []
    for value, symbol in digits:
        if num == 0: break
        count, num = divmod(num, value)
        
        roman_digits.append(symbol * count)
    return "".join(roman_digits)

在这里插入图片描述

13.罗马数字转整数

def romanToInt(self, s: str) -> int:
        d = {1000:'M',900:'CM', 500:'D', 400:'CD', 100:'C', 90:'XC', 50:'L', 40:'XL', 10:'X',               9:'IX', 5:'V', 4:'IV', 1:'I'}
        result = 0
        for key, value in d.items():
            while value == s[0:1]:
                s = s[1:]
                result = result + key
            while value == s[0:2]:
                s = s[2:]
                result = result + key
        return result

在这里插入图片描述

14.最长公共前缀

编写一个函数来查找字符串数组中的最长公共前缀。
如果不存在公共前缀,返回空字符串 “”。

第一个全自主效率击败99%的题目

def longestCommonPrefix(self, strs: List[str]) -> str:
        if not strs:return ""
        x = strs[0]
        # 提前找到最短字符串提升效率
        for i in range(1, len(strs)):
            if len(strs[i]) < len(x):
                x = strs[i]
        for s in strs:
            while not re.match('^' + x, s):
                x = x[:-1]
                if not x:
                    return ""
        return x

在这里插入图片描述

zip+set思路不错
def longestCommonPrefix(self, strs):
        ans = ''
        for i in zip(*strs):
            if len(set(i)) == 1:
                ans += i[0]
            else:
                break
        return ans

利用python的max()和min(),在Python里字符串是可以比较的,按照ascII值排,所以只需要比较最大最小的公共前缀就是整个数组的公共前缀
def longestCommonPrefix(self, strs):
        if not strs: return ""
        s1 = min(strs)
        s2 = max(strs)
        for i,x in enumerate(s1):
            if x != s2[i]:
                return s2[:i]
        return s1

15.三数之和

双指针

给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有满足条件且不重复的三元组。
注意:答案中不可以包含重复的三元组。

def threeSum(self, nums: List[int]) -> List[List[int]]:
        n=len(nums)
        res=[]
        if not nums or n<3:
            return []
        nums.sort()
        res=[]
        for i in range(n):
            if nums[i]>0:
                return res
            if i>0 and nums[i]==nums[i-1]:
                continue
            L=i+1
            R=n-1
            while L<R:
                if nums[i]+nums[L]+nums[R]==0:
                    res.append([nums[i],nums[L],nums[R]])
                    while L<R and nums[L]==nums[L+1]:
                        L=L+1
                    while L<R and nums[R]==nums[R-1]:
                        R=R-1
                    L=L+1
                    R=R-1
                elif nums[i]+nums[L]+nums[R]>0:
                    R=R-1
                else:
                    L=L+1
        return res

在这里插入图片描述

16.最接近的三数之和

系列:双指针

给定一个包括 n 个整数的数组 nums 和 一个目标值 target。找出 nums 中的三个整数,使得它们的和与 target 最接近。返回这三个数的和。假定每组输入只存在唯一答案。

代码直接改编自上一题

def threeSumClosest(self, nums: List[int], target: int) -> int:
      n=len(nums)
       nums.sort()
       chazhi = 10**4
       res = 0
       for i in range(n - 2):
           if i>0 and nums[i]==nums[i-1]:# 跳过重复
               continue
           L=i+1
           R=n-1
           while L<R:
               tar = nums[i]+nums[L]+nums[R]
               # 此句提高效率
               if tar == target:
                   return target
               if abs(tar - target) < chazhi:
                   res = tar
                   chazhi = abs(tar - target)
               if (tar - target) >= chazhi:
                   R=R-1
               if (target - tar) >= chazhi:
                   L=L+1
       return res

在这里插入图片描述

17.电话号码的字母组合

系列:回溯

给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。
给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。

def letterCombinations(self, digits: str) -> List[str]:
        d = {'2':'abc', '3':'def', '4':'ghi', '5':'jkl', '6':'mno', '7':'pqrs', '8':'tuv', '9':'wxyz'}
        if not digits: return []
        tmp = []
        for s in digits:
            if s in d:
                tmp.append(d[s])
        result = []
        def dfs(s, tmp):
            if not tmp:
                result.append(s)
                return
            for i in tmp[0]:
                dfs(s + i, tmp[1:])
        dfs('', tmp)
        return result

在这里插入图片描述

18.四数之和

给定一个包含 n 个整数的数组 nums 和一个目标值 target,判断 nums 中是否存在四个元素 a,b,c 和 d ,使得 a + b + c + d 的值与 target 相等?找出所有满足条件且不重复的四元组。

还是用双指针

left 和 right 是双指针,外层套两个循环 i 和 j。
最外层 i,j 初始值 i+1 , left 初始值 j+1 ,right 初始值最右边。等 left 和 right 移动重合,j 就 +1,又等重合,j+1,到 j 加到头,i 再加 1,等 i 加到头程序结束。

i 和 j 指针不需要安排那么满,以免初始值就重复。

def fourSum(self, nums: List[int], target: int) -> List[List[int]]:
        result = []
        nums.sort()
        for i in range(len(nums) - 3):
            if i > 0 and nums[i] == nums[i - 1]:
                continue
            for j in range(i + 1, len(nums) - 2):
                if j > i + 1 and nums[j] == nums[j - 1]:
                    continue
                left, right = j + 1, len(nums) - 1
                while left < right:
                    currSum = nums[i] + nums[j] + nums[left] + nums[right]
                    if currSum == target:
                        result.append([nums[i], nums[j], nums[left], nums[right]])
                        while left < right and nums[left] == nums[left + 1]:
                            left += 1
                        while left < right and nums[right] == nums[right - 1]:
                            right -= 1
                        left += 1
                        right -= 1
                    elif currSum < target:
                        left += 1
                    else:
                        right -= 1
        return result 

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值