26. 删除有序数组中的重复项
如果不是原地修改,我们完全可以new一个新数组,然后从头到尾遍历一遍,把不重复的元素添加到新数组里面。但是这个题要求原地修改,也就是只能在原数组上面进行一些操作。使用快慢双指针。让快指针在前面走。遇到相同的就跳过继续往后走,遇到不同的,就让slow+1然后替换到这个位置的元素即可。例如1 1 2,slow和fast初始都为0,当fast走到2发现不同的元素,我们肯定要保留第一个1,得先让slow+1替换掉第二个1。
class Solution:
def removeDuplicates(self, nums: List[int]) -> int:
slow = 0
fast = 0
while fast < len(nums):
if nums[fast] != nums[slow]:
slow += 1
nums[slow] = nums[fast]
fast += 1
return slow + 183. 删除排序链表中的重复元素
这个和26题几乎没啥区别,无非是把数组对应的操作变成了对链表的操作而已。只不过需要注意下最后如果slow不为空的话,要把slow的next置为空,不然可能存在多余的元素。
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def deleteDuplicates(self, head: Optional[ListNode]) -> Optional[ListNode]:
slow = head
fast = head
while fast != None:
if fast.val != slow.val:
slow.next = fast
slow = slow.next
fast = fast.next
if slow != None:
slow.next = None
return head
27. 移除元素
这个甚至可以说更简单了,只是需要稍微改下代码。之前我们需要先让slow+1再进行替换,现在需要先替换slow,然后再让slow+1,例如题目给的数据3 2 2 3,slow一开始指向0索引,当fast走到1索引,也就是不等于val的时候,就需要把0索引的3给替换掉。这样从[0,slow-1]区间一定是不包含val元素的。也就是slow个元素,所以返回slow。而26题是区间[0,slow]都是答案,所以返回的是slow+1个元素。·
class Solution:
def removeElement(self, nums: List[int], val: int) -> int:
slow = 0
fast = 0
while fast < len(nums):
if nums[fast] != val:
nums[slow] = nums[fast]
slow += 1
fast += 1
return slow283. 移动零
会了27题,这个也没什么难度了,就相当于让你移除所有的0元素。但是这个题不是返回一个区间长度,而是要看整个数组,那我们在移除完之后,直接把slow后面的元素全部置为0就可以了。
class Solution:
def moveZeroes(self, nums: List[int]) -> None:
"""
Do not return anything, modify nums in-place instead.
"""
slow = 0
fast = 0
while fast < len(nums):
if nums[fast] != 0:
nums[slow] = nums[fast]
slow += 1
fast += 1
for i in range(slow, len(nums)):
nums[i] = 0167. 两数之和 II - 输入有序数组
这个题暴力的话,就是所有数字两两组合,看是否和target相等,但是时间复杂度是$O^n$,还是很高的,然后使用双指针就需要变化一下思路了,不是快慢双指针,而是左右双指针。左指针指向数组的第一个元素,右指针指向数组的最后一个元素。如果和比target小,就让left往右移动,和就会变大了。相反,如果和比target大,就让right向左移动,和就会变小。直到找到一个刚好和为target的两个元素,如果left等于right或者比right大,那就说明不存在这样的两个元素。
class Solution:
def twoSum(self, nums: List[int], target: int) -> List[int]:
left = 0
right = len(nums) - 1
while left < right:
s = nums[left] + nums[right]
if s < target:
left += 1
elif s > target:
right -= 1
else:
return [left + 1, right + 1]返回值需要注意下,数组在代码里是从0开始的。题目要求的顺序是从1开始的。
344. 反转字符串
翻转字符串还是很简单的,只需要交换第一个元素和最后一个元素,交换第二个元素和倒数第二个元素,以此类推就可以了。使用双指针指向第一个元素和最后一个元素,然后不停的交换和移动就行。
class Solution:
def reverseString(self, s: List[str]) -> None:
"""
Do not return anything, modify s in-place instead.
"""
left = 0
right = len(s) - 1
while left < right:
s[left], s[right] = s[right], s[left]
left += 1
right -= 15. 最长回文子串
这个题稍微复杂一点。回文串就是指一个字符串正着读和倒着读是一样的。例如“abcba”,倒着读和正着读都是“abcba”。关于这个题,我们只需要选择一个中心点,从中心点扩散找最长的字符串,然后更新答案即可。
需要先写一个函数,求从中心点扩散的最大回文串,但是回文串可以是奇数也可以是偶数,当left==right的时候,就是奇数了。当while不满足的时候就是最终的答案了。
def func(self, s, left, right):
while left >= 0 and right < len(s) and s[left] == s[right]:
left -= 1
right += 1
return s[left + 1 : right]完整的代码如下,从0开始作为中心点遍历,分别求i作为中心以及i和i+1作为中心的最长回文串。然后更新结果。并且这里我们不用担心i会越界的情况,因为在func函数的while有了判断,可以避免越界。
class Solution:
def longestPalindrome(self, s: str) -> str:
res = ""
for i in range(len(s)):
s1 = self.func(s, i, i)
s2 = self.func(s, i, i + 1)
res = res if len(res) > len(s1) else s1
res = res if len(res) > len(s2) else s2
return res
def func(self, s, left, right):
while left >= 0 and right < len(s) and s[left] == s[right]:
left -= 1
right += 1
return s[left + 1 : right]leetcode数组双指针练习题
本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。
评论交流
欢迎留下你的想法