网站Logo 夕拾朝花

华为社招30天极速训练营

miubai
14
2025-10-02

每天保证至少两小时

day1--9.12

55. 跳跃游戏

  1. 解析:https://www.programmercarl.com/0055.%E8%B7%B3%E8%B7%83%E6%B8%B8%E6%88%8F.html#%E5%85%B6%E4%BB%96%E8%AF%AD%E8%A8%80%E7%89%88%E6%9C%AC

  2. 题解

     class Solution:
         def canJump(self, nums: List[int]) -> bool:
             cover = 0
             i = 0
             if len(nums) <= 1:
                 return True
             while i <= cover:
                 # 局部最优:局部最大覆盖范围
                 cover = max(cover, i + nums[i])
                 if cover >= len(nums) - 1:
                     return True
                 i += 1
             return False
     ​
  3. 总结:

    • 题目理解,样例解析部分没有认真思考,导致对题目理解存在偏差。

    • 程序每一步只能处理一件事,不要试图在第一步的时候,思考第二步。

    • 要图形结合,要先思考明确,然后再动手编写代码,不要直接就上手。

    • 代码语法等是最次的,重要的是编程的思维,抽象的、处理问题的思维模式,编写代码前,一定要先理清思路,如果思路没有理清,那就不要动手。

    • 贪心的核心:由局部最优->全局最优

    • 贪心无套路,对于贪心,多维度的分解问题,抽象各个子问题。

45. 跳跃游戏 II

  1. 解析:https://programmercarl.com/0045.%E8%B7%B3%E8%B7%83%E6%B8%B8%E6%88%8FII.html

  2. 题解

     class Solution:
         def jump(self, nums: List[int]) -> int:
             # 局部最优:curCover、nextCover向前推进,在当前curCover下,得到最大的nextCover
             curCover = 0 #第一跳的位置
             nextCover = 0 # 下一跳的覆盖范围
             res = 0
             i = 0
             if len(nums) <= 1:
                 return 0
             while i < len(nums) - 1:
                 nextCover = max(nextCover, nums[i] + i) # 最大覆盖范围
                 if i == curCover:
                     res += 1
                     curCover = nextCover
                 i += 1
             return res
  3. 总结

    • 局部最优的处理,最大覆盖范围、跳跃次数增加的位置,为本题难点。

    • 局部最优:两次跳跃,取两次跳跃的最远覆盖范围,决定跳跃位置。curCover、nextCover向前推进,在当前curCover下,得到最大的nextCover。在这两个指针的不断向前推进中,确保当前一步、下一步这两次跳跃的距离之和最远。

    • 跳跃位置:当前curCover覆盖的范围内,只需要跳跃一次。无论第二次起跳的起点在哪里,反正这个起点始终在我curCover的覆盖范围内,只要在这个范围内,我跳跃一次就行。注意,题目未要求标明每次跳跃的起点,因此这里对这种细节可以进行模糊,增加代码编写难度。

    • 程序流程:遍历curCover,在curCover内找到最大的nextCover。遍历完成curCover后,将nextCover赋值给curCover,即完成最优的一次跳跃,并增加跳跃次数。继续在curCover中寻找最优的nextCover,以此循环往复。

    • 特殊值处理:其一,要注意数据为空等情况;其二,要注意最后一次跳跃的处理。即若最后一次跳跃的curCover能够到达数组最后一位,则当i == curCover为ture,或者说i = curCover = len(nums)-1时,此时跳跃次数的增加是没有意义的。因为起跳动作在跳跃的起点位置,起跳res计数加一。最后一次跳跃时,在起点位置,跳数加一,跳到数组最后一位。既然到达数组最后一位,题目要求已符合,此时应不再执行跳跃动作,自然起跳计数不应该计数。

    • 综上所述:总的来说,贪心的问题核心还是在于对局部最优和全局最优的把握中,实际编程过程中,当前我最容易纠结在一些没必要的需求上,核心还是在于思考问题方式不够全面、发散,练习动手过少。

day2--9.13

1190. 反转每对括号间的子串

  1. 解析:

  2. 题解:

20. 有效的括号

  1. 解析:栈

  2. 题解:

     class Solution:
         def isValid(self, s: str) -> bool:  # 栈
             stack = []
             for i in range(len(s)):
                 top = stack[-1] if stack else None
                 if ')' == s[i] and top == '(':
                     stack.pop()
                     continue
                 if ']' == s[i] and top == '[':
                     stack.pop()
                     continue
                 if '}' == s[i] and top == '{':
                     stack.pop()
                     continue
                 stack.append(s[i])
             if len(stack) == 0:
                 return True
             return False
  3. 总结:

    • python栈的用法,list的用法,

