Leetcode刷题记录81-90,python语言
81 搜索旋转排序数组 II (左右指针)
定义函数search来搜索目标值在旋转排序数组中是否存在,参数为旋转排序数组nums和目标值target。
使用二分查找算法,在循环中不断缩小搜索范围。
初始化左右指针,分别指向数组的起始位置和末尾位置。
在循环中,计算中间元素的索引。
如果中间元素等于目标值,直接返回True。
如果左、中、右三个位置的元素值相等,则无法确定哪一部分是有序的,此时将左指针右移、右指针左移,缩小搜索范围。
如果左半段有序,则判断目标值是否在左半段范围内,若在,则将右指针移到中间元素左侧,否则将左指针移到中间元素右侧。
如果右半段有序,则判断目标值是否在右半段范围内,若在,则将左指针移到中间元素右侧,否则将右指针移到中间元素左侧。
循环结束后,若未找到目标值,则返回False。
class Solution:
def search(self, nums: List[int], target: int) -> bool:
left, right = 0, len(nums) - 1
while left <= right:
mid = (left + right) // 2 # //表示取整除法,4.5取4,中间位置的下标
# 如果中间元素等于目标值,直接返回True
if nums[mid] == target:
return True
# 处理左右两段分别有序的情况
if nums[left] == nums[mid] == nums[right]: # 比如[2,5,6,2,2,2,2]这种,三个数一样则无法确定哪一部分是有序的,此时将左指针右移、右指针左移,缩小搜索范围。
left += 1
right -= 1
elif nums[left] <= nums[mid]:
# 左半段有序
if nums[left] <= target < nums[mid]:
right = mid - 1
else:
left = mid + 1
else:
# 右半段有序
if nums[mid] < target <= nums[right]:
left = mid + 1
else:
right = mid - 1
return False
82 删除排序链表中的重复元素
定义了一个ListNode类来表示链表节点,每个节点包含一个值和一个指向下一个节点的指针。
定义了deleteDuplicates函数,用于删除链表中重复的节点,参数为链表的头节点head。
特殊情况处理:若链表为空或只有一个节点,直接返回原链表。
在链表头部添加一个虚拟头节点dummy,以便处理头节点重复的情况。
使用两个指针prev和head,其中prev指向当前已经确认不重复的节点,head用于遍历链表。
在循环中,若当前节点的值等于下一个节点的值,则开始遍历直到找到不重复的节点。
若找到不重复的节点,则将prev.next指向该节点,并更新prev和head。
若当前节点的值不等于下一个节点的值,则直接更新prev和head。
循环结束后,返回虚拟头节点dummy的下一个节点,即为去除重复节点后的新链表的头节点。
# 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]:
# 处理特殊情况,当链表为空或只有一个节点时,直接返回原链表
if not head or not head.next: # if not XXXX,表示 当XXXX为false时执行下面
return head
# 添加一个虚拟头节点,方便处理头节点重复的情况
dummy = ListNode(0)
dummy.next = head
prev = dummy # 用prev来保存返回的结果那些不重复数字
while head and head.next: # 两个都不为空
# 如果当前节点的值等于下一个节点的值,则开始遍历找到不重复的节点
if head.val == head.next.val:
while head.next and head.val == head.next.val: # 这里是说比如连续三四个重复数字,就用上while去跳过这些重复的,
head = head.next
# 跳过重复的节点,貌似头结点跳了两次,跳过重复节点
head = head.next
prev.next = head
else:
# 如果当前节点的值不等于下一个节点的值,则更新prev和head
prev = prev.next
head = head.next
return dummy.next
83 删除排序链表中的重复元素(一个节点,包括两部分data值和next指向)
可参考两篇链表文章,https://blog.csdn.net/charuiyu/article/details/86483930/ ; https://blog.csdn.net/Traceyfind/article/details/131901092
定义了一个ListNode类来表示链表节点,每个节点包含一个值和一个指向下一个节点的指针。
定义了deleteDuplicates函数,用于删除链表中重复的节点,参数为链表的头节点head。
特殊情况处理:若链表为空或只有一个节点,直接返回原链表。
使用两个指针prev和curr,其中prev指向当前已经确认不重复的节点,curr用于遍历链表。
在循环中,若当前节点值与上一个节点值相同,则将当前节点从链表中删除。
否则更新prev和curr的指向。
循环结束后,返回链表的头节点head。
# 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]:
if not head or not head.next:
return head
prev = head # prev是头结点了,他是一个值,不是输出链表,head是输出链表,所以最后return head
curr = head.next
while curr: # 当下一个节点不为空,
# 如果当前节点值与上一个节点值相同,则将当前节点从链表中删除
if prev.val == curr.val:
prev.next = curr.next
else:
# 否则更新prev和curr的指向
prev = curr
curr = curr.next
return head
86 分割链表
定义了一个ListNode类来表示链表节点,每个节点包含一个值和一个指向下一个节点的指针。
定义了partition函数,用于按照给定的值x将链表分割成两部分,小于x的节点在前,大于等于x的节点在后,参数为链表的头节点head和分割值x。
创建了两个虚拟头节点before_head和after_head,分别用于存储小于x的节点和大于等于x的节点。
创建了两个指针before和after,分别指向前半部分链表和后半部分链表的最后一个节点。
遍历原链表,根据节点值的大小将节点连接到相应的链表中。
若节点值小于x,则将该节点连接到前半部分链表中,并更新before指针。
否则将该节点连接到后半部分链表中,并更新after指针。
遍历结束后,将后半部分链表的最后一个节点指向None,前半部分链表的最后一个节点指向后半部分链表的头节点。
返回前半部分链表的头节点。
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def partition(self, head: Optional[ListNode], x: int) -> Optional[ListNode]:
# 创建两个虚拟头节点,分别用于存储小于x的节点和大于等于x的节点
before_head = ListNode(0)
after_head = ListNode(0)
# 创建两个指针,分别指向前半部分链表和后半部分链表
before = before_head
after = after_head
# 遍历原链表,根据节点值的大小将节点连接到相应的链表中
while head: # 当head不为空
if head.val < x:
before.next = head
before = before.next # 更新before指针
else:
after.next = head
after = after.next # 更新指针
head = head.next
# 将前半部分链表与后半部分链表连接起来
after.next = None
before.next = after_head.next # 虚拟节点0的下一个节点
return before_head.next # 虚拟节点0的下一个节点
88 合并两个有序数组
定义了merge函数,用于将两个有序数组合并为一个有序数组,参数为两个有序数组nums1和nums2,以及它们的长度m和n。
定义两个指针p1和p2,分别指向nums1和nums2的末尾。
从后往前遍历数组,将较大的元素放入nums1的末尾。
如果nums1已经遍历完毕,则将nums2中剩余的元素放入nums1中。
如果nums2已经遍历完毕,则退出循环。
如果当前nums1中指针p1所指的元素大于等于nums2中指针p2所指的元素,则将nums1中指针p1所指的元素放入nums1的末尾,并将指针p1向前移动。
否则将nums2中指针p2所指的元素放入nums1的末尾,并将指针p2向前移动。
循环结束后,nums1包含合并后的有序数组。
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.
"""
# 定义两个指针,分别指向nums1和nums2的末尾
p1 = m - 1
p2 = n - 1
# 从后往前遍历数组,将较大的元素放入nums1的末尾
for i in range(m + n - 1, -1, -1): # 类似倒着取数 5 4 3 2 1 0;是总个数之和
if p1 < 0: # nums1指针index,小于零 ;如果nums1已经遍历完毕,则将nums2中剩余的元素放入nums1中。
nums1[i] = nums2[p2] # 则将nums2中剩余的元素放入nums1中。
p2 -= 1 # nums2指针继续走
elif p2 < 0:
break # 结束整个for i循环
elif nums1[p1] >= nums2[p2]: # 在i当前位置,确定出填充的数字
nums1[i] = nums1[p1]
p1 -= 1
else:
nums1[i] = nums2[p2]
p2 -= 1
89 格雷编码
class Solution:
def grayCode(self, n: int) -> List[int]:
result = [] # 创建一个空列表用于存储格雷编码
for i in range(2**n): # 对于0到2的n次方之间的每一个数
result.append(i ^ (i >> 1)) # 将当前数i与右移一位的i异或,并将结果添加到结果列表中
return result # 返回格雷编码序列
90 子集 II
class Solution:
def subsetsWithDup(self, nums: List[int]) -> List[List[int]]:
nums.sort() # 首先对nums进行排序,以便处理重复元素
result = [[]] # 初始化结果为一个空列表(空集是任何集合的子集)
start = 0 # 初始化起始索引为0
for i in range(len(nums)): # 对于nums中的每一个元素
if i == 0 or nums[i] != nums[i-1]: # 如果是第一个元素或者当前元素与上一个元素不相同
start = 0 # 更新起始索引为0, start主要是用来在result前几个小列表中重新添加元素, 元素不一样就要start从零
size = len(result) # 获取当前结果列表的长度
for j in range(start, size): # 遍历结果列表中的每一个子集, 遍历每个小列表,在下面重新添加元素到之前小列表中,。相同元素的话,start就不能上一次加的[1,2]重复,不能[1] + [2]这样, 即start不能从0取
result.append(result[j] + [nums[i]]) # 将当前元素加入到子集中形成新的子集
start = size # 更新起始索引为当前结果列表的长度
return result # 返回最终的子集列表