删除有序数组中的重复项
给你一个有序数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。
不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。
提示:
0 <= nums.length <= 3 * 104
-104 <= nums[i] <= 104
nums 已按升序排列
解题思路:
首先题目&提示中反复强调了一个很重要的信息,‘有序!升序!’
那么就很容易可以想到用two pointer来解决这个问题
corner case:
因为有 nums.lengths 为0和1的情况,可以先解决一下corner case,当 nums长度为0或者1的时候,必定没有重复元素,直接返回长度即可
一般case:
双指针slow和fast,slow代表最后一个非重复元素,fast代表当前正在遍历的元素
初始化slow指向index为0的元素,fast指向index为1的元素
- 如果slow处元素==fast处元素 (nums[0] == nums[1]),元素的值相同,fast+=1
- 如果slow处元素!=fast处元素 (nums[0] != nums[1]),元素的值不相同,那么我们把slow指针向后移一位,把fast的值赋给slow,这时slow的意义还是‘最后一个非重复元素,fast+=1, fast指针移动到下一个需要检查的元素
以此类推,知道fast指针超出nums数组范围代码:
class Solution: def removeDuplicates(self, nums: List[int]) -> int: if len(nums) <= 1: return len(nums) slow, fast = 0, 1 while fast < len(nums): if nums[slow] != nums[fast]: slow += 1 nums[slow], nums[fast] = nums[fast], nums[slow] fast += 1 return slow+1
我这里没有做删除,因为slow指针之后的元素都是不要的元素,可以直接截断,提交结果也是通过的so
移除元素
给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。
不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。
元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。
提示:
0 <= nums.length <= 100
0 <= nums[i] <= 50
0 <= val <= 100
解题思路:
使用two pointer
- slow指针的systematic meaning是:在slow之前元素都是已确认非val的元素
- fast指针的systematic meaning是:正在遍历查看的元素
处理逻辑是:
- 如果fast指针遇到等于val的元素,slow指针不动,fast指针向后移动,去查看下一个元素
- 如果fast指针遇到非val的元素,把现在这个元素的值赋给 slow指针指向的这个元素,slow指针向后移动一位
当fast指针遍历完数组中全部元素(fast值==数组的长度),遍历结束
这时候
slow指针之前的所有元素则是我们排除掉val值之后的所有元素,因为python数组的index是0开始的,也就是说保留的元素个数等于slow前一个元素的index+1,那就是slow指针,我们直接返回slow指针的值即可。时空复杂度:
Time Complexity: O(N) 仅遍历一遍数组
Space Complexity: O(1) 除两个指针外,未使用其他存储空间代码:
class Solution: def removeElement(self, nums: List[int], val: int) -> int: if len(nums) == 0: return 0 slow = 0 for quick in range(0, len(nums)): if nums[quick] != val: nums[slow] = nums[quick] slow += 1 return slow
三数之和
给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。
注意:答案中不可以包含重复的三元组。
示例 1:
输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]
示例 2:
输入:nums = []
输出:[]
示例 3:
输入:nums = [0]
输出:[]
提示:
0 <= nums.length <= 3000
-105 <= nums[i] <= 105
解题思路:
首先捋清楚2Sum的解题方法:
2Sum有两种应该刻在脑子里的解题方法:用哈希表dict和用双指针two pointer
3Sum就是2Sum 双指针的变形问题
首先,讲一下2Sum双指针解法:
- 将 nums 里的数按从小到大排列,用
nums.sort()
- 然后初始化两个指针,指针left指向第一个元素(
left=0
),指针right指向数组的最后一个元素(right=len(nums)-1
)- 当left指针和rigt指针没有遇到之前,我们求left指针上的数&right指针上的数的和,sum,如果sum==target,那么我们就找到了;如果sum<target,left指针向右移动(aka 让sum变大一点);如果sum>target,right指针向左移动(aka 让sum减小一点)
有2Sum双指针在心,来看3Sum:
- 首先还是先排序
- 然后我们遍历nums中的每一个元素,对于每一个元素nums[i]做2Sum(target=0-nums[i],2Sum的数组范围是nums[i+1:])
- 现在,我们需要解决一下重复值的问题。会有两处的重复值需要我们处理:1、遍历nums中每个元素的时候:我们使用遇到的第一个,第二个第三个通过while continue 不做任何操作。2、2Sum的双指针里,同样,如果left的值与left-1的值相同,left++;如果right的值与right+1的值相同,right–
时空复杂度:
Time Complexity: O(N^2) – 遍历元素O(N),每个内部2Sum O(N), 共ON方
Space Complexity: O(1) – 除了输出结果的list,没有使用其他代码:
class Solution: def threeSum(self, nums: List[int]) -> List[List[int]]: if len(nums) < 3: return [] res = [] L = len(nums) nums.sort() for i in range(L-2): if i>0 and nums[i] == nums[i-1]: continue left, right = i+1, L-1 while left < right: temp_sum = nums[i]+nums[left]+nums[right] if temp_sum == 0: res.append([nums[i], nums[left], nums[right]]) left += 1 right -= 1 while left < right and nums[left] == nums[left-1]: left += 1 while left < right and nums[right] == nums[right+1]: right -= 1 elif temp_sum < 0: left += 1 else: right -= 1 return res