【LeetCode 刷题笔记 2022-10-19】

1700. 无法吃午餐的学生数量

1.注意事项

  • 简单题目,直接模拟就行
  • 来源:力扣(LeetCode)
  • 链接:题目传送门

2. 代码

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2022/10/19 8:38
# @Author  : David
# @File    : 1700. 无法吃午餐的学生数量.py
# @Description : 1700. 无法吃午餐的学生数量
from typing import List

"""
    学校的自助午餐提供圆形和方形的三明治,分别用数字 0 和 1 表示。所有学生站在一个队列里,每个学生要么喜欢圆形的要么喜欢方形的。
    餐厅里三明治的数量与学生的数量相同。所有三明治都放在一个 栈 里,每一轮:

    如果队列最前面的学生 喜欢 栈顶的三明治,那么会 拿走它 并离开队列。
    否则,这名学生会 放弃这个三明治 并回到队列的尾部。
    这个过程会一直持续到队列里所有学生都不喜欢栈顶的三明治为止。
    
    给你两个整数数组 students 和 sandwiches ,其中 sandwiches[i] 是栈里面第 i 个三明治的类型(i = 0 是栈的顶部),
     students[j] 是初始队列里第 j 名学生对三明治的喜好(j = 0 是队列的最开始位置)。请你返回无法吃午餐的学生数量。

    提示:
        1 <= students.length, sandwiches.length <= 100
        students.length == sandwiches.length
        sandwiches[i] 要么是 0 ,要么是 1 。
        students[i] 要么是 0 ,要么是 1 。
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/number-of-students-unable-to-eat-lunch
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
"""


def func_1(students: List[int], sandwiches: List[int]) -> int:
    """
        方法一,模拟执行的过程
        :param students: 学生列表
        :param sandwiches: 三明治列表
        :return: 返回吃不到午餐的学生数量
    """

    def insert():
        """
            将 students 中第一个数 (下标为 0) 插入到 students 最后 (下标为len(students))
            :return:None
        """
        t = students[0]
        for i in range(len(students) - 1):
            students[i] = students[i + 1]
        students[-1] = t

    if sum(students) == sum(sandwiches):
        # 没有学生吃不到午餐
        return 0
    else:
        # 有学生吃不到午餐
        result = 0  # 吃不到午餐的学生的数量

        k = j = len(students)  # 剩余学生数量
        while j > 0:
            if students[0] == sandwiches[0]:
                j -= 1  # 有一个学生已经拿到了午餐, 剩余学生数量 -1
                students.pop(0)  # 第一个学生删除
                sandwiches.pop(0)  # 第一份午餐删除
                k = j  # 记录剩余学生数量, 开始将第一个学生插入到 students 的末尾
            else:
                if k == 0:
                    # 如果所有剩余的学生都插入到 students 最后, 还有学生没有拿到午餐
                    # 则可以认为剩余的这些学生不可能拿到午餐, 记录学生的数量, 跳出循环
                    result = j
                    break
                else:
                    # 剩余没有插入到 students 末尾的学生数量
                    k -= 1
                    # 将 students 的第一个元素插入到 students 的末尾
                    insert()
        # 返回结果
        return result


class Solution(object):
    def Main(self):
        students, sandwiches = [1, 1], [0, 1]
        print(self.countStudents(students, sandwiches))

    def countStudents(self, students: List[int], sandwiches: List[int]) -> int:
        return func_1(students, sandwiches)


if __name__ == '__main__':
    Solution().Main()


60. 排列序列

1. 注意事项

  • 困难题
    • 回溯会超时
    • 需要使用数学的特点,计算第 k 个排列
  • 来源:力扣(LeetCode)
  • 链接:题目传送门

2. 代码

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2022/10/19 9:46
# @Author  : David
# @File    : 60. 排列序列.py
# @Description : 60. 排列序列

