【huawei】机试

目录

题目范围

牛客练习输入,输出

逻辑题:牛客的中+难等级的题目

算法题:力扣:简单+中等的题目

题型

题型:三道题是简单+简单+中等难度的题型。第一二题可能会是循环、数组、字符串、栈这些,第三题会难一点,二分查找、动态规划、DFS、BFS这些。

参考资料

leetcode网的典型练习题目编号如下:

字符串:3,49,30

线性表:86,16,27,732

队列:641,406,899

栈:946,116,117,895

哈希表:61,729,25,554

dfs:105,112,98,494,547,1254

bfs:1091,1129,102,101,752

字符串

3.无重复字符串的最长子串

python 复制代码
class Solution(object):
    def lengthOfLongestSubstring(self, s):
        """
        :type s: str
        :rtype: int
        """
        start = 0
        max_length = 0
        char_index_map = {}

        for i, char in enumerate(s):
            if char in char_index_map and char_index_map[char] >= start:
                start = char_index_map[char] + 1
            char_index_map[char] = i
            current_length = i - start + 1
            if current_length > max_length:
                max_length = current_length

        return max_length
    
str = input("Enter a string: ")
solution = Solution()

print("The longest substring without repeating characters is:", solution.lengthOfLongestSubstring(str))

49.字母异位词分组.py

python 复制代码
class Solution(object):
    def groupAnagrams(self, strs):
        """
        :type strs: List[str]
        :rtype: List[List[str]]
        """
        anagram_map = {}
        
        for s in strs:
            sorted_s = ''.join(sorted(s))
            if sorted_s in anagram_map:
                anagram_map[sorted_s].append(s)
            else:
                anagram_map[sorted_s] = [s]
        
        return list(anagram_map.values())
    
strs = input("Enter a list of words separated by spaces: ").split()
solution = Solution()
print("Grouped anagrams:", solution.groupAnagrams(strs))

30.串联所有单词的子串

python 复制代码
from collections import Counter

class Solution(object):
    def findSubstring(self, s, words):
        """
        :type s: str
        :type words: List[str]
        :rtype: List[int]
        """
        res = []
        m, n, ls = len(words), len(words[0]), len(s)
        for i in range(n):
            if i + m * n > ls:
                break
            differ = Counter()
            for j in range(m):
                word = s[i + j * n: i + (j + 1) * n]
                differ[word] += 1
            for word in words:
                differ[word] -= 1
                if differ[word] == 0:
                    del differ[word]
            for start in range(i, ls - m * n + 1, n):
                if start != i:
                    word = s[start + (m - 1) * n: start + m * n]
                    differ[word] += 1
                    if differ[word] == 0:
                        del differ[word]
                    word = s[start - n: start]
                    differ[word] -= 1
                    if differ[word] == 0:
                        del differ[word]
                if len(differ) == 0:
                    res.append(start)
        return res
s = input("Enter a string: ")
words = input("Enter words separated by spaces: ").split()
solution = Solution()
print("Starting indices of substring concatenations are:", solution.findSubstring(s, words))

线性表

86.分隔链表.py

python 复制代码
class ListNode:
    def __init__(self, val=0, next=None):
        self.val = int(val) if val is not None and val != '' else 0
        self.next = next

    @staticmethod
    def from_list(values):
        if not values:
            return None
        head = ListNode(values[0])
        cur = head
        for v in values[1:]:
            cur.next = ListNode(v)
            cur = cur.next
        return head

    def to_list(self):
        out = []
        node = self
        while node:
            out.append(node.val)
            node = node.next
        return out

    def __repr__(self):
        return '->'.join(str(x) for x in self.to_list())


class Solution(object):
    def partition(self, head, x):
        """
        :type head: Optional[ListNode]
        :type x: int
        :rtype: Optional[ListNode]
        """
        small = ListNode(0)
        smallHead = small
        large = ListNode(0)
        largeHead = large
        while head:
            if head.val < x:
                small.next = head
                small = small.next
            else:
                large.next = head
                large = large.next
            head = head.next
        large.next = None
        small.next = largeHead.next
        return smallHead.next
head = ListNode.from_list([1,4,3,2,5,2])
x = 3
solution = Solution()
new_head = solution.partition(head, x)
print("Partitioned linked list:", new_head.to_list())

16.最接近的三数之和

python 复制代码
from typing import List

class Solution:
    def threeSumClosest(self, nums: List[int], target: int) -> int:
        nums.sort()
        closest_sum = float('inf')
        for i in range(len(nums) - 2):
            left, right = i + 1, len(nums) - 1
            while left < right:
                current_sum = nums[i] + nums[left] + nums[right]
                if abs(current_sum - target) < abs(closest_sum - target):
                    closest_sum = current_sum
                if current_sum < target:
                    left += 1
                elif current_sum > target:
                    right -= 1
                else:
                    return current_sum
        return closest_sum
nums = list(map(int, input("Enter numbers separated by spaces: ").split()))
target = int(input("Enter the target sum: "))
solution = Solution()
result = solution.threeSumClosest(nums, target)
print("The sum of the three integers closest to the target is:", result)

27.移除元素

python 复制代码
from typing import List
class Solution:
    def removeElement(self, nums: List[int], val: int) -> int:
        i = 0
        for j in range(len(nums)):
            if nums[j] != val:
                nums[i] = nums[j]
                i += 1
        return i

