【LeetCode刷题笔记】1-10题

本文所有题目和部分题解均源于LeetCode
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problemset/all/
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

说来也是惭愧,在大学里就注册了LeetCode账号,而到现在又重新注册了一个账号开始刷题…
若不是最近在深入学习人工智能,我可能不会碰它吧…哈哈

1. 两数之和

  1. 题目

    给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。

    你可以假设每种输入只会对应一个答案。但是,数组中同一个元素不能使用两遍。

    示例:

    给定 nums = [2, 7, 11, 15], target = 9  
    因为 nums[0] + nums[1] = 2 + 7 = 9  
    所以返回 [0, 1]
    
  2. 解题思路
    我们把原先的数组转为字典,通过字典查询加快速度。

  • 判断 target - nums[i] 是否在字典中,不在就添加
  • 通过查询到的字典的值反向获取下标索引
  1. 实现代码
    def twoSum(nums, target):
        dic = {}
        n = len(nums)
        for i in range(n):
            if target - nums[i] in dic:
                return dic[target - nums[i]], i
            else:
                dic[nums[i]] = i
    

2. 两数相加

  1. 题目

    给出两个 非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字。

    如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。

    您可以假设除了数字 0 之外,这两个数都不会以 0 开头。
    示例:

    输入:(2 -> 4 -> 3) + (5 -> 6 -> 4)
    输出:7 -> 0 -> 8
    原因:342 + 465 = 807
    
  2. 解题思路
    通过对每一个位置进行除法运算和取余来确定本位置的值,以及该位置是否需要进一。

  3. 实现代码

  • 在Pycharm上实现代码

    class ListNode:
        def __init__(self, val):
            if isinstance(val, int):
                self.val = val
                self.next = None
    
            elif isinstance(val, list):
                self.val = val[0]
                self.next = None
                cur = self
                for i in val[1:]:
                    cur.next = ListNode(i)
                    cur = cur.next
    
        def gatherAttrs(self):
            return ", ".join("{}: {}".format(k, getattr(self, k)) for k in self.__dict__.keys())
    
        def __str__(self):
            return self.__class__.__name__ + " {" + "{}".format(self.gatherAttrs()) + "}"
    
    
    class Solution:
        def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode:
            if isinstance(l1, list):
                l1 = ListNode(l1)
                l2 = ListNode(l2)
            head = ListNode(0)  # 头结点,无存储,指向链表第一个结点
            node = head  # 初始化链表结点
            s = 0  # 初始化 进一 的数
            while l1 or l2:
                x = l1.val if l1 else 0
                y = l2.val if l2 else 0
                sum = x + y + s  # 对每一位求和
                s = sum // 10  # 求进一(其为0或1)
                node.next = ListNode(sum % 10)  # 取余数,求本位结点
                if l1:  # 求空否,防止出现无后继结点
                    l1 = l1.next
                if l2:  # 同上
                    l2 = l2.next
                node = node.next  # 更新指针
            if s != 0:  # 验证最后一位相加是否需 进一
                node.next = ListNode(1)
            return head.next  # 返回头结点的下一个结点,即链表的第一个结点
    
    
    if __name__ == '__main__':
        test = Solution()
        print(test.addTwoNumbers([1, 3], [2, 1, 3]))
    
    
  • 在LeetCode上实现代码

    # Definition for singly-linked list.
    # class ListNode:
    #     def __init__(self, x):
    #         self.val = x
    #         self.next = None
    
    class Solution:
        def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode:
            head = ListNode(0)  #头结点,无存储,指向链表第一个结点
            node = head         #初始化链表结点
            s = 0           #初始化 进一 的数
            while l1 or l2:
                x = l1.val if l1 else 0
                y = l2.val if l2 else 0
                sum = x + y + s              # 对每一位求和
                s = sum // 10                # 求进一(其为0或1)
                node.next = ListNode(sum % 10)   # 取余数,求本位结点
                if l1:                           # 求空否,防止出现无后继结点
                    l1 = l1.next       
                if l2:                           # 同上
                    l2 = l2.next
                node = node.next                 # 更新指针
            if s != 0:                       # 验证最后一位相加是否需 进一
                node.next = ListNode(1)
            return head.next                     # 返回头结点的下一个结点,即链表的第一个结点
    

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

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

    示例 1:

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

    示例 2:

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

    示例 3:

    输入: "pwwkew" 	
    输出: 3 	
    解释: 因为无重复字符的最长子串是 "wke",
          所以其长度为 3。请注意,你的答案必
          须是子串的长度,"pwke" 是一
          个子序列,不是子串。
    
  2. 解题思路
    本题主要采取遍历的方式来记录最长的字符串。

  • 对字符串进行遍历,若不重复,存入暂存的字符串变量;
  • 遇到重复,则找到重复字符出现的第一个位置,保存其后面的字符串;
  • 比较当前字符串和记录的最长字符串,如果当前更长,则进行替换。
  1. 实现代码
    def lengthOfLongestSubstring(str):
        max_str = ''  # 保存最大字符串长度
        ele_str = ''  # 暂存字符串
        for element in str:
            # 对字符串进行遍历,如果不重复则存入暂存的字符串变量
            if element not in ele_str:
                ele_str += element
            # 遇到重复,则找到重复字符出现的第一个位置,保存其后面的字符串
            else:
                ele_str = ele_str[ele_str.index(element) + 1:]
                ele_str += element
            # 如果当前字符串更长,则进行替换
            if len(ele_str) > len(max_str):
                max_str = ele_str
        return len(max_str)
    

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

  1. 题目
    给定两个大小为 mn 的正序(从小到大)数组 nums1nums2

    请你找出这两个正序数组的中位数,并且要求算法的时间复杂度为 O(log(m + n))

    你可以假设 nums1nums2 不会同时为空。

  2. 解题思路
    我们可以将两个数组合并成一个数组,排序后找到中位数

    (1) 用Python数组的 extend() 函数,将第二个数组的元素添加到第一个数组中 nums1.extend(nums2)
    (2) 对当前数组进行排序 nums1.sort()
    (3) 判断中位数下标,我们设数组长度为 ll = len(nums1),中位数设为 res

    • 若为数组长度为奇数,则中位数为 nums1[l//2]
    • 若为数组长度为偶数,则中位数为 (nums1[l // 2 - 1] + nums1[l // 2]) / 2
  3. 实现代码

    def findMedianSortedArrays(num1, num2):
        num1.extend(num2)
        num1.sort()
        l = len(num1)
        if l % 2 == 1:
            res = num1[l // 2]
        else:
            res = (num1[l // 2 - 1] + num1[l // 2]) / 2
        return res
        
    

5. 最长回文子串

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

    示例 1

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

    示例 2:

    输入: "cbbd" 	
    输出: "bb"
    
  2. 解题思路
    从最长字符串开始比较,比如说字符串长是5,那就先把原串取反进行比较,如果不相等,则缩短长度到4,分别比较,以此类推。

  3. 实现代码

    def longestPalindrome(s):
        for l in range(len(s), -1, -1):
            for i in range(0, len(s) - l + 1):
                res_str = s[i:l + i]
                if res_str == res_str[::-1]:
                    return res_str
    

6. Z字形变换

  1. 题目
    将一个给定字符串根据给定的行数,以从上往下、从左到右进行 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
    
  2. 解题思路
    我们先把

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

    写成下面这个样子,也就是 V 型的,比题目说的 N 型好理解
    可以想象用手捏着最后一个字符,往右拉了一下:

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

    实际上就是,
    对列来说,一直往右走,
    对行来说,碰到边界就改变方向

  3. 实现代码

    def convert(s: str, numRows: int) -> str:
        if numRows <= 1:
            return s
        array = [s for a in range(numRows)]  # ['LEETCODEISHIRING', 'LEETCODEISHIRING', 'LEETCODEISHIRING']
        ans = [list() for b in range(numRows)]  # [[], [], []]
        i, direction = 0, 1
        res = ''
        for j in range(0, len(s)):
            ans[i].append(array[i][j])
            i += direction
            if i == 0 or i == numRows - 1:
                direction *= -1
        res = list()
        for element in ans:
            for k in element:
                res.append(k)
    
    

7. 整数反转

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

    示例 1:

    输入: 123
    输出: 321
    

    示例 2:

    输入: -123
    输出: -321
    

    示例 3:

    输入: 120
    输出: 21
    

    注意:

    假设我们的环境只能存储得下 32 位的有符号整数,则其数值范围为 [−231, 231 − 1]。请根据这个假设,如果反转后整数溢出那么就返回 0。

  2. 解题思路

  • 先将整数转换为字符串;
  • 判断字符串的第一个元素是否为 ‘-’,如果是,加 ‘-’ 并反转字符串,如果不是则直接反转字符串;
  • 判断反转后的字符串是否在 -231~231-1 范围内,若不在返回0。
  1. 实现代码

    def reverse_(x):
        s = str(x)
        if s[0] == '-':
            x = int('-' + s[1:][::-1])
        else:
            x = int(s[::-1])
    
        if (-2 ** 31) < x < (2 ** 31 - 1):
            return x
        else:
            return 0
    

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

  1. 题目
    请你来实现一个 atoi 函数,使其能将字符串转换成整数。

    首先,该函数会根据需要丢弃无用的开头空格字符,直到寻找到第一个非空格的字符为止。接下来的转化规则如下:

    ● 如果第一个非空字符为正或者负号时,则将该符号与之后面尽可能多的连续数字字符组合起来,形成一个有符号整数。
    ● 假如第一个非空字符是数字,则直接将其与之后连续的数字字符组合起来,形成一个整数。
    ● 该字符串在有效的整数部分之后也可能会存在多余的字符,那么这些字符可以被忽略,它们对函数不应该造成影响。

    注意:假如该字符串中的第一个非空格字符不是一个有效整数字符、字符串为空或字符串仅包含空白字符时,则你的函数不需要进行转换,即无法进行有效转换。

    在任何情况下,若函数不能进行有效的转换时,请返回 0 。

    提示:

    本题中的空白字符只包括空格字符 ’ ’ 。
    假设我们的环境只能存储 32 位大小的有符号整数,那么其数值范围为 [−231, 231 − 1]。如果数值超过这个范围,请返回 INT_MAX (231 − 1) 或 INT_MIN (−231) 。

    示例 1:

    输入: "42"
    输出: 42
    

    示例 2:

    输入: "   -42"
    输出: -42
    解释: 第一个非空白字符为 '-', 它是一个负号。
         我们尽可能将负号与后面所有连续出现的数字
         组合起来,最后得到 -42 。
    

    示例 3:

    输入: "4193 with words"
    输出: 4193
    解释: 转换截止于数字 '3' ,
    	  因为它的下一个字符不为数字。
    

    示例 4:

    输入: "words and 987"
    输出: 0
    解释: 第一个非空字符是 'w', 但它不是
    	  数字或正、负号。因此无法执行有效的转换。
    

    示例 5:

    输入: "-91283472332"
    输出: -2147483648
    解释: 数字 "-91283472332" 超过 32 位有符号
          整数范围。 因此返回 INT_MIN。
    
  2. 解题思路
    本题采用正则表达式来匹配关键字,从而得到自己想要的结果。

  3. 实现代码

    import re
    
    def myAtoi(str):
        INT_MIN = -2 ** 31
        INT_NAX = 2 ** 31 - 1
        str = str.lstrip()
        num = 0
        str_re = re.compile('^[\+\-]?\d+')
        num_str = str_re.findall(str)
        for i in num_str:
            num = int(''.join(i))
        if num > INT_NAX:
            num = INT_NAX
        elif num < INT_MIN:
            num = INT_MIN
        return num
    

9. 回文数

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

    示例 1:

    输入: 121
    输出: true
    

    示例 2:

    输入: -121
    输出: false
    解释: 从左向右读, 为 -121 。 从右向左读, 为 121- 。因此它不是一个回文数。
    

    示例 3:

    输入: 10
    输出: false
    解释: 从右向左读, 为 01 。因此它不是一个回文数。
    
  2. 解题思路
    转为字符串,再进行判断

  3. 实现代码

    def isPalindrome(x: int):
        s = str(x)
        # if s == s[::-1]:
        #     return True
        # else:
        #     return False
        return s[::-1] == s
    

10. 正则表达式匹配

  1. 题目
    给你一个字符串 s和一个字符规律p,请你来实现一个支持 '.''*'的正则表达式匹配。

    '.' 匹配任意单个字符
    '*' 匹配零个或多个前面的那一个元素
    

    所谓匹配,是要涵盖 整个 字符串s的,而不是部分字符串。

    说明:

    s可能为空,且只包含从 a-z的小写字母。
    p可能为空,且只包含从 a-z的小写字母,以及字符 .*

    示例 1:

    输入:
    s = "aa"
    p = "a"
    输出: false
    解释: "a" 无法匹配 "aa" 整个字符串。
    

    示例 2:

    输入:
    s = "aa"
    p = "a*"
    输出: true
    解释: 因为 '*' 代表可以匹配零个或多个前面的
    	  那一个元素, 在这里前面的元素就是 'a'。
    	  因此,字符串 "aa" 可被视为 'a' 重复了一次。
    

    示例 3:

    输入:
    s = "ab"
    p = ".*"
    输出: true
    解释: ".*" 表示可匹配零个或多个('*')
    	  任意字符('.')。
    

    示例 4:

    输入:
    s = "aab"
    p = "c*a*b"
    输出: true
    解释: 因为 '*' 表示零个或多个,这里 'c' 为 0 个, 'a' 被重复一次。因此可以匹配字符串 "aab"。
    

    示例 5:

    输入:
    s = "mississippi"
    p = "mis*is*p*."
    输出: false
    
  2. 解题思路
    这里参考的他人的解题思路,不得不说,我怕是长了个假脑子,
    @lru_cache(None)装饰符,实现记忆化搜索,等价于Top-Down动态规划,不懂其用法的可自行百度…

  3. 实现代码

    class Solution:
        @lru_cache(None)
        def isMatch(self, s: str, p: str) -> bool:
            if not p: return not s  # 结束条件
    
            first_match = (len(s) > 0) and p[0] in {s[0], '.'}
            # 先处理 `*`
            if len(p) >=2 and p[1] == '*':
                # 匹配0个 | 多个
                return self.isMatch(s, p[2:]) or (first_match and self.isMatch(s[1:], p))
            
            # 处理 `.` ,匹配一个
            return first_match and self.isMatch(s[1:], p[1:])
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值