【LeetCode】Top100 经典必刷题 04【4/20】

16. 最接近的三数之和

给你一个长度为 n 的整数数组 nums 和 一个目标值 target。请你从 nums 中选出三个整数,使它们的和与 target 最接近。

返回这三个数的和。

假定每组输入只存在恰好一个解。

 

示例 1:

输入:nums = [-1,2,1,-4], target = 1
输出:2
解释:与 target 最接近的和是 2 (-1 + 2 + 1 = 2) 。

示例 2:

输入:nums = [0,0,0], target = 1
输出:0

 

提示:

  • 3 <= nums.length <= 1000
  • -1000 <= nums[i] <= 1000
  • -104 <= target <= 104

python 参考题解:

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

例如,给定数组 nums = [-1,2,1,-4], 和 target = 1. 与 target 最接近的三个数的和为 2. (-1 + 2 + 1 = 2).
以下是解决这个问题的步骤和思路:

以下是用 Python 给出的题解:

def threeSumClosest(nums, target):
    nums.sort()  # 排序
    closest = float('inf')  # 初始化最接近的和为无穷大
    for i in range(len(nums)):
        left, right = i + 1, len(nums) - 1  # 初始化双指针
        while left < right:
            sum_of_three = nums[i] + nums[left] + nums[right]  # 计算三数之和
            if abs(target - sum_of_three) < abs(target - closest):  # 如果找到更接近的和
                closest = sum_of_three  # 更新最接近的和
            if sum_of_three < target:  # 如果和小于目标值,左指针右移
                left += 1
            elif sum_of_three > target:  # 如果和大于目标值,右指针左移
                right -= 1
            else:  # 如果和等于目标值,直接返回结果
                return sum_of_three
    return closest  # 返回最接近的和
# 示例
nums = [-1, 2, 1, -4]
target = 1
print(threeSumClosest(nums, target))  # 输出应为2

解题思路和步骤:

  1. 排序:首先对数组进行排序,这样可以方便地使用双指针法来寻找最接近的三数之和。
  2. 固定一个数:遍历数组,每次固定一个数,然后用双指针在剩余的数组部分中寻找最接近的两个数,使其和最接近目标值。
  3. 双指针:在固定一个数之后,设置两个指针,一个指向固定数的下一个数(left),另一个指向数组末尾(right)。通过比较当前三数之和与目标值的差距,移动两个指针来找到最接近的和。
  4. 更新答案:如果找到的和更接近目标值,则更新答案。
  • 时间复杂度:排序的时间复杂度为 O(nlogn) ,遍历数组的时间复杂度为 O(n),双指针的时间复杂度为 O(n),因此总的时间复杂度为 O(n^2)。
  • 空间复杂度:除了输入的数组外,没有使用额外的空间,所以空间复杂度为 O(1)。

17. 电话号码的字母组合

给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。答案可以按 任意顺序 返回。

给出数字到字母的映射如下(与电话按键相同)。

注意 1 不对应任何字母。

 

示例 1:

输入:digits = "23"
输出:["ad","ae","af","bd","be","bf","cd","ce","cf"]

示例 2:

输入:digits = ""
输出:[]

示例 3:

输入:digits = "2"
输出:["a","b","c"]

 

提示:

  • 0 <= digits.length <= 4
  • digits[i] 是范围 ['2', '9'] 的一个数字。

python 参考题解:

第 17道题是电话号码的组合,题目描述如下:

给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。答案可以按 任意顺序 返回。

电话号码的组合是指使用给定的数字来生成所有可能的电话号码组合。这是一个经典的回溯算法问题。

以下是用 Python 给出的题解:

def letterCombinations(digits):
    if not digits:
        return []
    # 定义一个字典,将数字映射到对应的字母
    phone = {
        '2': ['a', 'b', 'c'],
        '3': ['d', 'e', 'f'],
        '4': ['g', 'h', 'i'],
        '5': ['j', 'k', 'l'],
        '6': ['m', 'n', 'o'],
        '7': ['p', 'q', 'r', 's'],
        '8': ['t', 'u', 'v'],
        '9': ['w', 'x', 'y', 'z']
    }
    # 初始化结果列表
    result = []
    # 回溯函数
    def backtrack(path, mapping):
        # 如果路径长度等于数字长度,说明找到了一个有效的组合,将其添加到结果列表中
        if len(path) == len(digits):
            result.append(''.join(path))
            return
        # 获取当前数字对应的字母列表
        digit = digits[len(path)]
        letters = mapping[digit]
        # 遍历所有可能的字母
        for letter in letters:
            # 添加当前字母到路径中,并递归回溯
            path.append(letter)
            backtrack(path, mapping)
            # 回溯时移除当前字母
            path.pop()
    # 开始回溯
    backtrack([], phone)
    return result
# 示例
digits = "23"
print(letterCombinations(digits))  # 输出: ["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"]