nums = list(map(int, input("Enter numbers separated by spaces: ").split(",")))
val = int(input("Enter the value to remove: "))
solution = Solution()
new_length = solution.removeElement(nums, val)
print("The new length of the array is:", new_length)
print("The modified array is:", nums[:new_length])

732.我的日程安排

python 复制代码
from sortedcontainers import SortedDict

class MyCalendarThree:
    def __init__(self):
        # 使用SortedDict存储时间点的变化量
        self.diff = SortedDict()
        self.max_k = 0

    def book(self, startTime: int, endTime: int) -> int:
        # 更新起点和终点
        self.diff[startTime] = self.diff.get(startTime, 0) + 1
        self.diff[endTime] = self.diff.get(endTime, 0) - 1
        
        # 计算当前最大重叠次数
        current = 0
        for time in self.diff:
            current += self.diff[time]
            self.max_k = max(self.max_k, current)
        
        return self.max_k
calendar = MyCalendarThree()
print(calendar.book(10, 20))  # 返回 1
print(calendar.book(50, 60))  # 返回 1
print(calendar.book(10, 40))  # 返回 2
print(calendar.book(5, 15))   # 返回 3
print(calendar.book(5, 10))   # 返回 3
print(calendar.book(25, 55))  # 返回 3

队列

641.设计循环双端队列

python 复制代码
class MyCircularDeque:
    def __init__(self, k: int):
        self.capacity = k
        self.queue = [0] * k
        self.front = 0
        self.rear = 0
        self.size = 0

    def insertFront(self, value: int) -> bool:
        if self.isFull():
            return False
        
        self.front = (self.front - 1) % self.capacity
        self.queue[self.front] = value
        self.size += 1
        return True

    def insertLast(self, value: int) -> bool:
        if self.isFull():
            return False
        
        self.queue[self.rear] = value
        self.rear = (self.rear + 1) % self.capacity
        self.size += 1
        return True

    def deleteFront(self) -> bool:
        if self.isEmpty():
            return False
        
        self.front = (self.front + 1) % self.capacity
        self.size -= 1
        return True

    def deleteLast(self) -> bool:
        if self.isEmpty():
            return False
        
        self.rear = (self.rear - 1) % self.capacity
        self.size -= 1
        return True

    def getFront(self) -> int:
        return -1 if self.isEmpty() else self.queue[self.front]

    def getRear(self) -> int:
        return -1 if self.isEmpty() else self.queue[(self.rear - 1) % self.capacity]

    def isEmpty(self) -> bool:
        return self.size == 0

    def isFull(self) -> bool:
        return self.size == self.capacity
    
deque = MyCircularDeque(3)

print(deque.insertLast(1))    # True
print(deque.insertLast(2))    # True
print(deque.insertFront(3))   # True
print(deque.insertFront(4))   # False (已满)
print(deque.getRear())        # 2
print(deque.isFull())         # True
print(deque.deleteLast())     # True
print(deque.insertFront(4))   # True
print(deque.getFront())       # 4

406.根据身高重建队列

python 复制代码
from typing import List

class Solution:
    def reconstructQueue(self, people: List[List[int]]) -> List[List[int]]:
        # 排序:身高降序,k值升序
        people.sort(key=lambda x: (-x[0], x[1]))
        
        result = []
        for p in people:
            # 使用bisect找到插入位置
            # 这里可以直接使用insert,因为已经排序了
            result.insert(p[1], p)
        
        return result
    
solution = Solution()
    
people1 = [[7,0],[4,4],[7,1],[5,0],[6,1],[5,2]]
result1 = solution.reconstructQueue(people1)
print("测试用例1:")
print("输入:", people1)
print("输出:", result1)
print("预期:", [[5,0],[7,0],[5,2],[6,1],[4,4],[7,1]])
print("正确?", result1 == [[5,0],[7,0],[5,2],[6,1],[4,4],[7,1]])
print()

899.有序队列

python 复制代码
class Solution:
    def orderlyQueue(self, s: str, k: int) -> str:
        if k == 1:
            # 生成所有可能的旋转,取最小值
            return min(s[i:] + s[:i] for i in range(len(s)))
        else:
            # 当k>1时,可以完全重新排列
            return ''.join(sorted(s))
        
solution = Solution()
    
s1, k1 = "cba", 1
result1 = solution.orderlyQueue(s1, k1)
print(f"测试1: s='{s1}', k={k1}")
print(f"结果: '{result1}'")
print(f"预期: 'acb'")
print(f"正确: {result1 == 'acb'}")
print()

946.验证栈序列

python 复制代码
from typing import List

class Solution:
    def validateStackSequences(self, pushed: List[int], popped: List[int]) -> bool:
        """
        使用栈模拟push和pop操作
        思路:
        1. 遍历pushed数组,将元素依次压入栈
        2. 每次压入后,检查栈顶元素是否等于popped的当前元素
        3. 如果相等则弹出,直到栈为空或栈顶元素不等于popped当前元素
        4. 最后检查栈是否为空
        """
        stack = []
        pop_index = 0
        
        for num in pushed:
            # 压入当前元素
            stack.append(num)
            
            # 循环检查并弹出匹配的元素
            while stack and stack[-1] == popped[pop_index]:
                stack.pop()
                pop_index += 1
        
        # 如果栈为空,说明所有元素都正确弹出了
        return len(stack) == 0
    
solution = Solution()
    