1. 两数之和

  1. 解析:

  2. 题解: 解法一,暴力双循环

     class Solution:
         def twoSum(self, nums: List[int], target: int) -> List[int]:
             res = []
             for i in range(len(nums)):
                 for j in range(i+1, len(nums)):
                     if ( nums[i] + nums[j] ) == target:
                         res.append(i)
                         res.append(j)
             return res

    解法二,利用map哈希表

     class Solution:
         def twoSum(self, nums: List[int], target: int) -> List[int]:
             res = []
             # 哈希
             map = {}
             for i, num in enumerate(nums):
                 complement = target - num
                 if complement in map.keys():
                     return [map[complement], i]
                 map[num] = i
             return []
  3. 总结

    • 字典用法,字典遍历循环

    • 使用enumerate进行列表遍历

day3--9.29

14. 最长公共前缀

  1. 解析:https://www.cnblogs.com/vow007/p/18114649

  2. 题解:

     class Solution:
         def longestCommonPrefix(self, strs: List[str]) -> str:
             if len(strs) == 0:
                 return ""
             firstPrefix = strs[0]
     ​
             for i in range(len(firstPrefix)):
                 """纵向比较"""
                 first_ch = firstPrefix[i]
                 for j in range(1, len(strs)):
                     """每个字符串进行比较"""
                     if len(strs[j]) <= i or strs[j][i] != first_ch:
                         return firstPrefix[:i]
             return firstPrefix
     ​
  3. 总结:

    • python中,list切片的用法使用[:i]进行切片

1047. 删除字符串中的所有相邻重复项

  1. 解析:

  2. 题解:

     ​
     class Solution:
         def removeDuplicates(self, s: str) -> str:
             """栈移除相邻相同的元素"""
             stack = []
             size = len(s)
             if size == 0:
                 return ''
     ​
             for i in range(size):
                 """
                 1.空栈,直接入栈
                 2.非空,top != s[i],直接入
                 3.非空,top == s[i], 不入栈,且pop
                 """
                 if stack and stack[-1] == s[i]:
                     stack.pop()
                     continue
     ​
                 stack.append(s[i])
     ​
             return "".join(stack)
  3. 总结:

    • 本题主要考察栈的用法,重点明确python中栈的几种操作:(1)栈顶值top如何取;(2)弹栈;(3)压栈;(4)栈空判断;

    • 此外,本题还学习到list拼接字符串的方式:字符串的join()方法,用于将序列中的元素以指定的字符连接生成一个新的字符串。

392. 判断子序列

  1. 解析:

  2. 题解:

     class Solution:
         def isSubsequence(self, s: str, t: str) -> bool:
             """双指针,判别子序列"""
             if len(s) > len(t):
                 return False
             s_point = 0
             for i in range(len(t)):
                 if s_point < len(s) and t[i] == s[s_point]:
                     s_point += 1
             if s_point >= len(s):
                 return True
             return False
  3. 总结:

    • 此题使用快慢双指针很好解决

    • 注意点:本题注意空序列可以是任意序列的子序列,包括空序列

206. 反转链表

  1. 解析:

  2. 题解:

     # 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: Optional[ListNode]) -> Optional[ListNode]:
             if head is None:
                 return None
             res = ListNode()
             cur = head
             while cur is not None:
                 tmp = cur
                 cur = cur.next
                 tmp.next = res.next
                 res.next = tmp
     ​
             return res.next
     ​
  3. 总结:

    • 没什么难度~

day4---9.30

