LeetCode - Google 校招100题 第7天 序列(数据结构&贪心) (14题)

欢迎关注我的CSDN:https://spike.blog.csdn.net/
本文地址:https://spike.blog.csdn.net/article/details/144744418

Stack

LeetCode 合计最常见的 102 题:

  1. 校招100题 第1天 链表(List) (15题)
  2. 校招100题 第2天 树(Tree) (20题)
  3. 校招100题 第3天 动态规划(DP) (20题)
  4. 校招100题 第4天 查找排序(Search&Sort) (12题)
  5. 校招100题 第5天 双指针(Two Pointers) (11题)
  6. 校招100题 第6天 回溯法(Backtracking) (8题)
  7. 校招100题 第7天 序列(数据结构&贪心) (14题)
  8. 校招100题 第8天 图(Graph) (2题)

序列(数据结构&贪心) 算法包括栈、字典、集合、贪心等,基于不同的数据存储和访问方式的数据结构。栈(Stack) 是一种 后进先出(LIFO) 的数据结构,支持 推入(append) 和 弹出(pop) 操作,常用于处理嵌套问题和回溯算法。字典(Map) 是一种基于键值对的存储结构,提供快速的查找、插入和删除操作,其效率通常与哈希表的实现有关。集合(Set) 是一种无序且元素唯一的数据结构,支持高效的成员检查、添加和删除操作,常用于去重和数学集合操作。

1. 栈

1.1 32. 最长有效括号 (Hard)

Lintcode: 193 · 最长有效括号牛客常考题⭐️

class Solution:
    def longestValidParentheses(self, s: str) -> int:
        """
        最长有效括号, stack+flags更清晰,格式正确且连续,时间O(n), 空间O(n)
        """
        n = len(s)
        if n <= 1:
            return 0
        flags = [False] * n
        stack = []
        for i in range(n):
            if s[i] == "(":
                stack.append(i)
            else:
                if stack:
                    j = stack.pop(-1)
                    flags[i] = flags[j] = True
        res = 0
        tmp = 0
        for f in flags:
            if f:
                tmp += 1
                res = max(res, tmp)
            else:
                tmp = 0
        return res

1.2 394. 字符串解码

LintCode:575 · 字符串解码

class Solution:
    def decodeString(self, s: str) -> str:
        """
        栈操作,类似3[a]2[bc],时间O(S+|s|),空间复杂度O(S)
        """
        stack = []
        res = ""
        for c in s:
            if c != "]":  # 不等于
                stack.append(c)
                continue
            tmp = ""   # 解码"]"
            while stack and stack[-1] != "[":
                item = stack.pop(-1)
                tmp += item[::-1]  # 内部需要翻转,防止嵌套括号
            tmp = tmp[::-1]  # 整体进行翻转
            stack.pop()
            v = ""
            while stack and stack[-1].isdigit():
                item = stack.pop(-1)
                v += item[::-1]
            v = v[::-1]
            tmp = tmp * int(v)
            stack.append(tmp)
        res = "".join(stack)
        return res

1.3 739. 每日温度

LintCode:1060 · 每日温度

class Solution:
    def dailyTemperatures(self, temperatures: List[int]) -> List[int]:
        """
        最高温度出现在第几天之后,索引,输入列表,返回列表。
        单调栈,当前大于栈内最大值,则更新结果之后出栈
        时间O(n),空间O(n)
        """
        nums = temperatures
        n = len(nums)
        stack = []  # 单调栈
        res = [0] * n
        for i in range(n):
            while stack and nums[stack[-1]] < nums[i]:
                tmp = stack.pop()
                res[tmp] = i - tmp
            stack.append(i)
        return res

2. 集合

2.1 128. 最长连续序列

LintCode:124 · 最长连续序列牛客常考题⭐️

class Solution:
    def longestConsecutive(self, nums: List[int]) -> int:
        """
        最长连续序列,不考虑顺序,只考虑是否+1(连续),哈希表,依次判断是否存在,
        时间O(N),空间O(N)
        """
        res = 0
        v_set = set(nums)
        for v in v_set:
            if (v-1) in v_set:
                continue
            tmp = v  # 连续值
            r_tmp = 1
            while (tmp+1) in v_set:
                tmp += 1
                r_tmp += 1
            res = max(res, r_tmp)
        return res