pushed1 = [1, 2, 3, 4, 5]
popped1 = [4, 5, 3, 2, 1]
result1 = solution.validateStackSequences(pushed1, popped1)
print(f"测试1: pushed={pushed1}, popped={popped1}")
print(f"结果: {result1}")
print(f"预期: True")
print(f"正确: {result1 == True}")

895.最大频率栈

python 复制代码
from collections import defaultdict

class FreqStack:
    def __init__(self):
        """
        初始化最大频率栈
        需要维护三个数据结构:
        1. freq: 记录每个值的频率
        2. group: 记录每个频率对应的值列表(栈)
        3. max_freq: 当前最大频率
        """
        self.freq = defaultdict(int)  # 值 -> 频率
        self.group = defaultdict(list)  # 频率 -> 值列表(栈)
        self.max_freq = 0  # 当前最大频率

    def push(self, val: int) -> None:
        """
        将值推入栈中
        """
        # 更新频率
        self.freq[val] += 1
        f = self.freq[val]
        
        # 将值加入到对应频率的组中
        self.group[f].append(val)
        
        # 更新最大频率
        if f > self.max_freq:
            self.max_freq = f

    def pop(self) -> int:
        """
        弹出并返回出现频率最高的元素
        如果有多个频率相同的元素,返回最接近栈顶的
        """
        # 从最大频率对应的组中弹出元素
        val = self.group[self.max_freq].pop()
        
        # 更新该值的频率
        self.freq[val] -= 1
        
        # 如果最大频率对应的组为空,则减小最大频率
        if not self.group[self.max_freq]:
            self.max_freq -= 1
        
        return val
    
freq_stack = FreqStack()
    
print("测试示例1:")
operations = ["push", "push", "push", "push", "push", "push", "pop", "pop", "pop", "pop"]
values = [5, 7, 5, 7, 4, 5, None, None, None, None]

results = []
for op, val in zip(operations, values):
    if op == "push":
        freq_stack.push(val)
        results.append(None)
    elif op == "pop":
        results.append(freq_stack.pop())

print("操作序列:", operations)
print("值序列:", values)
print("结果:", results)
print("预期:", [None, None, None, None, None, None, 5, 7, 5, 4])
print("正确?", results == [None, None, None, None, None, None, 5, 7, 5, 4])

116.填充每个节点的下一个右侧节点指针

python 复制代码
from typing import Optional

# Node类的定义
class Node:
    def __init__(self, val: int = 0, left: 'Node' = None, right: 'Node' = None, next: 'Node' = None):
        self.val = val
        self.left = left
        self.right = right
        self.next = next


class Solution:
    def connect(self, root: 'Optional[Node]') -> 'Optional[Node]':
        """
        使用已建立的next指针进行层序遍历
        时间复杂度:O(n)
        空间复杂度:O(1)(不考虑递归栈空间)
        """
        if not root:
            return root
            
        # 从根节点开始
        leftmost = root
        
        # 当还有下一层时继续
        while leftmost.left:
            # 遍历当前层的节点,通过next指针横向移动
            head = leftmost
            while head:
                # 连接1:连接同一个父节点的左右子节点
                head.left.next = head.right
                
                # 连接2:连接不同父节点的相邻子节点
                if head.next:
                    head.right.next = head.next.left
                
                # 移动到当前层的下一个节点
                head = head.next
            
            # 移动到下一层的最左边节点
            leftmost = leftmost.left
        
        return root

def print_tree_next(root):
    """打印每层的next指针"""
    if not root:
        return
    
    leftmost = root
    while leftmost:
        current = leftmost
        level_nodes = []
        while current:
            next_val = current.next.val if current.next else "NULL"
            level_nodes.append(f"{current.val}->{next_val}")
            current = current.next
        print(" | ".join(level_nodes))
        leftmost = leftmost.left

# 构建一个完美二叉树
def build_perfect_tree(nodes):
    """构建完美二叉树用于测试"""
    if not nodes:
        return None
    
    from collections import deque
    
    root = Node(nodes[0])
    queue = deque([root])
    i = 1
    
    while queue and i < len(nodes):
        node = queue.popleft()
        
        if i < len(nodes):
            node.left = Node(nodes[i])
            queue.append(node.left)
            i += 1
        
        if i < len(nodes):
            node.right = Node(nodes[i])
            queue.append(node.right)
            i += 1
    
    return root


solution = Solution()
    
# 测试用例1
print("测试用例1:")
nodes1 = [1, 2, 3, 4, 5, 6, 7]
root1 = build_perfect_tree(nodes1)
root1 = solution.connect(root1)
print_tree_next(root1)
print()

117.填充每个节点的下一个右侧节点指针

python 复制代码
class Node:
    def __init__(self, val: int = 0, left: 'Node' = None, right: 'Node' = None, next: 'Node' = None):
        self.val = val
        self.left = left
        self.right = right
        self.next = next

class Solution:
    def connect(self, root: 'Node') -> 'Node':
        """
        更简洁的迭代解法
        """
        if not root:
            return root
            
        # 当前层头节点
        head = root
        
        while head:
            # 为下一层创建虚拟头节点
            dummy = Node(0)
            tail = dummy
            
            # 遍历当前层
            current = head
            while current:
                # 处理左子节点
                if current.left:
                    tail.next = current.left
                    tail = tail.next
                
                # 处理右子节点
                if current.right:
                    tail.next = current.right
                    tail = tail.next
                
                # 移动到当前层的下一个节点
                current = current.next
            
            # 移动到下一层
            head = dummy.next
        
        return root
    
