leetcode:双指针法之-有序数组-去重与合并

21. 合并两个有序链表

将两个升序链表合并为一个新的升序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
示例:
输入:1->2->4, 1->3->4
输出:1->1->2->3->4->4

非常正常的思路,定义两个指针分别指向两个链表,然后分别进行比较,

序号0123456
链表aa0a1a2a3a4a5a6
链表bb0b1b2b3b4b5b6

先比较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

序号ij
数组2233334
序号ij
数组2233334

发现nums[j] != nums[i] ,i=i+1,并将值赋值过去

序号ij
数组2333334

接着,发现nums[j] == nums[i],j = j+1

序号ij
数组2333334

还是相等j = j+1

序号ij
数组2333334

还是相等j = j+1

序号ij
数组2333334

还是相等j = j+1

序号ij
数组2333334

发现nums[j] != nums[i] ,i=i+1,并将值赋值过去

序号ij
数组2343334

结束之后前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的值,替换过去

序号ij
数组01223042

val[i] != 2,就往后走

序号ij
数组01223042

走到这里之后等于2了,然后看j,发现nums[j] == 2,直接往前走,把这个2给丢弃了

序号ij
数组01223042

发现nums[j] != 2,把这个值放到之前nums[i]==2的位置,然后j再往前走,i往后走

序号ij
数组01423042

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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值