Leetcode刷题记录1-21,python语言

1 两数之和

哈希表:利用python的字典,键为输入对象,值为输入对象的索引index

class Solution:
    def twoSum(self, nums: List[int], target: int) -> List[int]:
        dict0 = {}
        for i in range(0,len(nums)):
            sub = target - nums[i]
            if sub not in dict0:
                dict0[nums[i]]=i
            else:
                return [dict0[sub],i]

2 两数相加

链表ListNode
% 取余数
// 除法,取整数
/ 除法,取浮点数

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def addTwoNumbers(self, l1: Optional[ListNode], l2: Optional[ListNode]) -> Optional[ListNode]:
        sum1 = l1.val + l2.val    
        l3 = ListNode(sum1 % 10)
        l3.next = ListNode(sum1 // 10)
        p1 = l1.next
        p2 = l2.next
        p3 = l3

        while True:
            if p1 and p2:
                sum2 = p1.val + p2.val +p3.next.val
                p3.next = ListNode(sum2 % 10)
                p3.next.next = ListNode(sum2 // 10)
                p1 = p1.next
                p2 = p2.next
                p3 = p3.next
            elif p1 and not p2: 
                sum2 = p1.val + p3.next.val
                p3.next = ListNode(sum2 % 10)
                p3.next.next = ListNode(sum2 // 10)
                p1 = p1.next
                p3 = p3.next
            elif p2 and not p1: 
                sum2 = p2.val + p3.next.val
                p3.next = ListNode(sum2 % 10)
                p3.next.next = ListNode(sum2 // 10)
                p2 = p2.next
                p3 = p3.next
            else:
                if p3.next.val == 0:
                    p3.next = None
                break
        return l3

3 无重复字符的最长子串

哈希表:字典,键为字母,值为索引

class Solution:
    def lengthOfLongestSubstring(self, s: str) -> int:
        dict0 = {}
        length = len(s)
        if length == 1:
            return length

        head, max_length = 0, 0
        for i in range(length):
            if s[i] in dict0 and head <= dict0[s[i]]:
                head = dict0[s[i]] + 1
            else:
                max_length = max(max_length, i-head+1)
            dict0[s[i]] = i
        return max_length

法二, 滑动窗口

class Solution:
    def lengthOfLongestSubstring(self, s: str) -> int:
        dic, res, i = {}, 0, -1
        for j in range(len(s)):
            if s[j] in dic:
                i = max(dic[s[j]], i) # 更新左指针 i
            dic[s[j]] = j # 哈希表记录
            res = max(res, j - i) # 更新结果
        return res

4 寻找两个正序数组的中位数(Hard)

这段代码定义了两个函数 findMedianSortedArrays 和 findKth。findMedianSortedArrays 函数接受两个正序数组 nums1 和 nums2 作为输入,并返回这两个数组的中位数。findKth 函数用来找到两个数组的第 k 小的元素。
在 findMedianSortedArrays 函数中,如果两个数组的总长度是偶数,就返回中间两个数的平均值;如果总长度是奇数,则返回中间的那个数。
findKth 函数使用了递归的方法,在每次递归中,根据两个数组的中位数来判断应该舍弃哪一半的数组元素,然后继续在剩余的部分中寻找第 k 小的元素。

class Solution:
    def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float:
        total_len = len(nums1) + len(nums2)
        def findKth(k, nums1, nums2):
            if not nums1:
                return nums2[k]
            if not nums2:
                return nums1[k]
            
            index1, index2 = len(nums1) // 2, len(nums2) // 2
            mid1, mid2 = nums1[index1], nums2[index2]
            
            if index1 + index2 < k:
                if mid1 > mid2:
                    return findKth(k - index2 - 1, nums1, nums2[index2 + 1:])
                else:
                    return findKth(k - index1 - 1, nums1[index1 + 1:], nums2)
            else:
                if mid1 > mid2:
                    return findKth(k, nums1[:index1], nums2)
                else:
                    return findKth(k, nums1, nums2[:index2])


        if total_len % 2 == 0:
            return (findKth(total_len // 2, nums1, nums2) + findKth(total_len // 2 - 1, nums1, nums2)) / 2
        else:
            return findKth(total_len // 2, nums1, nums2)

5 最长回文子串

这段代码定义了一个函数 longestPalindrome,它接受一个字符串 s 作为输入,并返回其中最长的回文子串。
该函数使用了中心扩展法,遍历字符串中的每个字符,以当前字符为中心向两边扩展,同时考虑了奇数长度和偶数长度的回文子串。通过不断更新最长回文子串的起始位置和长度,最终得到整个字符串中的最长回文子串。

class Solution:
    def longestPalindrome(self, s: str) -> str:
        if not s:
            return ""

        start = 0
        max_length = 1
        n = len(s)

        def expand_around_center(s: str, left: int, right: int) -> int:
    # 从指定的左右边界向两端扩展,直到无法扩展为止
            while left >= 0 and right < len(s) and s[left] == s[right]:
                left -= 1
                right += 1
            # 返回回文子串的长度
            return right - left - 1    

        # 中心扩展法
        for i in range(n):
            # 以单个字符为中心
            length1 = expand_around_center(s, i, i)
            # 以两个相邻字符的间隙为中心
            length2 = expand_around_center(s, i, i + 1)
            # 取两种中心扩展的最大长度
            cur_length = max(length1, length2)
            # 更新最长回文子串的起始位置和长度
            if cur_length > max_length:
                start = i - (cur_length - 1) // 2
                max_length = cur_length

        return s[start: start + max_length]

6 Z字形变换

这段代码定义了一个函数 convert,它接受一个字符串 s 和一个整数 numRows 作为输入,返回按照 Z 字形排列后的字符串。
在函数内部,我们使用一个长度为 min(numRows, len(s)) 的列表 rows 来存储每一行的字符。然后,我们遍历字符串 s 中的每个字符,根据当前行号 cur_row 将字符添加到对应的行中。当 cur_row 到达第一行或者最后一行时,我们改变方向,以便按照 Z 字形排列字符。
最后,我们将每一行的字符连接起来,得到最终的 Z 字形排列结果。

class Solution:
    def convert(self, s: str, numRows: int) -> str:
        if numRows == 1:
            return s

        rows = [''] * min(numRows, len(s)) # 当取4行,就是这种['', '', '', '']
        direction = 1
        cur_row = 0
        
        for char in s:
            rows[cur_row] += char
            if cur_row == 0:
                direction = 1
            elif cur_row == numRows - 1:
                direction = -1
            cur_row += direction
        
        return ''.join(rows)

7 整数反转

定义一个函数 reverse(x),接受一个整数 x 作为参数。
首先判断输入的整数 x 的正负情况,分别处理。
使用 str(x) 将整数转换为字符串,然后通过切片 [::1] 或者 [1:][::-1] 对字符串进行反转操作。
将反转后的字符串转换为整数,并根据题目要求返回结果。
最后进行边界值判断,如果结果超出了 32 位有符号整数的范围,则返回 0。
执行测试样例,输出结果。

class Solution:
    def reverse(self, x: int) -> int:
        if x >= 0:
            result = int(str(x)[::-1]) # [start : end : step],步长为-1,从右往左取数,索引为-1的开始 倒着取
        else:
            result = -int(str(x)[1:][::-1])

        if result < -2**31 or result > 2**31 - 1:
            return 0
        else:
            return result    

8 字符串转换整数(atoi)

定义一个函数 myAtoi(s),接受一个字符串 s 作为参数。
使用 strip() 方法去除字符串两端的空格。
如果字符串为空,则直接返回 0。
设置一个符号位 sign,默认为正数,如果字符串起始位置是符号位,则根据情况更新符号位,并将字符串截取掉符号部分。
遍历剩余的字符串,处理每个字符,如果是数字则进行累加,如果遇到非数字字符则跳出循环。
将累加得到的数乘以符号位,得到最终结果。
最后处理溢出情况,如果结果超出了 32 位有符号整数的范围,则返回相应的边界值。
执行测试样例,输出结果。

class Solution:
    def myAtoi(self, s: str) -> int:
        s = s.strip( )  # 去除字符串两端的空格 strip() 处理的时候,如果不带参数,默认是清除两边的空白符,例如:/n, /r, /t, ‘ ‘)。
        if not s:  # 处理空字符串情况
            return 0
        
        sign = 1  # 符号位,默认为正数
        if s[0] in ['-', '+']:  # 处理符号位
            if s[0] == '-':
                sign = -1
            s = s[1:]

        num = 0
        for char in s:
            if char.isdigit(): # 字符串所有字符都是数字返回True
                num = num * 10 + int(char) # 每出现下一次,就把上次的乘以10,进位1*10+2=12,12*10+3=123
            else:
                break # 碰到非数字的,跳出整个for循环

        num = sign * num  # 加上符号位,正负号

        # 处理溢出情况
        if num < -2**31:
            return -2**31
        elif num > 2**31 - 1:
            return 2**31 - 1
        else:
            return num

9 回文数

解法:可以将整数转换为字符串,然后判断字符串是否为回文串。记住用while循环。

class Solution:
    def isPalindrome(self, x: int) -> bool:
        if x < 0:
            return False
        
        num_str = str(x)

        left = 0
        right = len(num_str) - 1

        while left < right:
            if num_str[left] != num_str[right]:
                return False
            left += 1
            right -= 1

        return True

11 盛最多水的容器

在代码中,我们使用了两个指针left和right来表示数组的起始位置和结束位置。通过计算min(height[left], height[right]) * (right - left)来得到当前区域的面积,并与已经得到的最大面积max_area进行比较,更新最大面积。然后,根据当前左右指针所指向的高度的大小关系,移动较小的指针,继续寻找更大的面积。最后返回最大面积。

class Solution:
    def maxArea(self, height: List[int]) -> int:
        left = 0
        right = len(height) - 1
        max_area = 0

        while left < right:
            area = min(height[left], height[right]) * (right - left)
            max_area = max(max_area, area)

            if height[left] < height[right]:
                left += 1
            else:
                right -= 1

        return max_area

12 整数转罗马数字

用字典存储每个特殊罗马数字,键为整数,值为罗马数字。在这段代码中,intToRoman 函数接受一个整数作为输入,首先建立了一个字典 roman_dict 用来存储罗马数字与整数的对应关系。然后通过循环遍历字典中的键值对,从大到小逐步减去对应的整数值,并将对应的罗马数字添加到结果字符串 roman_num 中。

class Solution:
    def intToRoman(self, num: int) -> str:
        roman_dict = {
            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_num = ''
        for value, token in roman_dict.items():
            while num >= value:
                roman_num += token
                num -= value
        
        return roman_num

13 罗马数字转整数

在这段代码中,romanToInt 函数接受一个罗马数字字符串作为输入,首先建立了一个字典 roman_dict 用来存储罗马数字与整数的对应关系。然后通过遍历罗马数字字符串,根据规则进行转换并累加得到最终的整数值。在遍历过程中,根据当前字符的值和前一个字符的值来判断是做加法还是减法操作。记得替换值prev_value = cur_value

class Solution:
    def romanToInt(self, s: str) -> int:
        num_dict = {
            'I':1, 'V':5, 'X':10, 'L':50, 'C':100, 'D':500, 'M':1000
            }

        prev_value = 0
        total = 0
        for char in s:
            cur_value = num_dict[char]
            if cur_value > prev_value:
                total += cur_value - 2 * prev_value
            else:
                total += cur_value
            prev_value = cur_value
        return total

14 最长公共前缀

首先判断输入的字符串数组是否为空,如果为空则直接返回空字符串。
初始化公共前缀为第一个字符串,然后遍历字符串数组,逐个比较每个字符串与当前公共前缀的最长公共前缀,更新公共前缀。
最终得到的公共前缀即为最长公共前缀。

class Solution:
    def longestCommonPrefix(self, strs: List[str]) -> str:
        if not strs:
            return ""

        prefix = strs[0]
        for string in strs[1:]: # 循环的是list中的各个元素第一个单词第二个单词第三个单词,而不是单个单个的字母
            while string.find(prefix) != 0: # 只要有一个字母不一样,find()都是-1,都在string里面find()就是0
                prefix = prefix[:-1]
                if not prefix:
                    return ""
        
        return prefix

15 三数之和

双指针用法,left right
首先将数组排序,方便后续操作。
遍历数组,将当前元素作为目标值,使用双指针来寻找满足条件的两个数。
在当前元素后面的范围内使用双指针,通过调整左右指针的值来逼近目标值。
如果找到了满足条件的三个数,则将其加入结果列表中。
最后返回结果列表。

class Solution:
    def threeSum(self, nums: List[int]) -> List[List[int]]:
        nums.sort()  # 先对数组排序
        res = []
        length = len(nums)

        for i in range(length - 2):
            # 跳过重复元素
            if i > 0 and nums[i] == nums[i - 1]:
                continue

            left = i + 1
            right = length - 1
            target = -nums[i]

            while left < right:
                # 找到满足条件的三个数
                if nums[left] + nums[right] == target:
                    res.append([nums[i], 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 nums[left] + nums[right] < target:
                    left += 1 # sort()后 让小的变大
                else:
                    right -= 1 # 让大的变小

        return res

16 最接近的三数之和

class Solution:
    def threeSumClosest(self, nums: List[int], target: int) -> int:
        nums.sort()
        closest_sum = float('inf')

        for i in range(len(nums) - 2):
            left, right = i + 1, len(nums) - 1 # 左指针从i+1开始,右指针最后一位
        
            while left < right:
                current_sum = nums[i] + nums[left] + nums[right]
                
                if abs(current_sum - target) < abs(closest_sum - target):
                    closest_sum = current_sum
                
                if current_sum < target:
                    left += 1
                elif current_sum > target:
                    right -= 1
                else:
                    return current_sum
                    
        return closest_sum

17 电话号码的字母组合

在这段代码中,我们首先建立了一个数字到字母的映射关系,然后使用迭代的方式来生成所有可能的字母组合。我们初始化一个空列表 combinations,然后遍历输入的每一个数字。对于每一个数字,我们将其对应的字母取出,然后将当前已有的组合与字母进行组合,得到新的组合,并存储在 new_combinations 中。最后更新 combinations 为 new_combinations,继续下一轮迭代,直到处理完所有的数字。最终返回所有可能的字母组合。

class Solution:
    def letterCombinations(self, digits: str) -> List[str]:
        if not digits:
            return []
        
        digit_mapping = {
            '2': 'abc',
            '3': 'def',
            '4': 'ghi',
            '5': 'jkl',
            '6': 'mno',
            '7': 'pqrs',
            '8': 'tuv',
            '9': 'wxyz'
        }
        
        combinations = ['']
        
        for digit in digits:
            letters = digit_mapping[digit]
            new_combinations = []
            
            for combination in combinations:
                for letter in letters:
                    new_combinations.append(combination + letter)
            
            combinations = new_combinations
        
        return combinations

18 四数之和

首先对输入数组进行排序,然后使用四个指针来遍历数组,找到所有满足条件的四元组。在遍历的过程中,利用双指针的方法来不断调整左右指针,以逼近目标值。

class Solution:
    def fourSum(self, nums: List[int], target: int) -> List[List[int]]:
        nums.sort()
        n = len(nums)
        result = []
        
        for i in range(n-3): # 最左边的index,第一位
            if i > 0 and nums[i] == nums[i-1]: # 最左边为相同值,跳到下一个i循环
                continue
            
            for j in range(i+1, n-2): # 第二位,从i+1
                if j > i+1 and nums[j] == nums[j-1]: # j的上一次为相同值,下一个j循环
                    continue
                
                left = j + 1 # 左指针,除去第一位 第二位
                right = n - 1 # 右指针
                
                while left < right:
                    total = nums[i] + nums[j] + nums[left] + nums[right]
                    
                    if total == 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 total < target:
                        left += 1
                    else:
                        right -= 1
        
        return result

19 删除链表的倒数

双指针的方法来解决此问题。我们首先创建一个虚拟头结点 dummy,并将其指向链表的头部。然后,我们初始化两个指针 fast 和 slow 都指向 dummy。接着,我们让 fast 先向前移动 n+1 步,然后同时移动 fast 和 slow 直到 fast 到达链表末尾。此时 slow 指向要删除节点的前一个节点,我们只需将 slow.next 指向 slow.next.next 即可删除倒数第 n 个节点。

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def removeNthFromEnd(self, head: Optional[ListNode], n: int) -> Optional[ListNode]:
        dummy = ListNode(0) # 虚拟头结点
        dummy.next = head
        fast = slow = dummy
        
        # 让fast指针先向前移动n+1步。快慢指针相差n+1步是关键,到最后,快指针在尾节点下一个none,慢指针在要删的前一个,就刚好有slow.next = slow.next.next删去操作
        for _ in range(n + 1):
            fast = fast.next
        
        # 同时移动fast和slow,直到fast到达链表末尾
        while fast is not None:
            fast = fast.next
            slow = slow.next
            
        slow.next = slow.next.next
        
        return dummy.next

20 有效的括号

栈的数据结构来解决此问题。我们遍历输入的字符串,对于每个字符,如果是左括号,则将其压入栈中;如果是右括号,则与栈顶元素进行匹配,若匹配则弹出栈顶元素,否则返回False。最后,检查栈是否为空,若为空则表示所有括号都匹配成功,返回True;否则返回False。
这种方法能够有效地检查括号是否匹配,因为栈的特性符合括号匹配的后进先出规则。

class Solution:
    def isValid(self, s: str) -> bool:
        stack = []
        mapping = {')': '(', '}': '{', ']': '['}
        
        for char in s: # 从左往右循环看
            if char in mapping: # 针对字典的键,看char是否为键,若为右括号,
                top_element = stack.pop() if stack else '#' # pop是默认弹出列表中的最后一个元素 若stack非空list时,看stack上一次加入的是否为对应左括号。否则top_element令为 # 井号,一定不匹配。
                if mapping[char] != top_element: # 不匹配,
                    return False
            else:
                stack.append(char)
        
        return not stack # 这里stack为空的话那就是空的s字符串也匹配, not stack意思是返回一个bool类型true 。 判断stack是否为空,为空也是匹配成功

21 合并两个有序链表

首先定义了一个链表节点类ListNode,然后定义了函数mergeTwoLists(l1, l2)来合并两个有序链表。在函数中,通过使用一个dummy节点和一个current指针来构建合并后的链表。接着通过循环比较两个链表的节点值,按顺序将较小的节点接入到合并后的链表中。

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def mergeTwoLists(self, l1: Optional[ListNode], l2: Optional[ListNode]) -> Optional[ListNode]:
        dummy = ListNode(0) # 虚拟头结点
        current = dummy # 指针,
        
        while list1 and list2: # 将l1和l2视为指针,l1和l2都不为空时
            if list1.val < list2.val: # 
                current.next = list1
                list1 = list1.next
            else:
                current.next = list2
                list2 = list2.next
            current = current.next
        
        if list1: #l1不为空时
            current.next = list1
        else: # l1为空时
            current.next = list2
        
        return dummy.next
  • 12
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值