def print_tree_next(root):
    """打印每层的next指针"""
    if not root:
        return
    
    leftmost = root
    while leftmost:
        current = leftmost
        level_nodes = []
        while current:
            next_val = current.next.val if current.next else "NULL"
            level_nodes.append(f"{current.val}->{next_val}")
            current = current.next
        print(" | ".join(level_nodes))
        leftmost = leftmost.left

# 构建测试树
root = Node(1)
root.left = Node(2)
root.right = Node(3)
root.left.left = Node(4)
root.left.right = Node(5)
root.right.right = Node(7)
solution = Solution()
root = solution.connect(root)
print("测试用例:")
print_tree_next(root)

哈希表

61.旋转链表

python 复制代码
from typing import Optional

class ListNode:
    def __init__(self, val=0, next=None):
        self.val = val
        self.next = next

class Solution:
    def rotateRight(self, head: Optional[ListNode], k: int) -> Optional[ListNode]:
        """
        旋转链表:将链表每个节点向右移动k个位置
        
        思路:
        1. 如果链表为空或只有一个节点,或者k=0,直接返回
        2. 计算链表长度,并找到尾节点
        3. 将链表连接成环
        4. 计算实际需要移动的步数:k % n
        5. 找到新的尾节点(从head开始移动n - k%n - 1步)
        6. 断开环,返回新的头节点
        
        时间复杂度:O(n)
        空间复杂度:O(1)
        """
        # 边界情况处理
        if not head or not head.next or k == 0:
            return head
        
        # 1. 计算链表长度,并找到尾节点
        n = 1  # 链表长度
        tail = head
        while tail.next:
            tail = tail.next
            n += 1
        
        # 2. 计算实际需要移动的步数(避免重复旋转)
        k = k % n
        if k == 0:  # 如果移动0步或移动整圈,直接返回
            return head
        
        # 3. 将链表连接成环
        tail.next = head
        
        # 4. 找到新的尾节点(第n-k个节点)
        new_tail = head
        for _ in range(n - k - 1):
            new_tail = new_tail.next
        
        # 5. 新的头节点是新的尾节点的下一个节点
        new_head = new_tail.next
        
        # 6. 断开环
        new_tail.next = None
        
        return new_head

solution = Solution()
head = ListNode(1, ListNode(2, ListNode(3, ListNode(4, ListNode(5)))))
k = 2
new_head = solution.rotateRight(head, k)
# 输出旋转后的链表  
result = []
while new_head:
    result.append(new_head.val)
    new_head = new_head.next
print("Rotated linked list:", result)  # 预期输出: [4, 5, 1, 2, 3]

25.K个一组翻转链表

python 复制代码
from typing import Optional


class ListNode:
    def __init__(self, val=0, next=None):
        self.val = val
        self.next = next

class Solution:
    def reverseKGroup(self, head: Optional[ListNode], k: int) -> Optional[ListNode]:
        """
        更简洁的迭代实现
        """
        # 创建虚拟头节点
        dummy = ListNode(0)
        dummy.next = head
        prev = dummy
        
        while True:
            # 检查剩余节点是否足够k个
            check = prev
            for _ in range(k):
                if not check.next:
                    return dummy.next
                check = check.next
            
            # 翻转当前k个节点
            # prev -> 1 -> 2 -> 3 -> next
            # 翻转后:prev -> 3 -> 2 -> 1 -> next
            
            # 记录当前组的第一个节点(翻转后将成为尾节点)
            group_start = prev.next
            # 记录当前组翻转后的尾节点
            last = None
            
            # 翻转k个节点
            current = prev.next
            for _ in range(k):
                next_node = current.next
                current.next = last
                last = current
                current = next_node
            
            # 连接翻转后的组
            prev.next = last  # prev指向翻转后的头节点
            group_start.next = current  # 原组的第一个节点(现在是尾节点)指向下一组的头节点
            
            # 更新prev为当前组的尾节点
            prev = group_start

solution = Solution()
head = ListNode(1, ListNode(2, ListNode(3, ListNode(4, ListNode(5)))))
k = 2
new_head = solution.reverseKGroup(head, k)
# 输出翻转后的链表  
result = []
while new_head:
    result.append(new_head.val)
    new_head = new_head.next
print("Reversed linked list in k-groups:", result)

554.砖墙


python 复制代码
from typing import List
from collections import defaultdict

class Solution:
    def leastBricks(self, wall: List[List[int]]) -> int:
        """
        砖墙问题:找到穿过最少砖块的垂直线
        
        思路:
        1. 统计每个垂直缝隙的位置(前缀和)
        2. 找到出现次数最多的缝隙位置
        3. 最少的穿过砖块数 = 总行数 - 最多缝隙数量
        
        时间复杂度:O(n×m),其中n是行数,m是每行的砖块数
        空间复杂度:O(k),k是不同缝隙位置的数量
        """
        if not wall:
            return 0
        
        # 使用字典统计每个缝隙位置出现的次数
        gap_count = defaultdict(int)
        
        # 遍历每一行砖块
        for row in wall:
            # 计算前缀和(缝隙位置)
            prefix_sum = 0
            # 注意:最后一个缝隙是墙的右边缘,不算有效缝隙
            for brick in row[:-1]:  # 不包括最后一块砖的右边缘
                prefix_sum += brick
                gap_count[prefix_sum] += 1
        
        # 如果没有找到任何缝隙(比如每行只有一块砖)
        if not gap_count:
            return len(wall)
        
        # 找到出现次数最多的缝隙
        max_gaps = max(gap_count.values())
        
        # 最少穿过砖块数 = 总行数 - 最多缝隙数
        return len(wall) - max_gaps
    
