力扣(LeetCode)是一个在线编程平台,主要用于帮助程序员提升算法和数据结构方面的能力。以下是一些力扣上的入门题目,以及它们的解题代码。
--点击进入刷题地址
题目1:三数之和
题目描述:
给定一个包含n个整数的数组nums,判断nums中是否存在三个元素a,b,c ,使得a + b + c = 0 ?找出所有满足条件且不重复的三元组。
代码实现:
def threeSum(nums): res = [] n = len(nums) for i in range(n-2): if i > 0 and nums[i] == nums[i-1]: continue left = i + 1 right = n - 1 while left < right: total = nums[i] + nums[left] + nums[right] if total == 0: 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 total < 0: left += 1 else: right -= 1 return res
解题思路:
- 这个问题是一个经典的数组问题,要求在给定的整数数组中找到所有和为特定目标值的三元组。我们需要遍历数组中的所有可能的三元组,并检查它们的和是否等于目标值。
- 由于题目要求返回所有不重复的三元组,我们需要使用一个集合来存储已经找到的三元组,以便在找到重复的三元组时将其跳过。在遍历数组时,我们可以使用两个指针i和j来分别指向数组中的第一个和第二个数,然后使用第三个指针k从数组的末尾向前遍历。这样我们可以保证每次找到的三元组的第一个数都不相同,从而避免了重复。
- 在找到一个和为目标值的三元组后,我们可以将其添加到结果数组中,并继续遍历数组,直到找到所有的三元组为止。
- 需要注意的是,为了避免重复的三元组,我们需要跳过重复的元素。具体来说,当i和j指向的元素相同时,我们需要跳过它们,继续遍历数组。
- 最后,我们返回结果数组即可。
题目2:三数之和 II
题目描述:
给定一个包含n个整数的数组nums,其中每个元素的值介于1到1000之间。找出nums中同时满足下列三个条件的所有三个整数num1、num2和num3:num1 + num2 + num3 = target,num1 < num2 < num3,num1、num2、num3均不相同。返回所有不重复的三元组。要求时间复杂度为O(n^2)。
解题思路:
这个问题可以使用三重循环遍历数组来解决。首先,我们定义三个指针i、j和k,分别指向数组中的起始位置、第二个数和第三个数。然后,我们使用三重循环遍历数组中的所有可能的三元组,并检查是否满足条件具体来说,我们检查i、j和k指向的三个数是否满足条件,如果满足条件则将它们作为一个三元组添加到结果中最后返回所有不重复的三元组即可。
代码实现:
def threeSum(nums, target): res = [] n = len(nums) for i in range(n): for j in range(i+1, n): for k in range(j+1, n): if nums[i] + nums[j] + nums[k] == target and nums[i] != nums[j] != nums[k]: res.append([nums[i], nums[j], nums[k]]) return res
题目3:矩阵中的路径
给定一个二维矩阵,其中0表示空地,1表示障碍物。从左上角开始,要走到右下角只能向右或向下走,问从左上角走到右下角有多少种不同的路径?
解题思路:
这个问题可以使用动态规划来解决。我们可以定义一个二维数组dp,其中dp[i][j]表示从左上角走到位置(i, j)的路径数。对于位置(0, 0),它只有一种路径,即dp[0][0] = 1。对于其他位置,如果它没有被障碍物阻挡,则可以从上方或左方走到该位置,即dp[i][j] = dp[i-1][j] + dp[i][j-1]。如果它被障碍物阻挡,则无法从上方或左方走到该位置,即dp[i][j] = 0。最后返回dp[n-1][m-1],其中n和m分别为矩阵的行数和列数。
代码实现:
def uniquePaths(matrix): if not matrix: return 0 n, m = len(matrix), len(matrix[0]) dp = [[0] * m for _ in range(n)] dp[0][0] = 1 for i in range(n): for j in range(m): if matrix[i][j] == 1: continue if i > 0: dp[i][j] += dp[i-1][j] if j > 0: dp[i][j] += dp[i][j-1] dp[i][j] -= dp[i-1][j-1] if i > 0 and j > 0 else 0 return dp[n-1][m-1]
题目4:旋转图像
给定一个m x n的矩阵matrix,将其旋转90度并返回结果。旋转后的矩阵应该是一个n x m的矩阵。
解题思路:
这个问题可以使用分治法来解决。我们可以将矩阵分成四个部分:左上角、右上角、右下角和左下角。首先,我们分别对左上角和右上角、左下角和右下角进行旋转操作。然后,我们将左上角和右上角、左下角和右下角的结果合并在一起,得到最终的旋转后的矩阵。具体步骤如下:
- 对左上角和右上角进行旋转操作:将左上角的m x m矩阵旋转90度,得到一个m x m的矩阵。同时,将右上角的(n-m) x (n-m)矩阵旋转90度,得到一个(n-m) x (n-m)的矩阵。这样,左上角和右上角的区域就得到了旋转后的结果。
- 对左下角和右下角进行旋转操作:将左下角区域的(m-n) x m矩阵旋转90度,得到一个m x (m-n)的矩阵。同时,将右下角的(n-m) x (n-m)矩阵旋转90度,得到一个(n-m) x (n-m)的矩阵。这样,左下角和右下角的区域就得到了旋转后的结果。
- 将左上角和右上角、左下角和右下角的区域合并在一起,得到最终的旋转后的矩阵。
def rotateImage(matrix): n = len(matrix) # 遍历每个元素,将其与对应的对称位置的值进行交换 for i in range(n): for j in range(i+1, n): matrix[i][j], matrix[j][i] = matrix[j][i], matrix[i][j] return matrix
题目5:最长递增子序列II
给定一个未排序的整数数组nums,找到最长递增子序列的长度。要求时间复杂度为O(nlogn),且空间复杂度为O(1)。
解题思路:
这个问题可以使用动态规划结合单调栈来解决。首先,我们可以使用单调栈来找到每个元素前面比它小的元素的位置。具体来说,我们可以使用一个栈来维护数组中的元素,遍历数组时,如果当前元素大于栈顶元素,则将栈顶元素弹出,直到找到一个小于等于当前元素的元素或者栈为空为止。然后,我们遍历数组中的每个元素,对于每个元素,我们找到它前面比它小的元素的位置,并更新dp数组。最后返回dp数组中的最大值即可。
代码实现:
def lengthOfLIS(nums): n = len(nums) if n == 0: return 0 dp = [1] * n stack = [] for i in range(n): while stack and nums[i] > nums[stack[-1]]: stack.pop() if not stack: dp[i] = 1 else: dp[i] = dp[stack[-1]] + 1 stack.append(i) return max(dp)
题目6:最大子序和
给定一个整数数组nums,求数组中连续子序列的最大和。要求使用Kadane算法,时间复杂度为O(n)。
解题思路:
这个问题可以使用Kadane算法来解决。Kadane算法的核心思想是维护一个当前的最大子序列和,初始时为0。遍历数组中的每个元素,如果当前元素大于0,则将其加入到当前最大子序列和中,否则将其与当前最大子序列和相减。最后返回最大子序列和即可。
代码实现:
def maxSubArray(nums): if not nums: return 0 max_sum = nums[0] current_sum = nums[0] for i in range(1, len(nums)): if nums[i] > 0: current_sum += nums[i] else: current_sum = nums[i] max_sum = max(max_sum, current_sum) return max_sum
这些题目属于中等难度的算法题,主要涉及矩阵操作、路径寻找、子序列和的最大值、三数之和的条件求解等方面的知识和技巧。解题过程中需要运用循环、递归、动态规划等算法和数据结构,以及一些数学推理和逻辑分析的方法。通过解决这些题目,可以提高编程能力和算法设计水平,加深对数据结构和算法的理解和应用。