菜鸟刷题——283移动零-83删除排序链表中的重复元素

力扣283:移动零

题目描述

283移动零

解题思路

对于该题,这里提供三种解题思路。暴力求解法、双指针法与类似快速排序思想。

法一: 暴力求解法

因为该题慕要求在不复制数组的情况下对数组进行原地修改,因此我们在判断一个结点值为0时,便可以立马将数组后面的数据往前挪,然后将数组末尾的数值赋值为0。由于移动数组元素时,末尾的数据一定是0,因此我们可以定义一个指针q指向数组的末尾,当移动一次数组元素,q指针指针便往前移动一步。即q = q - 1。这样可以使得数组每次移动数据时,不必将后续数据全部移动,只需将q指针之前的数据进行移动,因为q指针之后的数据一定全为0。完整代码如下所示:

'''给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。
请注意 ,必须在不复制数组的情况下原地对数组进行操作。'''
class Solution(object):
    def moveZeros(self, nums):
        """
        :type nums: List[int]
        :rtype: None Do not return anything, modify nums in-place instead.
        """
        '''方法一:暴力求解法'''
        length = len(nums)
        p = 0
        q = length-1
        while p<q:
            if nums[p]==0:
                index = p
                for i in range(p+1, length):
                    nums[index] = nums[i]
                    index += 1
                nums[q] = 0
                q -= 1
            else:
                p += 1
        return nums
if __name__ == '__main__':
    nums = [0,1,0,3,12] # 0,1,0,3,12
    aa = Solution()
    result = aa.moveZeros(nums)
    a = 1

法二:双指针法

定义两个指针p,q指向数组,如若q指针指向的数组数值为0,则将q指针的数值赋给p,两个指针同时往后移动;如果q指针指向的数组数值不为0时,则将q指针往后移动。当q指针所指向元素为空时,说明该数组已经遍历完全。这时判断p指针是否指向数组尾端,如若不是,则说明p指针后的所有数据都为0。然后使用循环将p指针后的数据全部赋值为0,完整代码如下:

'''给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。
请注意 ,必须在不复制数组的情况下原地对数组进行操作。'''
class Solution(object):
    def moveZeros(self, nums):
        """
        :type nums: List[int]
        :rtype: None Do not return anything, modify nums in-place instead.
        """
        '''方法二:双指针'''
        length = len(nums)
        p = q = 0
        while q<length:
            if nums[q]!=0:
                nums[p] = nums[q]
                p += 1
            q +=1
        while p<length:
            nums[p] = 0
            p += 1
        return nums
if __name__ == '__main__':
    nums = [0,1,0,3,12] # 0,1,0,3,12
    aa = Solution()
    result = aa.moveZeros(nums)
    a = 1

方法三:快速排序思想

这个方法参考了快速排序的思想。快速排序中需要确定数组中的一个元素作为分割中间点x,然后将所有小于x的元素放在x的左边,大于x的元素放在x的右边。
在这里,我们可以使用0作为这个分割中间点,只要大于0的元素我们就放在0的左边,小于或等于0的我们放在0的右边。完整代码如下:

'''给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。
请注意 ,必须在不复制数组的情况下原地对数组进行操作。'''
class Solution(object):
    def moveZeros(self, nums):
        """
        :type nums: List[int]
        :rtype: None Do not return anything, modify nums in-place instead.
        """
        '''方法三:类似快速排序'''
        length = len(nums)
        p = q = 0
        while q<length:
            if nums[q]!=0:
                index = nums[p]
                nums[p] = nums[q]
                nums[q] = index
                p += 1
            q += 1
        return nums

if __name__ == '__main__':
    nums = [0,1,0,3,12] # 0,1,0,3,12
    aa = Solution()
    result = aa.moveZeros(nums)
    a = 1

希望自己能熟练各种排序算法思路,学会思维拓展!

力扣83:删除排序链表中的重复元素

题目描述

83题目描述

解题思路

该题目的解题方法就非常多了,递归法、迭代法、利用集合等数据结构都可以解决此问题。在这里提供5种解题思路。

方法一:迭代,双指针法

使用两个指针left,right,使left=head,right=head.next。
当right指针所指向的结点非空时,进行下列操作:
当left.val != right.val时,使left.next = right,同时left,right两个指针同时往后移动;
当left.val == right.val时,只将right指针往后移动。
当right指针指向空时,有可能left指针后的元素全部相同。因此需要另外判断。
如果left.val 与 left.next.val相等时,则说明left指针后的所有元素都与left所指元素相等,直接将left.next = None。
完整代码如下:

class ListNode(object):
    def __init__(self, val, next=None):
        self.val = val
        self.next = next
class LinkList(object):
    def __init__(self):
        self.head = None
    def linklist(self, data):
        head = ListNode(-1)
        p = head
        for i in data[:]:
            p.next = ListNode(i)
            p = p.next
        return head.next
class Solution(object):
    def deleteDuplicates(self, head):
        """
        :type head: ListNode
        :rtype: ListNode
        """
        '''方法一:迭代,双指针法(但是感觉自己写的有些繁琐)'''
        if not head: return head # 如果为空
        left, right = head, head.next
        while right:
            if left.val != right.val:
                left.next = right
                left = left.next
            right = right.next
        # 这里处理的是链表最后几个结点的值都是重复的情形下,right结点遍历完链表。
        # 所以我们只需判断left的val值与left.next.val值是否相同
        if left.next:
            if left.val == left.next.val:
                left.next = None
        return head
if __name__ == '__main__':
    head = []
    clist = LinkList()
    list = clist.linklist(head)
    aa = Solution()
    result = aa.deleteDuplicates(list)
    a = 1