solution = Solution()
    
# 测试用例1:题目示例
print("测试用例1:")
wall1 = [[1,2,2,1],[3,1,2],[1,3,2],[2,4],[3,1,2],[1,3,1]]
result1 = solution.leastBricks(wall1)
print(f"输入: wall = {wall1}")
print(f"输出: {result1}")
print(f"预期: 2")
print(f"正确: {result1 == 2}")

729.我的日程安排表

python 复制代码
import bisect

class MyCalendar:
    def __init__(self):
        """
        使用两个列表分别存储开始时间和结束时间,并保持有序
        """
        self.starts = []  # 开始时间列表(有序)
        self.ends = []    # 结束时间列表(对应有序)

    def book(self, startTime: int, endTime: int) -> bool:
        """
        使用二分查找找到插入位置,检查前后是否有重叠
        """
        # 使用bisect找到startTime应该插入的位置
        pos = bisect.bisect_right(self.starts, startTime)
        
        # 检查与前一个区间是否重叠(如果pos > 0)
        # 当前一个区间的结束时间 > startTime,则重叠
        if pos > 0 and self.ends[pos-1] > startTime:
            return False
        
        # 检查与后一个区间是否重叠(如果pos < len(self.starts))
        # 如果endTime > 后一个区间的开始时间,则重叠
        if pos < len(self.starts) and endTime > self.starts[pos]:
            return False
        
        # 没有重叠,插入新区间
        self.starts.insert(pos, startTime)
        self.ends.insert(pos, endTime)
        return True
    
print("测试用例1:")
calendar = MyCalendar()
print(calendar.book(10, 20))  # True
print(calendar.book(15, 25))  # False,与[10,20)重叠
print(calendar.book(20, 30))  # True,刚好相邻不重叠

DFS

105.从前序与中序遍历序列构造二叉树

python 复制代码
from typing import List, Optional

class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right
class Solution:
    def buildTree(self, preorder: List[int], inorder: List[int]) -> Optional[TreeNode]:
        """
        更简洁的递归实现
        """
        if not preorder or not inorder:
            return None
        
        # 前序遍历的第一个元素是根节点
        root_val = preorder[0]
        root = TreeNode(root_val)
        
        # 在中序遍历中找到根节点的位置
        root_index = inorder.index(root_val)
        
        # 递归构建左右子树
        # 左子树的前序遍历:preorder[1:root_index+1]
        # 左子树的中序遍历:inorder[:root_index]
        root.left = self.buildTree(preorder[1:root_index+1], inorder[:root_index])
        
        # 右子树的前序遍历:preorder[root_index+1:]
        # 右子树的中序遍历:inorder[root_index+1:]
        root.right = self.buildTree(preorder[root_index+1:], inorder[root_index+1:])
        
        return root
    
solution = Solution()
preorder = [3,9,20,15,7]
inorder = [9,3,15,20,7]
root = solution.buildTree(preorder, inorder)
print("Root of the constructed tree:", root.val)  # 输出根节点的值

112.路径总和

python 复制代码
from typing import Optional

class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right


class Solution:
    def hasPathSum(self, root: Optional[TreeNode], targetSum: int) -> bool:
        """
        非常简洁的递归实现(一行代码)
        """
        if not root:
            return False
        if not root.left and not root.right:
            return targetSum == root.val
        return self.hasPathSum(root.left, targetSum - root.val) or self.hasPathSum(root.right, targetSum - root.val)
    
# 示例用法
solution = Solution()
root = TreeNode(5)
root.left = TreeNode(4)
root.right = TreeNode(8)
root.left.left = TreeNode(11)
root.left.left.left = TreeNode(7)
root.left.left.right = TreeNode(2)
root.right.left = TreeNode(13)
root.right.right = TreeNode(4)
targetSum = 22
print("Has path sum:", solution.hasPathSum(root, targetSum))  # 输出: Has path sum: True

98.验证二叉搜索树

python 复制代码
from typing import Optional

# Definition for a binary tree node.
class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right

class Solution:
    def isValidBST(self, root: Optional[TreeNode]) -> bool:
        """
        验证二叉搜索树
        
        方法一:递归传递范围
        每个节点都有一个允许的值范围(min_val, max_val)
        左子树的值必须在 (min_val, root.val) 范围内
        右子树的值必须在 (root.val, max_val) 范围内
        
        时间复杂度:O(n),每个节点访问一次
        空间复杂度:O(h),递归栈空间,h为树的高度
        """
        
        def validate(node: Optional[TreeNode], min_val: float, max_val: float) -> bool:
            """
            递归验证节点是否在有效范围内
            
            参数:
            node: 当前节点
            min_val: 允许的最小值(不包含)
            max_val: 允许的最大值(不包含)
            """
            # 空节点是有效的BST
            if not node:
                return True
            
            # 检查当前节点值是否在允许范围内
            if node.val <= min_val or node.val >= max_val:
                return False
            
            # 递归验证左子树和右子树
            # 左子树的最大值不能超过当前节点值
            # 右子树的最小值不能小于当前节点值
            return (validate(node.left, min_val, node.val) and 
                    validate(node.right, node.val, max_val))
        
        # 初始调用,根节点的值可以是任意值,所以使用正负无穷大作为范围边界
        return validate(root, float('-inf'), float('inf'))
    
