距上一篇双指针的算法介绍已有四个月,换了个忙碌的工作,没时间也没心情刷题了。然而学习是一种信仰,一口气把two pointer剩下的一些题目学习了一下,现在继续总结归纳two pointer问题。
上一节是几个经典的求和问题,这一节是元素交换的几个典型场景。
26. Remove Duplicates from Sorted Array
Given a sorted array nums, remove the duplicates in-place such that each element appear only once and return the new length.
Do not allocate extra space for another array, you must do this by modifying the input array in-place with O(1) extra memory.
Given nums = [0,0,1,1,1,2,2,3,3,4],
Your function should return length = 5,with the first five elements of nums being modified to 0, 1, 2, 3, 4
respectively.It doesn't matter what values are set beyond the returned length.
这一类题目(包括下面的几道题),都是要求返回长度,只要原数组前面元素是相应结果即可,无所谓后面的元素。因此算法的要求是 in-place 不占用额外内存,而且双指针也一定是O(n)的复杂度。
class Solution:
def removeDuplicates(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
numset = set()
j = 0
l = len(nums)
while j < l:
if nums[j] not in numset:
numset.add(nums[j])
nums[len(numset) - 1] = nums[j]
j += 1
return len(numset)
这是鄙人写的,性能还不错,但是当看了其他人的代码后,这里有一个多余的set,占用了额外的空间,当然速度好像是比下面的快了。看下面的解法,与上一个元素比较来判断,因为这是一个排序后的数组。
class Solution:
def removeDuplicates(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
length = len(nums)
if length < 2:
return length
index = 1
for i in range(1,length):
if nums[i] != nums[i-1]:
nums[index] = nums[i]
index += 1
return index
双指针思想体现在,一个指针i 遍历nums数组,一个指针index 指向非重复元素的位置。许多问题都是这种思想~下面我们看一下这个问题的升级版:
80. Remove Duplicates from Sorted Array II
Given a sorted array nums, remove the duplicates in-place such that duplicates appeared at most twice and return the new length.
Do not allocate extra space for another array, you must do this by modifying the input array in-place with O(1) extra memory.
Given nums = [1,1,1,2,2,3],
Your function should return length = 5 with the first five elements of nums being 1, 1, 2, 2 and 3 respectively.It doesn't matter what you leave beyond the returned length.
这一题要求最多重复两次,既然是排序的数组,上一题我们用nums[i] != nums[i-1],这一题我们通过记住上一个数字(即nums[numlen])和出现的次数来控制,numlen是记录长度的指针,由于只控制两次,可以用一个布尔值记录,如果题目改为多次,就用一个count变量控制。
class Solution:
def removeDuplicates(self, nums):
l = len(nums)
if l < 2:
return l
i = 1
numlen = 1
f = 1
while i < l:
if nums[i] != nums[numlen-1]:
nums[numlen] = nums[i]
numlen += 1
f = 1
elif nums[i] == nums[numlen-1] and f:
nums[numlen] = nums[i]
numlen += 1
f = 0
i += 1
return numlen
27. Remove Element
Given an array nums and a value val, remove all instances of that value in-place and return the new length.
Do not allocate extra space for another array, you must do this by modifying the input array in-place with O(1) extra memory.
The order of elements can be changed. It doesn't matter what you leave beyond the new length.
Given nums = [0,1,2,2,3,0,4,2], val = 2,Your function should return length = 5, with the first five elements of
nums containing 0, 1, 3, 0, and 4. Note that the order of those five elements can be arbitrary.It doesn't matter what values are set beyond the returned length.
上面是去重,这一题是去掉钦定的某个数字。把上面的问题想明白了,这一题很容易构建相应的双指针算法结构。
class Solution:
def removeElement(self, nums, val):
if not nums:
return 0
l = len(nums)
i = 0
j = l - 1
while i <= j:
if nums[i] == val:
while nums[j] == val and j > i:
j -= 1
nums[i] = nums[j]
j -= 1
if j <= i:
break
i += 1
return j + 1
指针i 从头指向非val的元素,遇到等于val的就要交换一个;j 从末尾向前遍历,将非val的值交换到前面。此题是典型的元素交换,由于不要求数组后面元素是啥,所以实际上没有进行交换==。
不过,两个指针的停止条件(while语句和break语句),以及指针停止的各种情况,最后返回的为什么是j+1 ,朋友们还需要琢磨一下,我写完博客也要再琢磨琢磨= =
283. Move Zeroes
Given an array nums, write a function to move all 0
's to the end of it while maintaining the relative order of the non-zero elements.
Input: [0,1,0,3,12]
Output: [1,3,12,0,0]
最后一题,也十分简洁,不同的是不返回长度,要求保持原来的顺序,而且前面是非0的,后面是0,这样我们就必须交换元素了。看下面代码,一个指针n指向非0的元素,指针i从头遍历~由于要保持原来的顺序,不可用两个指针一头一尾。
class Solution:
def moveZeroes(self, nums):
n = 0
for i in range(len(nums)):
if nums[i]:
if n != i:
nums[n] = nums[i]
nums[i] = 0
n += 1
元素交换的一类题到此了,各种情况对指定数字交换位置到前排,双指针的元素交换一般是一个指针从头指向需保留的元素的位置,另一个指针遍历数组。敬请收看后续双指针的问题~