15 三数之和
链接: https://leetcode-cn.com/problems/reverse-nodes-in-k-group/
给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有满足条件且不重复的三元组。
注意:答案中不可以包含重复的三元组。
示例:
给定数组 nums = [-1, 0, 1, 2, -1, -4],
满足要求的三元组集合为:
[
[-1, 0, 1],
[-1, -1, 2]
]
方法一:先对数组进行排序,然后通过两个指针求结果
class Solution:
def threeSum(self, nums: List[int]) -> List[List[int]]:
nums.sort()
res = []
for i, num in enumerate(nums[:-2]): # 这里枚举到倒数第二个元素是为了防止后面下标越界
if len(nums) < 3: # 如果数组本身元素个数小于3,那么返回的结果为空列表
break
if nums[0] > 0: # 如果排序后的数组首元素大于0,那么数组所有元素都大于0,不存在符合要求的三元组,返回空列表
break
if nums[0] + nums[1] + nums[2] > 0: # 最小的三个元素相加大于0,不存在符合要求的三元组,返回空列表
break
if i > 0 and nums[i] == nums[i - 1]: # 循环过程中遇到与上个元素相同的值,直接进入下一次循环
continue
left = i + 1 # 左边的指针,用来定位从哪个位置开始求解
right = len(nums) - 1 # 右边的指针从数组末尾开始逐步往left靠拢,通过nums[i]+nums[left]+nums[right]判断
while left < right:
if num + nums[left] + nums[right] < 0: #说明left指向的数比较小,需要往下一个数移
left += 1
elif num + nums[left] + nums[right] > 0: #说明right指向的数让结果过大,需要让right指向小一点的值
right -= 1
else:
res.append([num, nums[left], nums[right]]) #满足a+b+c=0,将结果以列表的形式放入res中
while left < right and nums[left] == nums[left + 1]:
left += 1 #为了去掉重复元素,让left指针移动指向下一个不重复的值
while left < right and nums[right] == nums[right - 1]:
right -= 1 #为了去掉重复元素,让right指针移动指向上一个不重复的值
left, right = left + 1, right - 1 # 当left的下一个与right的上一个都与他们本身指向的值不重复时,分别指向下一个和上一个
return res
方法二:用Python内置的二分查找函数bisect,这个方法是LeetCode上大神的,用Python内置的二分查找函数,方法很巧妙,放在这里供大家参考。
class Solution:
def threeSum(self, nums: List[int]) -> List[List[int]]:
res = []
count = {}
for i in nums:
count[i] = count.get(i, 0) + 1
nums = sorted(count)
for i, num in enumerate(nums):
if count[num] > 1:
if num == 0:
if count[num] > 2:
res.append([0,0,0])
else:
if -num * 2 in count:
res.append([num, num, -num * 2])
if num < 0:
twoSum = -num
left = bisect.bisect_left(nums, twoSum - nums[-1], i + 1)
for i in nums[left: bisect.bisect_right(nums, twoSum // 2, left)]:
j = twoSum - i
if j in count and j != i:
res.append([num, i, j])
return res
169 多数元素
链接:https://leetcode-cn.com/problems/majority-element/
给定一个大小为 n 的数组,找到其中的多数元素。多数元素是指在数组中出现次数大于 ⌊ n/2 ⌋ 的元素。
你可以假设数组是非空的,并且给定的数组总是存在多数元素。
示例 1:
输入: [3,2,3]
输出: 3
示例 2:
输入: [2,2,1,1,1,2,2]
输出: 2
方法一:将数组排序后取中间的值,这里利用了题目中多数元素在数组中出现次数大于 ⌊ n/2 ⌋ 这一点,在这个基础上,排序后的数组位于中间的元素值总是多数元素
class Solution:
def majorityElement(self, nums: List[int]) -> int:
nums.sort()
return nums[len(nums)//2]
方法二:用两个变量num和count,num存储元素值,count用于计数,遇到等于num的元素时,num不变,count加一;遇到不等于num的元素时,若count不等于0,那么count减一;当遇到不等于num的元素且count等于0时,num等于新的元素值,count重新加一一直到数组循环结束
class Solution:
def majorityElement(self, nums: List[int]) -> int:
count = 0
num = 0
for i in nums:
if num != i:
if count == 0:
num = i
count += 1
else:
count -= 1
else:
count += 1
return num
206 反转链表
链接:https://leetcode-cn.com/problems/reverse-linked-list/
反转一个单链表。
示例:
输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL
进阶:
你可以迭代或递归地反转链表。你能否用两种方法解决这道题?
方法一:迭代法反转链表
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def reverseList(self, head: ListNode) -> ListNode:
if not head or head.next == None:
return head
curr = head
prev = None
Next = head
while curr:
Next = curr.next
curr.next = prev
prev = curr
curr = Next
return prev
方法二:递归反转链表(这个的运行时间和内存消耗都远超迭代法的)
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def reverseList(self, head: ListNode) -> ListNode:
if not head or head.next == None:
return head
newHead = self.reverseList(head.next)
head.next.next = head
head.next = None
return newHead
24 两两交换链表中的节点
链接:https://leetcode-cn.com/problems/swap-nodes-in-pairs/
给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。
你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。
示例:
给定 1->2->3->4, 你应该返回 2->1->4->3。
方法一:设置一个哑结点在头部,然后用三个指针进行交换,需要搞清楚交换后各指针指向的位置。
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def swapPairs(self, head: ListNode) -> ListNode:
if not head or not head.next:
return head
newHead = ListNode()
newHead.next = head
curr = head
prev = newHead
while curr:
if not curr.next:
break
Next = curr.next
curr.next = Next.next
Next.next = curr
prev.next = Next
prev = curr
curr = prev.next
return newHead.next
方法二:递归法
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def swapPairs(self, head: ListNode) -> ListNode:
if not head or not head.next:
return head
curr = head.next
prev = head
prev.next = self.swapPairs(curr.next)
curr.next = prev
return curr
141 环形链表
链接:https://leetcode-cn.com/problems/linked-list-cycle/
给定一个链表,判断链表中是否有环。
为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。
示例 1:
输入:head = [3,2,0,-4], pos = 1
输出:true
解释:链表中有一个环,其尾部连接到第二个节点。
示例 2:
输入:head = [1,2], pos = 0
输出:true
解释:链表中有一个环,其尾部连接到第一个节点。
示例 3:
输入:head = [1], pos = -1
输出:false
解释:链表中没有环。
进阶:
你能用 O(1)(即,常量)内存解决此问题吗?
方法一:用一个集合存储已经遍历过的节点,当遍历到的新节点在集合中出现过,说明存在环
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def hasCycle(self, head: ListNode) -> bool:
haveSeen = set()
while head:
if head in haveSeen:
return True
haveSeen.add(head)
head = head.next
return False
方法二:快慢指针
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def hasCycle(self, head: ListNode) -> bool:
if not head or not head.next:
return False
fast = head
slow = head
while fast and fast.next:
slow = slow.next
if fast.next:
fast = fast.next.next
else:
return False
if slow == fast:
return True
return False
方法三:和用集合的方法类似,将遍历过的节点的值都设置为None,当遍历到的结点的值为None时,说明存在环
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def hasCycle(self, head: ListNode) -> bool:
while head:
if head.val is None:
return True
head.val = None
head = head.next
return False
142 环形链表II
链接:https://leetcode-cn.com/problems/linked-list-cycle-ii/
给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。
说明:不允许修改给定的链表。
示例 1:
输入:head = [3,2,0,-4], pos = 1
输出:tail connects to node index 1
解释:链表中有一个环,其尾部连接到第二个节点。
示例 2:
输入:head = [1,2], pos = 0
输出:tail connects to node index 0
解释:链表中有一个环,其尾部连接到第一个节点。
示例 3:
输入:head = [1], pos = -1
输出:no cycle
解释:链表中没有环。
进阶:
你是否可以不用额外空间解决此题?
方法一:跟上一道题方法一同样的想法,不同在于返回值
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def detectCycle(self, head: ListNode) -> ListNode:
haveSeen = list()
while head:
if head in haveSeen:
return head
haveSeen.append(head)
head = head.next
return head
方法二:快慢指针,假设有环的链表经过n个节点后进入环,且环中有m个节点;当fast指针与slow指针第一次相遇时,fast指针走过的步数是slow指针的两倍,因为fast指针每次走一步,因此fast指针走过的步数为f=2s,又fast指针比slow指针多走整数圈环,因此f-s=am,因此s = am。接下来,指针每次经过进入环的节点所走的步数为n+xm,那么只要slow指针再走n步就能到进入环的节点。令fast=head,当fast与slow都走n步后会在入口节点相遇,此时fast指向的节点即为要求的节点。
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def detectCycle(self, head: ListNode) -> ListNode:
fast = head
slow = head
while True:
if not fast or not fast.next:
return
slow = slow.next
fast = fast.next.next
if slow == fast:
break
fast = head
while fast!= slow:
fast, slow = fast.next, slow.next
return fast
25 K个一组翻转链表
链接:https://leetcode-cn.com/problems/reverse-nodes-in-k-group/
给你一个链表,每 k 个节点一组进行翻转,请你返回翻转后的链表。
k 是一个正整数,它的值小于或等于链表的长度。
如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。
示例:
给你这个链表:1->2->3->4->5
当 k = 2 时,应当返回: 2->1->4->3->5
当 k = 3 时,应当返回: 3->2->1->4->5
说明:
你的算法只能使用常数的额外空间。
你不能只是单纯的改变节点内部的值,而是需要实际进行节点交换。
方法一:迭代法
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def reverseList(self, head: ListNode, tail: ListNode) -> ListNode:
pre = None
curr = head
while curr != tail:
Next = curr.next
curr.next = pre
pre = curr
curr = Next
return pre
def reverseKGroup(self, head: ListNode, k: int) -> ListNode:
newHead = ListNode(0)
newHead.next = head
pre = newHead
end = newHead
while(end.next):
for i in range(k):
if end:
end = end.next
if not end:
break
start = pre.next
nex = end.next
pre.next = self.reverseList(start, nex)
start.next = nex
pre = start
end = pre
return newHead.next
方法二:递归
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def reverseList(self, head: ListNode, tail: ListNode) -> ListNode:
pre = None
curr = head
while curr != tail:
Next = curr.next
curr.next = pre
pre = curr
curr = Next
return pre
def reverseKGroup(self, head: ListNode, k: int) -> ListNode:
if not head or not head.next:
return head
end = head
for i in range(k):
if not end:
return head
end = end.next
newHead = self.reverseList(head, end)
head.next = self.reverseKGroup(end, k)
return newHead