# 示例用法
solution = Solution()
# 构建一个示例二叉树
#       2   
#      / \
#     1   3 
root = TreeNode(2)
root.left = TreeNode(1) 
root.right = TreeNode(3)
print("Is valid BST:", solution.isValidBST(root))  # 输出: Is valid BST: True

494.目标和

python 复制代码
from typing import List

class Solution:
    def findTargetSumWays(self, nums: List[int], target: int) -> int:
        """
        将问题转化为子集和问题
        设添加'+'的数字和为p,添加'-'的数字和为q
        则 p + q = sum, p - q = target
        解得 p = (sum + target) // 2
        问题转化为:从nums中选择若干数,使其和为p的组合数
        """
        total_sum = sum(nums)
        
        # 如果target的绝对值大于总和,不可能实现
        if abs(target) > total_sum:
            return 0
        
        # 如果(sum + target)为奇数,不可能实现
        if (total_sum + target) % 2 == 1:
            return 0
        
        # 计算目标和
        target_sum = (total_sum + target) // 2
        # 确保target_sum非负
        if target_sum < 0:
            return 0
        
        # 动态规划:dp[i]表示和为i的组合数
        dp = [0] * (target_sum + 1)
        dp[0] = 1  # 和为0只有一种方式:不选任何数
        
        for num in nums:
            # 从后往前遍历,避免重复使用同一个数字
            for i in range(target_sum, num - 1, -1):
                dp[i] += dp[i - num]
        
        return dp[target_sum]
    
# 示例用法
solution = Solution()
nums = [1, 1, 1, 1, 1]
target = 3
print("Number of ways:", solution.findTargetSumWays(nums, target))  # 输出: Number of ways: 5

547.省份数量

python 复制代码
from typing import List

class Solution:
    def findCircleNum(self, isConnected: List[List[int]]) -> int:
        """
        使用DFS求解省份数量
        
        思路:
        1. 创建一个访问标记数组
        2. 对每个未访问的城市,进行DFS遍历所有相连的城市
        3. 每次DFS开始计数一个省份
        
        时间复杂度:O(n²)
        空间复杂度:O(n)
        """
        n = len(isConnected)
        visited = [False] * n
        provinces = 0
        
        def dfs(city: int):
            """深度优先搜索,标记所有相连的城市"""
            visited[city] = True
            # 遍历所有其他城市
            for neighbor in range(n):
                # 如果两个城市相连且邻居城市未被访问
                if isConnected[city][neighbor] == 1 and not visited[neighbor]:
                    dfs(neighbor)
        
        # 遍历所有城市
        for city in range(n):
            if not visited[city]:
                # 开始一个新的省份
                provinces += 1
                dfs(city)
        
        return provinces
    
# 示例用法
solution = Solution()
isConnected = [
    [1, 1, 0],
    [1, 1, 0],
    [0, 0, 1]
]
print("Number of provinces:", solution.findCircleNum(isConnected))  # 输出: Number of provinces: 2

1254.统计封闭岛屿的数目

python 复制代码
from typing import List

class Solution:
    def closedIsland(self, grid: List[List[int]]) -> int:
        """
        统计封闭岛屿的数量
        
        思路:
        1. 先处理边界上的岛屿(将它们标记为已访问,因为它们不是封闭的)
        2. 然后遍历内部,统计剩余的岛屿数量
        
        时间复杂度:O(m×n),其中m和n是网格的行数和列数
        空间复杂度:O(m×n),最坏情况下递归栈空间
        """
        if not grid or not grid[0]:
            return 0
        
        m, n = len(grid), len(grid[0])
        
        def dfs(i: int, j: int):
            """深度优先搜索,将相连的陆地标记为已访问"""
            # 边界检查
            if i < 0 or i >= m or j < 0 or j >= n:
                return
            
            # 如果是水域或已访问,返回
            if grid[i][j] == 1:
                return
            
            # 标记为已访问(修改为1,表示水域)
            grid[i][j] = 1
            
            # 向四个方向搜索
            dfs(i - 1, j)  # 上
            dfs(i + 1, j)  # 下
            dfs(i, j - 1)  # 左
            dfs(i, j + 1)  # 右
        
        # 步骤1:处理边界上的岛屿(将它们标记为水域)
        # 因为边界上的岛屿不可能被完全包围
        
        # 处理第一行和最后一行
        for j in range(n):
            if grid[0][j] == 0:  # 第一行
                dfs(0, j)
            if grid[m - 1][j] == 0:  # 最后一行
                dfs(m - 1, j)
        
        # 处理第一列和最后一列
        for i in range(m):
            if grid[i][0] == 0:  # 第一列
                dfs(i, 0)
            if grid[i][n - 1] == 0:  # 最后一列
                dfs(i, n - 1)
        
        # 步骤2:统计内部封闭岛屿的数量
        count = 0
        for i in range(1, m - 1):
            for j in range(1, n - 1):
                if grid[i][j] == 0:
                    count += 1
                    dfs(i, j)
        
        return count
    
# 示例用法
solution = Solution()
grid = [
    [1,1,1,1,1,1,1,0],
    [1,0,0,0,0,1,1,0],
    [1,0,1,0,1,1,1,0],
    [1,0,0,0,0,1,0,1],
    [1,1,1,1,1,1,1,0]
]
print("Number of closed islands:", solution.closedIsland(grid))  # 输出: Number of closed islands: 2