2.2 14. 最长公共前缀

LintCode: 78 · 最长公共前缀牛客常考题⭐️

class Solution:
    def longestCommonPrefix(self, strs: List[str]) -> str:
        """
        最长公共前缀,时间O(N),空间O(M)
        """
        res = ""
        n_list = []
        for s in strs:
            n_list.append(len(s))
        n_min = min(n_list)
        for i in range(n_min):
            tmp = set()
            for s in strs:
                tmp.add(s[i])
            if len(tmp) == 1:
                res += list(tmp)[0]
            else:
                break
        return res

3. 字典

3.1 560. 和为 K 的子数组 (前缀和PreSum)

LintCode:838 · 子数组和为K牛客常考题⭐️

class Solution:
    def subarraySum(self, nums: List[int], k: int) -> int:
        """
        前缀和 + 哈希表优化: pre[i]-pre[j-1]=k -> pre[j-1]=pre[i]-k
        pre[i]是前n项的和, pre[j-1]是之前出现的和,统计哈希表中pre[j-1]出现的次数,即可。
        输入:nums = [1,2,3], k = 3,输出:2,谨记: 数组不是单调的话,不要用滑动窗口,考虑用前缀和
        时间复杂度O(N), 空间O(N)
        """
        n = len(nums)
        presum = 0  # presum[i],前缀值
        res = 0
        mp = collections.defaultdict(int) # 统计前缀值出现的次数
        mp[0] = 1 # 注意,初始化前缀值0是1
        for i in range(n):
            presum += nums[i]
            tmp = presum - k  # pre[j-1]的值
            if tmp in mp.keys():  # 这个值出现过,加入这个值出现的次数
                res += mp[tmp]
            mp[presum] += 1  # 加入新值
        return res

4. 贪心

4.1 55. 跳跃游戏

LintCode:116 · 跳跃游戏

class Solution:
    def canJump(self, nums: List[int]) -> bool:
        """
        跳跃游戏1,是否成功,贪心,最大跳跃长度,超越数组,时间O(n),空间O(1)
        nums = [3,2,1,0,4],输出:false
        """
        n = len(nums)
        if n == 1:
            return True
        v_max = 0  # 到达的最远距离
        for i in range(n-1):
            if i > v_max:
                return False
            v_max = max(v_max, nums[i]+i) # nums[i]+i 跳跃的最大长度
            if v_max >= n-1:  # 大于最后一个位置
                return True
        return True if v_max >= n-1 else False

4.2 45. 跳跃游戏 II

LintCode:117 · 跳跃游戏 II

class Solution:
    def jump(self, nums: List[int]) -> int:
        """
        跳跃游戏2,最小跳跃次数,贪心,时间O(n),空间O(1)
        nums[i]是从索引i向前跳转的 最大 长度
        """
        n = len(nums)
        if n == 1:
            return 0
        v_max = 0  # 到达的最远距离
        end = 0
        res = 0
        for i in range(n-1):
            if i > v_max:  # 小于一次最远位置
                return -1
            v_max = max(v_max, nums[i]+i)  # 当前最远的位置
            if i == end:  # i到达边界步数
                end = v_max  # 更新最大边界,同时跳跃次数+1
                res += 1  # 步数+1,一次一次的更新
        return res

4.3 134. 加油站

LintCode:187 · 加油站

class Solution:
    def canCompleteCircuit(self, gas: List[int], cost: List[int]) -> int:
        """
        运行环路一周,贪心算法,gas是加油数量,cost是花费,选择起始位置
        gas = [1,2,3,4,5], cost = [3,4,5,1,2], 输出: 3
        燃料最低点的下一个开始,时间O(n), 空间O(1)
        """
        n = len(gas)
        v_min = float("inf")
        i_min = 0  # 燃料最低点的位置
        tmp = 0
        for i in range(n):
            tmp += gas[i] - cost[i]  # 累计剩余燃料
            if tmp <= v_min:  # 保存剩余燃料最低值
                v_min = tmp
                i_min = i
        if tmp < 0:
            return -1
        return (i_min+1) % n  # 最低燃料的下一个开始