"""
    给出集合 [1,2,3,...,n],其所有元素共有 n! 种排列。

    按大小顺序列出所有排列情况,并一一标记,当 n = 3 时, 所有排列如下:
        1. "123"
        2. "132"
        3. "213"
        4. "231"
        5. "312"
        6. "321"
    给定 n 和 k,返回第 k 个排列。

    方法一:回溯,但是容易超时

    方法二:使用数学公式直接计算
        直接用回溯法做的话需要在回溯到第k个排列时终止就不会超时了, 但是效率依旧感人
        可以用数学的方法来解, 因为数字都是从1开始的连续自然数, 排列出现的次序可以推
        算出来, 对于n=4, k=15 找到k=15排列的过程:

        1 + 对2,3,4的全排列 (3!个)
        2 + 对1,3,4的全排列 (3!个)         3, 1 + 对2,4的全排列(2!个)
        3 + 对1,2,4的全排列 (3!个)-------> 3, 2 + 对1,4的全排列(2!个)-------> 3, 2, 1 + 对4的全排列(1!个)-------> 3214
        4 + 对1,2,3的全排列 (3!个)         3, 4 + 对1,2的全排列(2!个)         3, 2, 4 + 对1的全排列(1!个)

        确定第一位:
            k = 14(从0开始计数)
            index = k / (n-1)! = 2, 说明第15个数的第一位是3
            更新k
            k = k - index*(n-1)! = 2
        确定第二位:
            k = 2
            index = k / (n-2)! = 1, 说明第15个数的第二位是2
            更新k
            k = k - index*(n-2)! = 0
        确定第三位:
            k = 0
            index = k / (n-3)! = 0, 说明第15个数的第三位是1
            更新k
            k = k - index*(n-3)! = 0
        确定第四位:
            k = 0
            index = k / (n-4)! = 0, 说明第15个数的第四位是4
        最终确定n=4时第15个数为3214

    提示:
        1 <= n <= 9
        1 <= k <= n!

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/permutation-sequence
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
"""
from functools import cache


class Solution(object):
    def Main(self):
        n = 3
        k = 3
        print(self.getPermutation(n, k))

    def getPermutation(self, n: int, k: int) -> str:
        @cache
        def factorial(x):
            """
            求 x 的阶乘
            :param x: x
            :return: x 的阶乘
            """
            if x < 3:
                return x
            else:
                return x * factorial(x - 1)

        k -= 1  # k 需要从 0 开始计数

        result = ""  # 排列结果
        ln = list(range(1, n + 1))  # 可选择的数的集合
        for i in range(1, n + 1):
            # i 需要从 1 到 n, 包括 n
            t = factorial(n - i)  # n-1 的阶乘

            if k == 0 or t == 0:
                # 计算 index(下标) 排除除零错误
                index = 0
            else:
                index = k // t

            # 保存每一次选择的结果
            result = f"{result}{ln[index]}"

            # 删除已经选择的数
            ln.pop(index)

            # 更新 k, 继续下一次循环
            k -= (index * t)

        # 返回结果
        return result


if __name__ == '__main__':
    Solution().Main()



1455. 检查单词是否为句中其他单词的前缀

1. 注意事项

2. 代码

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2022/10/19 11:24
# @Author  : David
# @File    : 1455. 检查单词是否为句中其他单词的前缀.py
# @Description : 1455. 检查单词是否为句中其他单词的前缀

"""
    给你一个字符串 sentence 作为句子并指定检索词为 searchWord ,其中句子由若干用 单个空格 分隔的单词组成。
    请你检查检索词 searchWord 是否为句子 sentence 中任意单词的前缀。

    如果 searchWord 是某一个单词的前缀,则返回句子 sentence 中该单词所对应的下标(下标从 1 开始)。
    如果 searchWord 是多个单词的前缀,则返回匹配的第一个单词的下标(最小下标)。如果 searchWord 不是任何单词的前缀,则返回 -1 。

    字符串 s 的 前缀 是 s 的任何前导连续子字符串。

    提示:
        1 <= sentence.length <= 100
        1 <= searchWord.length <= 10
        sentence 由小写英文字母和空格组成。
        searchWord 由小写英文字母组成。

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/check-if-a-word-occurs-as-a-prefix-of-any-word-in-a-sentence
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
"""


class Solution(object):
    def Main(self):
        sentence = "i love eating burger"
        search_word = "burg"
        print(self.isPrefixOfWord(sentence, search_word))

    def isPrefixOfWord(self, sentence: str, search_word: str) -> int:
        word_list = sentence.split(" ")  # 切分句子, 获得句子中的所有单词
        for index, word in enumerate(word_list):
            if word.startswith(search_word):
                # 如果 search_word 是 word 的前缀, 返回 index +1
                return index + 1
        # 如果 search_word 不是 所有word 的前缀, 返回 -1
        return -1