BFS

1091.二进制矩阵中的最短路径

python 复制代码
from typing import List
from collections import deque

class Solution:
    def shortestPathBinaryMatrix(self, grid: List[List[int]]) -> int:
        """
        在二进制矩阵中寻找最短畅通路径
        
        思路:
        1. 使用BFS寻找最短路径
        2. 可以从8个方向移动
        3. 路径必须全部由0组成
        
        时间复杂度:O(n²),其中n是矩阵边长
        空间复杂度:O(n²),用于存储队列和访问标记
        """
        n = len(grid)
        
        # 如果起点或终点是1,直接返回-1
        if grid[0][0] == 1 or grid[n-1][n-1] == 1:
            return -1
        
        # 如果只有一个单元格且为0
        if n == 1:
            return 1
        
        # 8个方向:上、下、左、右、左上、右上、左下、右下
        directions = [
            (-1, -1), (-1, 0), (-1, 1),  # 左上、上、右上
            (0, -1),           (0, 1),   # 左、右
            (1, -1),  (1, 0),  (1, 1)    # 左下、下、右下
        ]
        
        # 使用队列进行BFS,存储(x, y, distance)
        queue = deque()
        queue.append((0, 0, 1))  # 起点,距离为1
        
        # 标记已访问的单元格,避免重复访问
        visited = [[False] * n for _ in range(n)]
        visited[0][0] = True
        
        while queue:
            x, y, dist = queue.popleft()
            
            # 尝试8个方向
            for dx, dy in directions:
                new_x, new_y = x + dx, y + dy
                
                # 检查是否在边界内
                if 0 <= new_x < n and 0 <= new_y < n:
                    # 如果是终点
                    if new_x == n-1 and new_y == n-1 and grid[new_x][new_y] == 0:
                        return dist + 1
                    
                    # 如果是可访问的单元格且未访问过
                    if grid[new_x][new_y] == 0 and not visited[new_x][new_y]:
                        visited[new_x][new_y] = True
                        queue.append((new_x, new_y, dist + 1))
        
        # 如果队列为空仍未到达终点,返回-1
        return -1
    
# 示例用法
solution = Solution()
grid = [
    [0, 1],
    [1, 0]
]
print("Shortest path length:", solution.shortestPathBinaryMatrix(grid))  # 输出: Shortest path length: 2

1129.颜色交替的最短路径

python 复制代码
from typing import List
from collections import deque

class Solution:
    def shortestAlternatingPaths(self, n: int, redEdges: List[List[int]], blueEdges: List[List[int]]) -> List[int]:
        # 构建邻接表
        red_adj = [[] for _ in range(n)]
        blue_adj = [[] for _ in range(n)]
        
        for u, v in redEdges:
            red_adj[u].append(v)
        for u, v in blueEdges:
            blue_adj[u].append(v)
        
        # visited[i][0] 表示是否通过红色边到达过节点 i
        # visited[i][1] 表示是否通过蓝色边到达过节点 i
        visited = [[False, False] for _ in range(n)]
        # 初始化答案数组,-1 表示不可达
        answer = [-1] * n
        answer[0] = 0  # 节点 0 到自身的距离为 0
        
        # BFS 队列,元素为 (节点, 最后一条边的颜色, 步数)
        # 颜色表示:0 表示红色,1 表示蓝色
        queue = deque()
        # 起点可以以两种颜色状态开始(表示第一条边可以是红色或蓝色)
        queue.append((0, 0, 0))  # (节点, 颜色, 步数)
        queue.append((0, 1, 0))
        visited[0][0] = visited[0][1] = True
        
        while queue:
            node, color, steps = queue.popleft()
            # 下一个需要交替的颜色
            next_color = 1 - color
            # 根据颜色选择邻接表
            adj = red_adj if next_color == 0 else blue_adj
            for neighbor in adj[node]:
                if not visited[neighbor][next_color]:
                    visited[neighbor][next_color] = True
                    if answer[neighbor] == -1:
                        answer[neighbor] = steps + 1
                    queue.append((neighbor, next_color, steps + 1))
        
        return answer
    
# 示例用法
solution = Solution()
n = 3
redEdges = [[0,1],[1,2]]
blueEdges = []
print("Shortest alternating paths:", solution.shortestAlternatingPaths(n, redEdges, blueEdges))  # 输出: Shortest alternating paths: [0, 1, -1]

102.二叉树的层序遍历

python 复制代码
from typing import List, Optional
from collections import deque

# Definition for a binary tree node.
class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right

class Solution:
    def levelOrder(self, root: Optional[TreeNode]) -> List[List[int]]:
        """
        二叉树的层序遍历
        
        使用队列进行广度优先搜索(BFS)
        时间复杂度:O(n),每个节点访问一次
        空间复杂度:O(n),队列中最多存储一层节点
        """
        if not root:
            return []
        
        result = []
        queue = deque([root])  # 使用队列存储节点
        
        while queue:
            level_size = len(queue)  # 当前层的节点数
            level_values = []  # 存储当前层的节点值
            
            # 遍历当前层的所有节点
            for _ in range(level_size):
                node = queue.popleft()
                level_values.append(node.val)
                
                # 将子节点加入队列(先左后右)
                if node.left:
                    queue.append(node.left)
                if node.right:
                    queue.append(node.right)
            
            result.append(level_values)
        
        return result
    