1190. 反转每对括号间的子串

  1. 解析:

  2. 题解:

     class Solution:
         def reverseParentheses(self, s: str) -> str:
             """
             实现思路:栈+双端队列
             1.s字符ch依次序进栈stack
             2.遇“)”进入弹栈,按弹栈顺序组成临时字符串temp
             3.若stack不为空,temp按索引顺序入栈
             4.继续对s进行入栈操作,循环23
             5.stack为空,返回temp
             """
             if len(s) == 0:
                 return ""
     ​
             stack = []
             for i in range(len(s)):
                 if len(stack) != 0 and s[i] == ')':
                     """遇到)弹栈"""
                     tmp = ""
                     while len(stack) != 0 and stack[-1] != '(':
                         """遇到(结束弹栈,弹栈值由tmp记录"""
                         tmp += stack[-1]
                         stack.pop()
                     stack.pop()  # 弹出'('
     ​
                     for j in range(len(tmp)):
                         stack.append(tmp[j])
     ​
                     continue    # 过滤)
     ​
                 stack.append(s[i])  # 其余情况,直接入栈
     ​
             if len(stack) != 0:
                 """处理s首尾无括号的情况"""
                 return "".join(stack)
     ​
             return ""
  3. 总结:

    • 本题处理过程中,主要问题在于:未充分考虑括号匹配的几种形式,如(abc)ab(c)(ab)ca(b)c

    • 此外,去掉括号后,栈里面的值需要按顺序输出

day5---10.01

739. 每日温度

  1. 解析:https://programmercarl.com/0739.%E6%AF%8F%E6%97%A5%E6%B8%A9%E5%BA%A6.html#%E7%AE%97%E6%B3%95%E5%85%AC%E5%BC%80%E8%AF%BE

  2. 题解:

     class Solution:
         def dailyTemperatures(self, temperatures: List[int]) -> List[int]:
             """
             双循环,超时,使用单调栈
             1.遍历temp数组,
             2.tmp[i]<=stack.top(),索引i入栈
             3.tmp[i] > stack.top()出栈
             4.asn[stack.top()] = i - stack.top()
             5.以此类推,直至tmp遍历完
             """
             res = [0] * len(temperatures)
             stack = []
             for i, T in enumerate(temperatures):
                 while len(stack) != 0 and T > temperatures[stack[-1]]:
                     res[stack[-1]] = i - stack[-1]
                     stack.pop()
                 stack.append(i)
             return res
  3. 总结:

    • 思路:找元素某一方向比其大/小的元素,如本题

    • 本题为第一次接触单调栈,若不用单调栈,此题使用暴力双循环会超时

    • 单调栈时间复杂度为O(n)

day6--10.02

781. 森林中的兔子

  1. 解析:https://leetcode.cn/problems/rabbits-in-forest/solutions/698444/sen-lin-zhong-de-tu-zi-by-leetcode-solut-kvla/

  2. 题解:

     class Solution:
         def numRabbits(self, answers: List[int]) -> int:
             """
             本题思想,利用哈希先去重,然后计算,本题只能通过列表进行数学推到
             1.建立哈希表,key=ans[i],value记录其出现次数
             2.遍历ans,哈希值进行累加
             3.分别计算每个ans至少需要多少兔子
             4.注意向上取整
             """
             if len(answers) == 0:
                 return None
             count = Counter(answers)
             ans = 0
             for key, value in count.items():
                 ans += (value + key) // (key + 1) * (key + 1)
             return ans
  3. 总结:

    • 本题理解,主要在于向上取整。假设有x只兔子回答y,即回答y的次数为x次,在字典中key=y,value=x;则这些回答y的兔子,至少要分为(y + x) // (y + 1)组。

    • 为什么是(y+1):因为需要加上回答问题的兔子,这里y+1也是每组兔子的最小数量

    • 为什么是(x + y) // (y+1):为了向上取整。这里核心在于(x + y)中加的y,之所以要加这个y就是为了最终结果进行向上取整。

    • 为什么是(x+ y)而不是(x + y + 1):若采用(x + y + 1)则在进行整除时,若x = y+1正好整除的情况下会多算1组。例如x = 3,y = 2,此时最少分一组即可,每组3个兔子,每个兔子都说有2个兔子与它颜色一样。

    • 为什么(x + y) // (y + 1) * (y + 1)中整除了(y + 1)然后有进行乘法操作:计算机计算顺序和数学运算存在差别,这里分子分母不会进行约分的精确计算,通过整除操作计算出最少需要多少组即(x + y) // (y + 1) 组,每组兔子的个数最少为y + 1,因此结果相乘之后得到总共需要多少只兔子。

    • 本题还需要多多理解,理解难点就是整除这一块。做题过程中有思考过整除、求余等,欲通过整除+余数计算,有许多特殊情况需要考虑,但是一旦转换为程序里面的整除问题,这些特殊情况就容易解决了。

    • 日后处理相关问题,凡是涉及到整除、求模取余等相关操作,要及时与整除进行联系,没准能够事半功倍的解决问题。


动物装饰