解题思路和步骤:

  1. 定义映射字典:首先,我们定义一个字典 phone,将数字映射到对应的字母列表。
  2. 初始化结果列表:创建一个空列表 result,用于存储所有可能的电话号码组合。
  3. 回溯函数:定义一个递归函数 backtrack,它接受当前路径 path 和映射字典 mapping 作为参数。
  4. 边界条件:如果路径长度等于数字长度,说明找到了一个有效的组合,将其添加到结果列表中,并返回。
  5. 递归调用:对于当前数字,获取对应的字母列表。
  6. 遍历所有可能的字母:对于每个字母,将其添加到路径中,并递归调用 backtrack
  7. 回溯:在递归调用完成后,从路径中移除当前字母,以便尝试其他字母。
  8. 返回结果:遍历完成后,返回结果列表。

这个算法的时间复杂度是 O(3^n),其中 n 是电话号码的长度,因为每个数字都有3个可能的字母。空间复杂度是 O(n),因为我们需要存储递归调用的路径。

18. 四数之和

给你一个由 n 个整数组成的数组 nums ,和一个目标值 target 。请你找出并返回满足下述全部条件且不重复的四元组 [nums[a], nums[b], nums[c], nums[d]] (若两个四元组元素一一对应,则认为两个四元组重复):

  • 0 <= a, b, c, d < n
  • abcd 互不相同
  • nums[a] + nums[b] + nums[c] + nums[d] == target

你可以按 任意顺序 返回答案 。

 

示例 1:

输入:nums = [1,0,-1,0,-2,2], target = 0
输出:[[-2,-1,1,2],[-2,0,0,2],[-1,0,0,1]]

示例 2:

输入:nums = [2,2,2,2,2], target = 8
输出:[[2,2,2,2]]

 

提示:

  • 1 <= nums.length <= 200
  • -109 <= nums[i] <= 109
  • -109 <= target <= 109

python 参考题解:

第 18道题是 "4Sum",题目描述如下: 给定一个包含 n 个整数的数组 nums 和一个目标值 target,判断 nums 中是否存在四个元素 a, b, c, d ,使得 a + b + c + d = target。找出所有满足条件且不重复的四元组。

注意:答案中不可以包含重复的四元组。

示例 1:

输入: nums = [1,0,-1,0,-2,2], target = 0
输出: [[-2,2,1,0],[-2,2,-1,0]]

以下是用 Python 给出的题解:

def fourSum(nums, target):
    # 首先对数组进行排序
    nums.sort()
    result = []
    
    # 遍历数组,固定一个元素
    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:
                # 计算当前四数之和
                total = nums[i] + nums[j] + nums[left] + nums[right]
                # 如果四数之和等于target,添加到结果中
                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
                # 如果四数之和大于target,移动右指针
                elif total > target:
                    right -= 1
                # 如果四数之和小于target,移动左指针
                else:
                    left += 1
                    
    return result
# 示例
print(fourSum([1,0,-1,0,-2,2], 0))  # 输出: [[-2,2,1,0],[-2,2,-1,0]]

解题思路和步骤:

  1. 排序数组:首先,我们对输入的数组 nums 进行排序,以便后续操作。
  2. 遍历数组:使用一个循环遍历数组,固定第一个元素。
  3. 跳过重复元素:在循环中,我们跳过重复的元素,以避免重复的四元组。
  4. 使用双指针:对于每个固定元素,我们使用双指针 leftright 来寻找另外两个元素,使得四数之和等于 target
  5. 添加结果:如果找到满足条件的三元组,我们将其添加到结果列表中。
  6. 返回结果:遍历完成后,返回结果列表。

这个算法的时间复杂度是 O(n^3),因为我们需要对数组进行排序,并且对于每个元素,我们都需要使用双指针来寻找其他两个元素。空间复杂度是 O(n),因为我们需要存储结果列表。

19. 删除链表的倒数第 N 个结点

给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。

 

示例 1:

输入:head = [1,2,3,4,5], n = 2
输出:[1,2,3,5]

示例 2:

输入:head = [1], n = 1
输出:[]

示例 3:

输入:head = [1,2], n = 1
输出:[1]

 

提示:

  • 链表中结点的数目为 sz
  • 1 <= sz <= 30
  • 0 <= Node.val <= 100
  • 1 <= n <= sz

 

进阶:你能尝试使用一趟扫描实现吗?

python 参考题解:

第97道题是 "Interleaving String",题目描述如下: 给定三个字符串 s1、s2、s3,请你判断 s3 是否是由 s1 和 s2 交错组成的。

示例 1:

输入: s1 = "aabcc", s2 = "dbbca", s3 = "aadbbcbcac"
输出: true

示例 2:

输入: s1 = "aabcc", s2 = "dbbca", s3 = "aadbbbaccc"
输出: false

以下是用 Python 给出的题解:

def isInterleave(s1: str, s2: str, s3: str) -> bool:
    # 初始化一个二维数组,用于存储子问题的解
    dp = [[False] * (len(s2) + 1) for _ in range(len(s1) + 1)]
    
    # 初始化第一行和第一列,dp[0][0]始终为True
    dp[0][0] = True
    
    # 遍历s1和s2的字符
    for i in range(1, len(s1) + 1):
        dp[i][0] = dp[i - 1][0] and s1[i - 1] == s3[i - 1]
    for j in range(1, len(s2) + 1):
        dp[0][j] = dp[0][j - 1] and s2[j - 1] == s3[j - 1]
    
    # 遍历s1和s2的字符,更新dp数组
    for i in range(1, len(s1) + 1):
        for j in range(1, len(s2) + 1):
            dp[i][j] = (dp[i - 1][j] and s1[i - 1] == s3[i + j - 1]) or \
                       (dp[i][j - 1] and s2[j - 1] == s3[i + j - 1])
    
    # dp[len(s1)][len(s2)]为True时,s3是由s1和s2交错组成的
    return dp[len(s1)][len(s2)]
# 示例
print(isInterleave("aabcc", "dbbca", "aadbbcbcac"))  # 输出: True
print(isInterleave("aabcc", "dbbca", "aadbbbaccc"))  # 输出: False

解题思路和步骤:

  1. 初始化变量:首先,我们创建一个二维数组 dp,用于存储子问题的解。dp[i][j] 表示字符串 s1 的前 i 个字符和字符串 s2 的前 j 个字符是否可以组成字符串 s3 的前 i + j 个字符。
  2. 初始化第一行和第一列:由于 dp[0][0] 始终为 True,我们不需要为其赋值。对于 dp[0][j]dp[i][0],我们根据题目要求进行初始化。如果 s1[i - 1]s2[j - 1]s3[i + j - 1] 相等,则 dp[i][j]True
  3. 遍历字符串:使用两个循环遍历字符串 s1s2 的每一个字符。
  4. 更新dp数组:对于每个字符,我们根据当前字符与 s3 的对应字符是否相等,以及左上角的子问题是否为 True 来更新 dp[i][j]
  5. 返回结果:遍历完成后,如果 dp[len(s1)][len(s2)]True,则字符串 s3 是由字符串 s1s2 交错组成的;否则不是。

这个算法的时间复杂度是 O(m * n),其中 m 是字符串 s1 的长度,n 是字符

20. 有效的括号

给定一个只包括 '('')''{''}''['']' 的字符串 s ,判断字符串是否有效。

有效字符串需满足:

  1. 左括号必须用相同类型的右括号闭合。
  2. 左括号必须以正确的顺序闭合。
  3. 每个右括号都有一个对应的相同类型的左括号。

 

示例 1:

输入:s = "()"
输出:true

示例 2:

输入:s = "()[]{}"
输出:true

示例 3:

输入:s = "(]"
输出:false

 

提示:

  • 1 <= s.length <= 104
  • s 仅由括号 '()[]{}' 组成

python 参考题解:

第20道题是 "Valid Parentheses",题目描述如下: 给定一个只包括 '(',')','{','}','[',']' 的字符串 s ,判断字符串是否有效。 有效字符串需满足: 1. 左括号必须用相同类型的右括号闭合。 2. 左括号必须以正确的顺序闭合。

示例 1:

输入: "()"
输出: true

示例 2:

输入: "()[]{}"
输出: true

示例 3:

输入: "(]"
输出: false

以下是用 Python 给出的题解:

def isValid(s: str) -> bool:
    # 初始化一个空栈
    stack = []
    # 初始化一个映射字典,用于映射左括号到右括号
    bracket_map = {")": "(", "}": "{", "]": "["}
    
    # 遍历字符串中的每一个字符
    for char in s:
        # 如果当前字符是右括号
        if char in bracket_map.values():
            # 如果栈不为空且栈顶元素是当前字符对应的左括号
            if stack and stack[-1] == bracket_map[char]:
                # 移除栈顶元素
                stack.pop()
            else:
                # 否则返回false
                return False
        # 如果当前字符是左括号
        elif char in bracket_map.keys():
            # 添加当前字符到栈中
            stack.append(char)
            
    # 遍历结束后,如果栈为空,返回true;否则返回false
    return not stack
# 示例
print(isValid("()"))  # 输出: True
print(isValid("()[]{}"))  # 输出: True
print(isValid("(]"))  # 输出: False

解题思路和步骤:

  1. 初始化栈:首先,我们创建一个空栈 stack 来存储左括号。
  2. 创建映射字典:我们创建一个字典 bracket_map,用于映射左括号到对应的右括号。
  3. 遍历字符串:使用一个循环遍历字符串 s 中的每一个字符。
  4. 处理右括号:如果当前字符是右括号,我们检查栈是否为空,如果栈不为空且栈顶元素是当前字符对应的左括号,则移除栈顶元素;否则,返回 False
  5. 处理左括号:如果当前字符是左括号,我们将其添加到栈中。
  6. 返回结果:遍历结束后,如果栈为空,返回 True;否则,返回 False

这个算法的时间复杂度是 O(n),其中 n 是字符串的长度,因为我们只需要遍历字符串一次。空间复杂度是 O(1),因为我们只使用了常数级别的额外空间。

  • 16
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值