# 示例用法
solution = Solution()
# 构建一个示例二叉树
#       3
#      / \
#     9  20
root = TreeNode(3)
root.left = TreeNode(9)
root.right = TreeNode(20)
root.right.left = TreeNode(15)
root.right.right = TreeNode(7)
print("Level order traversal:", solution.levelOrder(root))  # 输出: Level order traversal:

101.对称二叉树

python 复制代码
from typing import Optional

# Definition for a binary tree node.
class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right

class Solution:
    def isSymmetric(self, root: Optional[TreeNode]) -> bool:
        """
        检查二叉树是否轴对称
        
        递归方法:
        1. 如果根节点为空,返回True
        2. 定义一个辅助函数检查两个树是否镜像对称
        3. 检查左右子树是否镜像
        
        时间复杂度:O(n),每个节点访问一次
        空间复杂度:O(h),递归栈深度,h为树的高度
        """
        if not root:
            return True
        
        def is_mirror(left: Optional[TreeNode], right: Optional[TreeNode]) -> bool:
            # 两个都为空,对称
            if not left and not right:
                return True
            # 一个为空一个不为空,不对称
            if not left or not right:
                return False
            # 值不相等,不对称
            if left.val != right.val:
                return False
            # 递归检查:左子树的左节点和右子树的右节点,左子树的右节点和右子树的左节点
            return (is_mirror(left.left, right.right) and 
                    is_mirror(left.right, right.left))
        
        return is_mirror(root.left, root.right)
    
# 示例用法
solution = Solution()
# 构建一个示例二叉树
#       1
#      / \
#     2   2
root = TreeNode(1)
root.left = TreeNode(2)
root.right = TreeNode(2)
print("Is symmetric:", solution.isSymmetric(root))  # 输出: Is symmetric: True

752.打开转盘锁

python 复制代码
from typing import List
from collections import deque

class Solution:
    def openLock(self, deadends: List[str], target: str) -> int:
        """
        打开转盘锁的最少旋转次数
        
        思路:使用BFS搜索从"0000"到target的最短路径
        每个状态有8个邻居(4个拨轮,每个可以向上或向下转一次)
        死亡数字deadends相当于障碍,不能访问
        
        时间复杂度:O(10000) = O(1),因为状态空间是有限的
        空间复杂度:O(10000)
        """
        # 特殊情况处理
        if target == "0000":
            return 0
        
        # 将deadends转换为集合,方便快速查找
        deadends_set = set(deadends)
        if "0000" in deadends_set:
            return -1
        
        # BFS队列,存储(当前密码, 步数)
        queue = deque()
        queue.append(("0000", 0))
        
        # 记录已访问的状态
        visited = set()
        visited.add("0000")
        
        # BFS搜索
        while queue:
            current, steps = queue.popleft()
            
            # 生成所有可能的下一步状态
            for i in range(4):  # 4个拨轮
                # 向上转
                next_up = self.rotate_up(current, i)
                if next_up == target:
                    return steps + 1
                if next_up not in visited and next_up not in deadends_set:
                    visited.add(next_up)
                    queue.append((next_up, steps + 1))
                
                # 向下转
                next_down = self.rotate_down(current, i)
                if next_down == target:
                    return steps + 1
                if next_down not in visited and next_down not in deadends_set:
                    visited.add(next_down)
                    queue.append((next_down, steps + 1))
        
        # 无法解锁
        return -1
    
    def rotate_up(self, s: str, i: int) -> str:
        """
        将第i位数字向上旋转(加1),0->1, 1->2, ..., 9->0
        """
        num = int(s[i])
        num = (num + 1) % 10
        return s[:i] + str(num) + s[i+1:]
    
    def rotate_down(self, s: str, i: int) -> str:
        """
        将第i位数字向下旋转(减1),0->9, 1->0, ..., 9->8
        """
        num = int(s[i])
        num = (num - 1) % 10
        return s[:i] + str(num) + s[i+1:]
    
# 示例用法
solution = Solution()
deadends = ["0201","0101","0102","1212","2002"]
target = "0202"
print("Minimum moves to unlock:", solution.openLock(deadends, target))  # 输出: Minimum moves to unlock: 6
相关推荐
前端不太难2 小时前
HarmonyOS 项目中如何拆分共用层与形态模型
华为·状态模式·harmonyos
要做一个小太阳2 小时前
华为Atlas 900 A3 SuperPoD 超节点网络架构
运维·服务器·网络·华为·架构
Facechat2 小时前
鸿蒙开发入坑篇(九):本地数据库 (RDB) 深度解析
数据库·华为·harmonyos
编程彩机2 小时前
互联网大厂Java面试:从分布式事务到微服务优化的技术场景解读
java·spring boot·redis·微服务·面试·kafka·分布式事务
编程彩机2 小时前
互联网大厂Java面试:从Spring WebFlux到分布式事务的技术场景解析
java·微服务·面试·分布式事务·spring webflux
阿钱真强道2 小时前
08 鸿蒙对接-jetlinks-official-protocol-不使用md5-不加时间戳
华为·harmonyos
听麟2 小时前
HarmonyOS 6.0+ PC端多设备文件拖拽协同开发实战:手眼同行增强与分布式软总线深度应用
分布式·华为·harmonyos
kogorou0105-bit2 小时前
前端设计模式:发布订阅与依赖倒置的解耦之道
前端·设计模式·面试·状态模式
BlackWolfSky3 小时前
鸿蒙中级课程笔记11—元服务开发
笔记·华为·harmonyos