觉得自己写的双指针法过于繁琐,后面学习了别人写的双指针法,对自己的双指针法进行了优化。完整代码如下:

class ListNode(object):
    def __init__(self, val, next=None):
        self.val = val
        self.next = next
class LinkList(object):
    def __init__(self):
        self.head = None
    def linklist(self, data):
        head = ListNode(-1)
        p = head
        for i in data[:]:
            p.next = ListNode(i)
            p = p.next
        return head.next
class Solution(object):
    def deleteDuplicates(self, head):
        """
        :type head: ListNode
        :rtype: ListNode
        """
        '''方法一优化'''
        if not head:
            return head
        left, right = head, head.next
        while right:
            if left.val == right.val:
                left.next = right.next
            else:
                left = right
            right = right.next
        return head
if __name__ == '__main__':
    head = []
    clist = LinkList()
    list = clist.linklist(head)
    aa = Solution()
    result = aa.deleteDuplicates(list)
    a = 1

优化过后的方法在right指针遍历完列表后不需要额外判断left指针与left.next指针所指向的数据是否相等了。因为优化的方法是每遇到一个相等的数据,立马将其删除。而原来的方法是直到找到不相等的结点才进行元素的删除。

方法二:单指针(参考冒泡排序)

该方法其实与优化过后的方法一雷同,通过不断的两两比较,如若相同,则立刻进行结点的删除。完整代码如下:

class ListNode(object):
    def __init__(self, val, next=None):
        self.val = val
        self.next = next
class LinkList(object):
    def __init__(self):
        self.head = None
    def linklist(self, data):
        head = ListNode(-1)
        p = head
        for i in data[:]:
            p.next = ListNode(i)
            p = p.next
        return head.next
class Solution(object):
    def deleteDuplicates(self, head):
        """
        :type head: ListNode
        :rtype: ListNode
        """
        '''方法二:单指针'''
        # 不断两两比较,个人觉得有冒泡排序的思想在里头
        p = head
        while p and p.next:
            if p.val == p.next.val: p.next = p.next.next
            p = p.next
        return head
if __name__ == '__main__':
    head = []
    clist = LinkList()
    list = clist.linklist(head)
    aa = Solution()
    result = aa.deleteDuplicates(list)
    a = 1

方法三:递归,跳过连续相等的元素

该方法不断调用自身,跳过连续相等的元素。完整代码如下:

class ListNode(object):
    def __init__(self, val, next=None):
        self.val = val
        self.next = next
class LinkList(object):
    def __init__(self):
        self.head = None
    def linklist(self, data):
        head = ListNode(-1)
        p = head
        for i in data[:]:
            p.next = ListNode(i)
            p = p.next
        return head.next
class Solution(object):
    def deleteDuplicates(self, head):
        """
        :type head: ListNode
        :rtype: ListNode
        """
        '''方法三:递归,跳过连续相等的元素'''
        # 处理空链表与一个元素的链表
        if not head or not head.next:
            return head
        if head.val != head.next.val:
            head.next = self.deleteDuplicates(head.next)
        else:
            move = head.next
            while move and head.val == move.next.val:
                move = move.next
            return self.deleteDuplicates(move)
        return head
if __name__ == '__main__':
    head = []
    clist = LinkList()
    list = clist.linklist(head)
    aa = Solution()
    result = aa.deleteDuplicates(list)
    a = 1

方法四:递归删除下一个相等的元素

前面的方法都是从前往后链接的,这里介绍一种从后往前删除重复结点的方法。完整代码如下:

class ListNode(object):
    def __init__(self, val, next=None):
        self.val = val
        self.next = next
class LinkList(object):
    def __init__(self):
        self.head = None
    def linklist(self, data):
        head = ListNode(-1)
        p = head
        for i in data[:]:
            p.next = ListNode(i)
            p = p.next
        return head.next
class Solution(object):
    def deleteDuplicates(self, head):
        """
        :type head: ListNode
        :rtype: ListNode
        """
        '''方法四:递归删除下一个相等的元素'''
        if not head or not head.next:
            return head
        # 遍历到链表的最后一个结点,这个是从后往前删除
        head.next = self.deleteDuplicates(head.next)
        if head.val !=head.next.val:
            return head
        else:
            head.next      
if __name__ == '__main__':
    head = []
    clist = LinkList()
    list = clist.linklist(head)
    aa = Solution()
    result = aa.deleteDuplicates(list)
    a = 1

方法五:利用set剔除重复结点

这里我们接触set的无序性、不重复性和确定性的三个特性,来达到剔除重复结点的目的。完整代码如下:

class ListNode(object):
    def __init__(self, val, next=None):
        self.val = val
        self.next = next
class LinkList(object):
    def __init__(self):
        self.head = None
    def linklist(self, data):
        head = ListNode(-1)
        p = head
        for i in data[:]:
            p.next = ListNode(i)
            p = p.next
        return head.next
class Solution(object):
    def deleteDuplicates(self, head):
        """
        :type head: ListNode
        :rtype: ListNode
        """
        '''方法五:利用set保存出现过的元素(set:无序性、不重复性、确定性)'''
        if not head or not head.next: return head
        val_set = set()
        val_set.add(head.val)
        root = ListNode(-1)
        root.next = head
        while head and head.next:
            if head.next.val in val_set:
                head.next = head.next.next
            else:
                head = head.next
                val_set.add(head.val)
        return root.next

if __name__ == '__main__':
    head = []
    clist = LinkList()
    list = clist.linklist(head)
    aa = Solution()
    result = aa.deleteDuplicates(list)
    a = 1

如若有别的更好的方法,欢迎大家在评论区分享!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值