文章目录
力扣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:删除排序链表中的重复元素
题目描述
解题思路
该题目的解题方法就非常多了,递归法、迭代法、利用集合等数据结构都可以解决此问题。在这里提供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
如若有别的更好的方法,欢迎大家在评论区分享!