21. 合并两个有序链表
将两个升序链表合并为一个新的升序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
示例:
输入:1->2->4, 1->3->4
输出:1->1->2->3->4->4
非常正常的思路,定义两个指针分别指向两个链表,然后分别进行比较,
序号 | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
---|---|---|---|---|---|---|---|
链表a | a0 | a1 | a2 | a3 | a4 | a5 | a6 |
链表b | b0 | b1 | b2 | b3 | b4 | b5 | b6 |
先比较a0和b0,a0大于b0的话,就把链表a的指针往后挪一下,指向a1,接着比较a1和b0,如果a1还是小于b0,链表a的指针再往后挪一个,比较a2和b0,如果a2大于了b0,就把链表b的指针往后挪一下,指向b1,接着比较a2和b1,一直比较到最后,这是非常朴素的思想
# Definition for singly-linked list.
class ListNode:
def __init__(self, x):
self.val = x
self.next = None
class Solution:
def mergeTwoLists(self, l1: ListNode, l2: ListNode) -> ListNode:
head = tmp = ListNode(-1)
while l1 and l2:
if l1.val < l2.val:
tmp.next = l1
l1 = l1.next
else:
tmp.next = l2
l2 = l2.next
tmp = tmp.next
if l1:
tmp.next = l1
if l2:
tmp.next = l2
return head.next
这里要求的是新链表是通过拼接给定的两个链表的所有节点组成的。 所以没有新建链表,直接把原来链表拼接上去
88. 合并两个有序数组
给你两个有序整数数组 nums1 和 nums2,请你将 nums2 合并到 nums1 中,使 num1 成为一个有序数组。
说明:
初始化 nums1 和 nums2 的元素数量分别为 m 和 n 。
你可以假设 nums1 有足够的空间(空间大小大于或等于 m + n)来保存 nums2 中的元素。
示例:
输入:
nums1 = [1,2,3,0,0,0], m = 3
nums2 = [2,5,6], n = 3
输出: [1,2,2,3,5,6]
合并两个数组的方法其实和合并链表是一模一样的,但是数组有一个好处是可以直接读取和存储任意位置,我们可以倒序比较,先比较两个数组中最后的位置,也就是最大的值,把两个数组中最大值放在最后面,这样我们就可以不新增空间的情况下,把两个数组存到一个里面,当然这里也是有限制条件的 nums1 有足够的空间(空间大小大于或等于 m + n)来保存 nums2 中的元素
class Solution:
def merge(self, nums1: List[int], m: int, nums2: List[int], n: int) -> None:
"""
Do not return anything, modify nums1 in-place instead.
"""
end = m + n - 1
p = m - 1
q = n - 1
while p >= 0 and q >= 0:
if nums1[p] > nums2[q]:
nums1[end] = nums1[p]
p -= 1
else:
nums1[end] = nums2[q]
q -= 1
end -= 1
nums1[:q+1] = nums2[:q+1]
26. 删除排序数组中的重复项
这个算得上是双指针的一个巧妙应用了,前两个其实是正常的应用。取两个指针,i,j,如果nums[j] == nums[i]说明重复了,我们把 j j j移动一位,接着再进行比较,如果还是相等就继续移动,等到nums[j] 不等于nums[i]时说明是一个新的项了,咱们把i的位置往后挪一位,把这一项赋值给nums[i]
本质上nums[j]用来发现不同项,发现之后就存到前面去
nums[j] == nums[i],j = j+1
序号 | i | j | |||||
---|---|---|---|---|---|---|---|
数组 | 2 | 2 | 3 | 3 | 3 | 3 | 4 |
序号 | i | j | |||||
---|---|---|---|---|---|---|---|
数组 | 2 | 2 | 3 | 3 | 3 | 3 | 4 |
发现nums[j] != nums[i] ,i=i+1,并将值赋值过去
序号 | i | j | |||||
---|---|---|---|---|---|---|---|
数组 | 2 | 3 | 3 | 3 | 3 | 3 | 4 |
接着,发现nums[j] == nums[i],j = j+1
序号 | i | j | |||||
---|---|---|---|---|---|---|---|
数组 | 2 | 3 | 3 | 3 | 3 | 3 | 4 |
还是相等j = j+1
序号 | i | j | |||||
---|---|---|---|---|---|---|---|
数组 | 2 | 3 | 3 | 3 | 3 | 3 | 4 |
还是相等j = j+1
序号 | i | j | |||||
---|---|---|---|---|---|---|---|
数组 | 2 | 3 | 3 | 3 | 3 | 3 | 4 |
还是相等j = j+1
序号 | i | j | |||||
---|---|---|---|---|---|---|---|
数组 | 2 | 3 | 3 | 3 | 3 | 3 | 4 |
发现nums[j] != nums[i] ,i=i+1,并将值赋值过去
序号 | i | j | |||||
---|---|---|---|---|---|---|---|
数组 | 2 | 3 | 4 | 3 | 3 | 3 | 4 |
结束之后前i位保存的就是去重后的数据了
class Solution:
def removeDuplicates(self, nums: List[int]) -> int:
i,j,n = 0,1,len(nums)
while j < n:
if nums[j] == nums[i]:
j += 1
else:
i += 1
nums[i] = nums[j]
return i+1
27. 移除元素
给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。
不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。
元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。
同样是双指针,一个指针指向头,一个指针指向尾,如果头指针的值不等于val,就往后走,如果等于val,咱们就从后面找,找到一个不等与val的值,替换过去
序号 | i | j | ||||||
---|---|---|---|---|---|---|---|---|
数组 | 0 | 1 | 2 | 2 | 3 | 0 | 4 | 2 |
val[i] != 2,就往后走
序号 | i | j | ||||||
---|---|---|---|---|---|---|---|---|
数组 | 0 | 1 | 2 | 2 | 3 | 0 | 4 | 2 |
走到这里之后等于2了,然后看j,发现nums[j] == 2,直接往前走,把这个2给丢弃了
序号 | i | j | ||||||
---|---|---|---|---|---|---|---|---|
数组 | 0 | 1 | 2 | 2 | 3 | 0 | 4 | 2 |
发现nums[j] != 2,把这个值放到之前nums[i]==2的位置,然后j再往前走,i往后走
序号 | i | j | ||||||
---|---|---|---|---|---|---|---|---|
数组 | 0 | 1 | 4 | 2 | 3 | 0 | 4 | 2 |
nums[i]又等于 2了,接着去找不等于2的j,进行替换
class Solution:
def removeElement(self, nums: List[int], val: int) -> int:
p,q = 0,len(nums)-1
while p <= q:
if nums[q] == val:
q -= 1
if nums[p] != val:
p += 1
else:
nums[p] = nums[q]
q -= 1
return p