4.4 121. 买卖股票的最佳时机

LintCode:149 · 买卖股票的最佳时机牛客常考题⭐️

class Solution:
    def maxProfit(self, prices: List[int]) -> int:
        """
        买卖股票1,只在一只赚钱,时间O(n),空间O(1)
        输入:[7,1,5,3,6,4],输出:5
        """
        prev = prices[0]
        res = 0
        n = len(prices)
        for i in range(n):
            res = max(res, prices[i]-prev)
            prev = min(prev, prices[i])
        return res

4.5 122. 买卖股票的最佳时机 II

LintCode:150 · 买卖股票的最佳时机 II牛客常考题⭐️

class Solution:
    def maxProfit(self, prices: List[int]) -> int:
        """
        买卖股票2,赚差价,贪心,累加区间最大值,时间O(n),空间O(1)
        输入:prices = [1,2,3,4,5],输出:4
        """
        n = len(prices)
        res = 0
        for i in range(1, n):
            res += max(0, prices[i]-prices[i-1])
        return res

4.6 LCR 158. 库存管理 II(超过半数的数字)

牛客常考题⭐️

class Solution:
    def inventoryManagement(self, stock: List[int]) -> int:
        """
        数组中出现超过一半的数字(众数)
        摩尔投票法: 核心理念为 票数正负抵消。 时间O(N), 空间O(1)
        """
        nums = stock
        n = len(nums)
        v = 0    # 众数
        tmp = 0  # 投票,当投票是0时,替换新的数字
        for i in range(n):
            if tmp == 0:
                v = nums[i]
            if nums[i] == v:
                tmp += 1
            else:
                tmp -= 1
        res = 0  # 统计次数
        for i in range(n):
            if nums[i] == v:
                res += 1
        if res > (n//2):
            return v
        else:
            return 0

5. 矩阵模拟

5.1 48. 旋转图像

LintCode:161 · 旋转图像

class Solution:
    def rotate(self, matrix: List[List[int]]) -> None:
        """
        上下翻转、对角线翻转,顺时针旋转90°,即是旋转图像
        逆时针旋转90°是左右翻转
        时间O(n^2),空间O(1)
        """
        if not matrix or not matrix[0]:
            return
        m = len(matrix)
        n = len(matrix[0])
        # 上下翻转,如果是水平翻转(n-j-1),则逆时针旋转90°
        for i in range(m//2):
            for j in range(n):
                matrix[i][j], matrix[m-i-1][j] = matrix[m-i-1][j], matrix[i][j]
        # 对角矩阵翻转
        for i in range(m):
            for j in range(i):
                matrix[i][j], matrix[j][i] = matrix[j][i], matrix[i][j]

5.2 54. 螺旋矩阵

LintCode:374 · 螺旋矩阵牛客常考题⭐️

class Solution:
    def spiralOrder(self, matrix: List[List[int]]) -> List[int]:        
        """
        4个指针 + 上右不用判断,下左需要判断边界,时间O(mn), 空间O(1), 空间排除输出之外的复杂度
        """
        if not matrix or not matrix[0]:
            return []
        m = len(matrix)
        n = len(matrix[0])
        res = []
        l, r, t, b = 0, n-1, 0, m-1
        while l <= r and t <= b:
            for i in range(l, r+1):
                res.append(matrix[t][i])
            for i in range(t+1, b+1):
                res.append(matrix[i][r])
            # 非常重要的边界判断,否则会重复
            if l < r and t < b:
                for i in range(r-1, l-1, -1):
                    res.append(matrix[b][i])
                for i in range(b-1, t, -1):
                    res.append(matrix[i][l])
            l += 1
            r -= 1
            t += 1
            b -= 1
        return res
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ManonLegrand

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值