递归是一种算法或函数的编程技巧,它通过直接或间接调用自身来解决问题。在递归过程中,一个问题被分解为更小的子问题,直到问题的规模变得足够小,可以直接求解。
在Python中,我们可以使用递归来解决许多问题,例如计算阶乘、斐波那契数列等。递归的关键在于找到一个可以将问题分解为更小规模的相同类型问题的解法。
递归的基本思想是将一个大问题分解为若干个相同类型的子问题,然后逐层解决这些子问题。当子问题可以直接求解时,递归终止;否则,继续对子问题进行递归求解。
def factorial(n):
# 基本情况:当n为0或1时,阶乘值为1
if n == 0 or n == 1:
return 1
# 递归情况:计算n的阶乘等于n乘以(n-1)的阶乘
else:
return n * factorial(n-1)
# 测试
print(factorial(5)) # 输出:120
双指针算法是一种高效的解决数组或链表问题的算法。它通过使用两个指针,一个快指针和一个慢指针,来遍历数组或链表,从而找到满足特定条件的元素或节点。
在数组中,我们通常使用快指针来遍历数组,而慢指针则用来标记已经访问过的元素。当快指针到达数组的末尾时,慢指针指向的就是最后一个未被访问的元素。这种方法的时间复杂度为O(n),因为每个元素只会被访问一次。
在链表中,快指针通常用于遍历链表的头部,而慢指针则用于跟随链表的尾部。当快指针到达链表的末尾时,慢指针将指向链表的最后一个节点。这种方法的时间复杂度也为O(n),因为每个节点只会被访问一次。
class ListNode:
def __init__(self, x):
self.val = x
self.next = None
def hasCycle(head: ListNode) -> bool:
slow = head
fast = head
while fast and fast.next:
slow = slow.next
fast = fast.next.next
if slow == fast:
return True
return False
在上面的例子中,我们定义了一个 ListNode 类来表示链表节点,然后定义了一个 hasCycle 函数来判断链表是否有环。在函数中,我们设置了两个指针 slow 和 fast,其中 slow 每次移动一个节点,而 fast 每次移动两个节点。如果链表中存在环,那么这两个指针最终会相遇;否则,它们会在某个时刻相遇之前停止移动。
比如leetcode的第一题两数之和
给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。
你可以按任意顺序返回答案。
示例 1:
输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。
示例 2:
输入:nums = [3,2,4], target = 6
输出:[1,2]
示例 3:
输入:nums = [3,3], target = 6
输出:[0,1]
def twoSum(nums: list[int], target: int) -> list[int]:
left = 0
right = len(nums) - 1
while left < right:
current_sum = nums[left] + nums[right]
if current_sum == target:
return [left, right]
elif current_sum < target:
left += 1
else:
right -= 1
return []
这个题很明显,用双指针是很好的实现思路,你也可以用单循环实现,但是单循环太慢了,时间复杂度更高,当数组的长度很大的时候,单循环很慢.
先看代码
def max_length_of_substring(s):
n = len(s)
if n == 0:
return 0
# 定义双指针left和right,以及一个字典来存储字符出现的位置
left, right = 0, 0
char_dict = {}
max_len = 0
while right < n:
# 如果当前字符已经在字典中出现过,则更新左指针的位置
if s[right] in char_dict and char_dict[s[right]] >= left:
left = char_dict[s[right]] + 1
# 更新当前字符在字典中的位置
char_dict[s[right]] = right
# 更新最大长度
max_len = max(max_len, right - left + 1)
# 右指针向右移动一位
right += 1
return max_len
解决这个问题的思路是,创建一个滑动窗口,使得窗口中的字符都是不重复的。
具体来说,我们定义两个指针left和right,分别指向滑动窗口的左右边界。当右指针向右移动时,如果当前字符已经在窗口中出现过,则需要更新左指针的位置,以便保证窗口中的字符都是不重复的。
如果当前字符已经在字典中出现过,并且其位置大于等于左指针的位置,则说明需要将左指针移动到当前字符上一次出现的位置的下一位。否则,说明当前字符是第一次出现,可以继续扩展窗口。
需要注意的是,在这个题目中,我们需要使用一个字典来存储每个字符最近一次出现的位置。具体来说,字典的键是字符,值是该字符最近一次出现的位置。当右指针向右移动时,我们需要将当前字符加入字典中,并更新其出现的位置。
Python双指针算法是一种非常实用的算法,它可以帮助我们在处理数组和链表问题时提高效率。
如果你有什么问题,欢迎给我留言