if __name__ == '__main__':
    Solution().Main()


1450. 在既定时间做作业的学生人数

1. 注意事项

2. 代码

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2022/10/19 11:35
# @Author  : David
# @File    : 1450. 在既定时间做作业的学生人数.py
# @Description : 1450. 在既定时间做作业的学生人数
from typing import List

"""
    给你两个整数数组 startTime(开始时间)和 endTime(结束时间),并指定一个整数 queryTime 作为查询时间。
    
    已知,第 i 名学生在 startTime[i] 时开始写作业并于 endTime[i] 时完成作业。
    
    请返回在查询时间 queryTime 时正在做作业的学生人数。
    形式上,返回能够使 queryTime 处于区间 [startTime[i], endTime[i]](含)的学生人数。
    
    提示:
        startTime.length == endTime.length
        1 <= startTime.length <= 100
        1 <= startTime[i] <= endTime[i] <= 1000
        1 <=queryTime <= 1000

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/number-of-students-doing-homework-at-a-given-time
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
"""


class Solution(object):
    def Main(self):
        start_time, end_time, query_time = [1, 2, 3], [3, 2, 7], 4
        print(self.busyStudent(start_time, end_time, query_time))

    def busyStudent(self, start_time: List[int], end_time: List[int], query_time: int) -> int:
        res = 0  # 结果, query_time 时, 正在学习的学生数量
        for i in range(len(start_time)):
            if start_time[i] <= query_time <= end_time[i]:
                res += 1
        return res


if __name__ == '__main__':
    Solution().Main()


977. 有序数组的平方

1. 注意事项

2. 代码

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2022/10/19 11:46
# @Author  : David
# @File    : 977. 有序数组的平方.py
# @Description : 977. 有序数组的平方
from typing import List

"""
    给你一个按 非递减顺序 排序的整数数组 nums,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。
    
    提示:
        1 <= nums.length <= 10^4
        -10^4 <= nums[i] <= 10^4
        nums 已按 非递减顺序 排序
"""


def func_1(nums: List[int]) -> List[int]:
    """
        方法一:模拟,但是会出现超时
        :param nums: 目标数组
        :return: 每个数字的平方 组成的新数组
    """

    def insert_sort(val: int) -> None:
        """
            插入排序
            :param val: 待插入的数
            :return: None
        """
        flag = True  # 表示 val 需要插入数组的末尾
        for i in range(1, len(nums)):
            if nums[i] < val:
                nums[i - 1] = nums[i]
            else:
                nums[i - 1] = val
                flag = False  # 表示 val 已经插入到数组种
                break

        if flag:
            # 如果 val 是数组中的最大值时,需要特殊处理一下
            nums[-1] = val

    if len(nums) >= 2:
        # 如果数组长度大于等于2
        while nums[0] < 0:
            t = nums[0] * -1  # 取 nums[0] 的相反数
            insert_sort(t)

    for i in range(len(nums)):
        nums[i] *= nums[i]

    return nums


def func_2(nums: List[int]) -> List[int]:
    """
        方法二:直接求平方,然后排序
        :param nums: 目标数组
        :return: 每个数字的平方 组成的新数组
    """
    for i in range(len(nums)):
        nums[i] *= nums[i]
    nums.sort()

    return nums


class Solution(object):
    def Main(self):
        nums = [-1,-2,-3,1,2,3]
        print(self.sortedSquares(nums))

    def sortedSquares(self, nums: List[int]) -> List[int]:
        return func_2(nums)


if __name__ == '__main__':
    Solution().Main()


1929. 数组串联

1. 注意事项

2. 代码

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2022/10/19 12:42
# @Author  : David
# @File    : 1929. 数组串联.py
# @Description : 1929. 数组串联
from typing import List

"""
    给你一个长度为 n 的整数数组 nums 。请你构建一个长度为 2n 的答案数组 ans ,数组下标 从 0 开始计数 ,
    对于所有 0 <= i < n 的 i ,满足下述所有要求:
    
    ans[i] == nums[i]
    ans[i + n] == nums[i]
    具体而言,ans 由两个 nums 数组 串联 形成。
    
    返回数组 ans 。
    
    提示:
        n == nums.length
        1 <= n <= 1000
        1 <= nums[i] <= 1000

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/concatenation-of-array
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
"""


