1. 指针移动速度不同(快慢指针)
141. 环形链表(判断是否有环)
# 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:
slow, fast = head, head
while fast and fast.next:
slow = slow.next
fast = fast.next.next
if slow == fast: return True
return False
class Solution:
def removeDuplicates(self, nums: List[int]) -> int:
slow = 0; fast = 1
while fast < len(nums):
if nums[slow] != nums[fast]:
slow += 1
nums[slow] = nums[fast]
fast += 1
return slow + 1
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def middleNode(self, head: ListNode) -> ListNode:
slow = fast = head
while fast and fast.next:
slow = slow.next
fast = fast.next.next
return slow
class Solution:
def getNext(self, n: int) -> int:
res = 0
while n > 0:
n, d = divmod(n, 10)
res += d ** 2
return res
def isHappy(self, n: int) -> bool:
slow = n; fast = self.getNext(n)
while fast != 1 and slow != fast:
slow = self.getNext(slow)
fast = self.getNext(self.getNext(fast))
return fast == 1
class Solution:
def isHappy(self, n: int) -> bool:
def sqrtsum(n: int) -> int:
return sum(map(lambda x: x ** 2,map(int,list(str(n)))))
if 1 < n < 10 and n != 7: return False
m = sqrtsum(n)
if m == 1: return True
else: return self.isHappy(m)
2. 指针位置不同
2.1 左右指针
2.1.1 回文:
class Solution:
def palindrome(self, s: str, left: int, right: int) -> str:
while(left>=0 and right<len(s) and s[left]==s[right]):
left-=1
right+=1
return s[left+1:right]
def longestPalindrome(self, s: str) -> str:
res=""
for i in range(len(s)):
#奇数回文子串
s1 = self.palindrome(s,i,i)
#偶数回文子串
s2 = self.palindrome(s,i,i+1)
res = res if len(res)>len(s1) else s1
res = res if len(res)>len(s2) else s2
return res
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def isPalindrome(self, head: ListNode) -> bool:
vals = []
cur = head
while cur:
vals.append(cur.val)
cur = cur.next
return vals == vals[::-1]
eg. 409. 最长回文串
class Solution:
def longestPalindrome(self, s: str) -> int:
res = 0
flag = 0
c = Counter(s)
for v in c.values():
if v % 2 == 1: flag = 1
res += v//2*2
return res if flag == 0 else res + 1
class Solution:
def isPalindrome(self, s: str) -> bool:
s = re.sub(r'[^A-Za-z0-9]','',s).lower()
return s==s[::-1]
剑指 Offer II 019. 最多删除一个字符得到回文
class Solution:
def isPalindrome(self, s: str) -> bool:
return s == s[::-1]
def validPalindrome(self, s: str) -> bool:
l = 0; r = len(s) - 1
while l <= r:
# 删除 s[l] 或 s[r], 判断
if s[l] != s[r]:
return self.isPalindrome(s[l:r]) or self.isPalindrome(s[l+1:r+1])
l += 1
r -= 1
return True
剑指 Offer II 020. 回文子字符串的个数
class Solution:
def countSubstrings(self, s: str) -> int:
res = 0
n = len(s)
for k in range(2*n-1):
l = k // 2
r = k // 2 + k % 2
while l >= 0 and r < n and s[l] == s[r]:
res += 1
l -= 1
r += 1
return res
2.1.2 nSum:
2Sum
class Solution:
def twoSum(self, nums: List[int], target: int) -> List[List[int]]:
left = 0; right = len(nums)-1
res = []
nums.sort()
while left < right:
sums = nums[left] + nums[right]
if sums < target:
left += 1
elif sums > target:
right -= 1
else:
res.append([left, right])
# 跳过所有重复元素
while left < right and nums[left] == nums[left+1]: left += 1
while left < right and nums[right] == nums[right-1]: right -= 1
left += 1; right -= 1
return res
3Sum:
class Solution:
def threeSum(self, nums: List[int], target: int) -> List[List[int]]:
res = [];
nums.sort()
for i in range(len(nums)):
left = i + 1; right = len(nums) - 1
if i > 0 and nums[i] == nums[i-1]: continue
while left < right:
sums = nums[i] + nums[left] + nums[right]
if sums < target: left += 1
elif sums > target: right -= 1
else:
res.append([nums[left],nums[i],nums[right]])
while left < right and nums[left] == nums[left+1]: left += 1
while left < right and nums[right] == nums[right-1]: right -= 1
left += 1; right -= 1
return res
eg.
class Solution:
def pairSums(self, nums: List[int], target: int) -> List[List[int]]:
left = 0; right = len(nums)-1
res = []
nums.sort()
while left < right:
sums = nums[left] + nums[right]
if sums == target:
res.append([nums[left], nums[right]])
left += 1; right -= 1
elif sums < target:
left += 1
else:
right -= 1
return res
class Solution:
def twoSum(self, nums: List[int], target: int) -> List[int]:
lo = 0; hi = len(nums) - 1
while lo < hi:
sums = nums[lo] + nums[hi]
if sums == target: return [nums[lo], nums[hi]]
elif sums < target: lo += 1
elif sums > target: hi -= 1
return []
剑指 Offer II 006. 排序数组中两个数字之和
class Solution:
def twoSum(self, numbers: List[int], target: int) -> List[int]:
l = 0; r = len(numbers) - 1
while l <= r:
sums = numbers[l] + numbers[r]
if sums == target: return [l,r]
elif sums < target: l += 1
elif sums > target: r -= 1
class Solution:
def threeSum(self, nums: List[int]) -> List[List[int]]:
res = []; target = 0
nums.sort()
for i in range(len(nums)):
left = i + 1; right = len(nums) - 1
if i > 0 and nums[i] == nums[i-1]: continue
while left < right:
sums = nums[left] + nums[i] + nums[right]
if sums < target: left += 1
elif sums > target: right -= 1
else:
res.append([nums[left],nums[i],nums[right]])
while left < right and nums[left] == nums[left+1]: left += 1
while left < right and nums[right] == nums[right-1]: right -= 1
left += 1; right -= 1
return res
class Solution:
def twoSum(self, nums: List[int], start: int, target: int) -> List[List[int]]:
lo = start; hi = len(nums)-1
res = []
nums.sort()
while lo < hi:
left = nums[lo]; right = nums[hi]
sums = nums[lo] + nums[hi]
if sums < target:
lo += 1
elif sums > target:
hi -= 1
else:
res.append([nums[lo], nums[hi]])
while lo < hi and nums[lo] == left: lo += 1
while lo < hi and nums[hi] == right: hi -= 1
return res
def threeSum(self, nums: List[int]) -> List[List[int]]:
res = []
nums.sort()
for i in range(len(nums)):
twoSumTarget = 0 - nums[i]
twoSumRes = self.twoSum(nums, i+1, twoSumTarget)
for it in twoSumRes:
it.append(nums[i])
res.append(it)
ans = list(set(map(lambda x: tuple(sorted(x)), res)))
return ans
class Solution:
def threeSumClosest(self, nums: List[int], target: int) -> int:
res = nums[0] + nums[1] + nums[2]
nums.sort()
for i in range(len(nums)):
left = i + 1; right = len(nums) - 1
while left < right:
sums = nums[left] + nums[i] + nums[right]
res = sums if abs(sums - target) < abs(res - target) else res
if sums < target: left += 1
elif sums > target: right -= 1
else: return res
return res
2.1.3 example
class Solution:
def maxArea(self, height: List[int]) -> int:
res = 0
left = 0; right = len(height) - 1
while left < right:
# 相同条件下边界距离越远,面积越大,所以设置左右指针从两边向中间移动;哪个边界小,哪个边界移动重新寻找机会,希望用边界高度的增加弥补两边界距离的减小
if height[left] < height[right]:
res = max(res, (right - left) * height[left])
left += 1
else:
res = max(res, (right - left) * height[right])
right -= 1
return res
剑指 Offer 21. 调整数组顺序使奇数位于偶数前面
class Solution:
def exchange(self, nums: List[int]) -> List[int]:
l = 0; r = len(nums) - 1
while l <= r:
while l <= r and nums[l] % 2 == 1:
l += 1
while l <= r and nums[r] % 2 == 0:
r -= 1
if l > r: break
nums[l], nums[r] = nums[r], nums[l]
return nums
class Solution:
def sortColors(self, nums: List[int]) -> None:
"""
Do not return anything, modify nums in-place instead.
"""
if len(nums) < 2: return
# 循环不变量确定循环变量
# 0 in [0, p0), 1 in [p0, i), 2 in [p2, len(nums)]
i = 0; p0 = 0; p2 = len(nums) - 1
# 循环变量 i>p2 时, 跳出循环
while i <= p2:
if nums[i] == 0:
nums[i], nums[p0] = nums[p0], nums[i]
p0 += 1
i += 1
elif nums[i] == 1:
i += 1
else: # nums[i] == 2
nums[i], nums[p2] = nums[p2], nums[i]
# 由于不知道交换回来的nums[p2]的值,所以不对循环变量 i 操作,进入下一次循环判断
p2 -= 1
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def partition(self, head: ListNode, x: int) -> ListNode:
# 不要用连等号
left, right = ListNode(0), ListNode(0)
sml, big = left, right
while head:
if head.val < x:
left.next = head
left = left.next
else:
right.next = head
right = right.next
head = head.next
left.next = big.next
right.next = None
return sml.next
class Solution:
def trap(self, height: List[int]) -> int:
# max min
res = 0
left = 0; right = len(height) - 1
# leftMax[i] 表示下标 i 及其左边的位置中,height 的最大高度,rightMax[i] 表示下标 i 及其右边的位置中,height 的最大高度。
leftmax = rightmax = 0
while left < right:
leftmax = max(leftmax, height[left])
rightmax = max(rightmax, height[right])
# 若 height[left] < height[right], 则 leftmax < rightmax
# 接的雨水由小边决定
if height[left] < height[right]:
res += leftmax - height[left]
left += 1
else:
res += rightmax - height[right]
right -= 1
return res
2.2 前后指针
class Solution:
def oneEditAway(self, first: str, second: str) -> bool:
m = len(first); n = len(second)
if abs(m-n) > 1: return False
for i in range(min(m,n)):
if first[i] != second[i]:
return first[i+1:] == second[i+1:] or first[i+1:] == second[i:] or first[i:] == second[i+1:]
return True
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def deleteNode(self, head: ListNode, val: int) -> ListNode:
cur = head.next
pre = head
if head.val == val:
return head.next
while cur.val != val:
cur = cur.next
pre = pre.next
pre.next = cur.next
return head
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
# hash table
def removeDuplicateNodes(self, head: ListNode) -> ListNode:
pre = None; cur = head
visited = set()
while cur:
if cur.val in visited:
# 删除cur
pre.next = cur.next
else:
visited.add(cur.val)
# pre指针后移到cur
pre = cur
cur = cur.next
return head
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def getKthFromEnd(self, head: ListNode, k: int) -> ListNode:
slow = fast = head
while k > 0:
fast = fast.next
k -= 1
while fast:
slow = slow.next
fast = fast.next
return slow
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def kthToLast(self, head: ListNode, k: int) -> int:
slow = fast = head
while k > 0:
fast = fast.next
k -= 1
while fast:
slow = slow.next
fast = fast.next
return slow.val
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def reverseList(self, head: ListNode) -> ListNode:
pre, cur = None, head
while cur:
# 存储当前链表的下一个节点为临时变量
tmp = cur.next
# 当前链表的下一个指向前一个链表
cur.next = pre
# pre, cur整体往后移动一个位置
pre, cur = cur, tmp
return pre
def reverseList(self, head: ListNode) -> ListNode:
# 递归终止条件
if head is None or head.next is None:
return head
p = self.reverseList(head.next)
head.next.next = head
head.next = None
return p
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def reverseKGroup(self, head: ListNode, k: int) -> ListNode:
# 判断是否有k个节点
def cal_len(head):
p = head
cnt = 0
while p:
cnt += 1
p = p.next
if cnt >= k: return True
return False
# 翻转k个节点
def reverseK(head, k):
pre, cur = None, head
while k:
tmp = cur.next
cur.next = pre
pre, cur = cur, tmp
k -= 1
return pre, cur
# 递归
def dfs(head, k):
if not cal_len(head): return head
pre, cur = reverseK(head, k)
head.next = dfs(cur, k)
return pre
return dfs(head, k)
剑指 Offer II 022. 链表中环的入口节点
# 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:
slow, fast = head, head
while True:
if not fast or not fast.next: return None
slow = slow.next
fast = fast.next.next
if slow == fast: break
slow = head
while slow != fast:
fast = fast.next
slow = slow.next
return slow
剑指 Offer II 023. 两个链表的第一个重合节点
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
p = headA; q = headB
while p != q:
p = p.next if p else headB
q = q.next if q else headA
return p