class Solution(object):
    def Main(self):
        nums = [1, 2, 1]
        print(self.getConcatenation(nums))

    def getConcatenation(self, nums: List[int]) -> List[int]:
        nums.extend(nums)
        return nums


if __name__ == '__main__':
    Solution().Main()


1351. 统计有序矩阵中的负数

1. 注意事项

2. 代码

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2022/10/19 12:51
# @Author  : David
# @File    : 1351. 统计有序矩阵中的负数.py
# @Description : 1351. 统计有序矩阵中的负数
from typing import List

"""
    给你一个 m * n 的矩阵 grid,矩阵中的元素无论是按行还是按列,都以非递增顺序排列。 请你统计并返回 grid 中 负数 的数目。
    
    提示:
        m == grid.length
        n == grid[i].length
        1 <= m, n <= 100
        -100 <= grid[i][j] <= 100

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/count-negative-numbers-in-a-sorted-matrix
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
"""


def binary_search(arr: List[int], left: int, right: int, target: int):
    """
        二分查找
        返回 x 在 arr 中的索引,如果不存在返回 -1
        :param arr: 目标数组
        :param left: 左边开始位置
        :param right: 右边结束位置
        :param target: 目标值
        :return: 返回 x 在 arr 中的索引
    """
    # 基本判断
    if right >= left:
        # mid = int(l + (r - l) / 2)
        mid = (right + left) // 2
        # 元素整好的中间位置
        if arr[mid] == target:
            return mid
            # 元素小于中间位置的元素,只需要再比较左边的元素
        elif arr[mid] > target:
            # 元素大于中间位置的元素,只需要再比较右边的元素
            # return binary_search(arr, left, mid - 1, target)
            return binary_search(arr, mid + 1, right, target)
        else:
            # return binary_search(arr, mid + 1, right, target)
            return binary_search(arr, left, mid - 1, target)
    else:
        # 不存在
        return -1


def func_1(grid: List[List[int]]) -> int:
    """
        统计并返回 grid 中 负数 的数目
        解决方案:
            1. 遍历矩阵的每一行
            2. 在每一行中使用二叉查找, 找到 "-1" 的下标
            3. 记录负数的个数
            4. 返回结果

        :param grid: 目标矩阵
        :return: grid 中负数的数目
    """
    n = len(grid)
    m = len(grid[0])
    ans = 0
    if grid[n - 1][m - 1] >= 0:
        # 特殊情况, 矩阵中没有负数
        return ans
    else:
        # m 大于等于 3, 使用二分查找进行统计
        for i in range(n):
            if grid[i][0] < 0:
                # 第 i 行, 第一个数小于零, 直接判定整行都是负数
                index = 0
            elif grid[i][m - 1] < 0:
                # 如果矩阵的第 i 行的最后一个数小于 0, 表示这一行种存在负数
                index = binary_search(grid[i], 0, m, - 1)  # 找到最后一个 -1 的下标

                if index == -1:
                    # 第 i 行中不存在 -1
                    for j in range(m - 1, -1, -1):
                        # 反向遍历 grid[i], 找到第一个负数
                        if grid[i][j] < 0:
                            index = j
                else:
                    # 找到第一个 -1 的下标
                    while grid[i][index - 1] == -1:
                        index -= 1
            else:
                # 第 i 行, 第一个数大于零, 并且最后一个数大于零
                index = m

            # 统计负数的个数
            ans += (m - index)
    return ans


def func_2(grid: List[List[int]]) -> int:
    """
        统计并返回 grid 中 负数 的数目
        解决方案:暴力破解
        :param grid: 目标矩阵
        :return: grid 中负数的数目
    """
    ans = 0
    for row in grid:
        for col in row:
            if col < 0:
                ans += 1
    return ans


class Solution(object):
    def Main(self):
        # grid = [[4, 3, 2, -1], [3, 2, 1, -1], [1, 1, -1, -2], [-1, -1, -2, -3]]
        # grid = [[3, 2], [1, 0]]
        # grid = [[1, -1, -1], [-1, -1, -2]]
        grid = [[7, -3]]
        print(self.countNegatives(grid))

    def countNegatives(self, grid: List[List[int]]) -> int:
        return func_2(grid)


if __name__ == '__main__':
    Solution().Main()
    # nums = [4, 3, 2, -1]
    # print(binary_search(nums, 0, len(nums) - 1, -1))


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值