• leetcode marathon [复习] 8.24 - 9道


    组合,排列,子集

    给出一个集合[1,2,3,4],输出其:
    组合:k=2,[1,2],[1,3],[1,4]…
    排列:1234,1243,1324,1342…
    子集:[1],[1,2],[1,2,3]…
    编写代码时,主要分为两类

    排列顺序需要考虑:排列

    road 代表已有轨迹,choice代表选择
    每次需要复制,并添加新的选择,choice去除选择

    为什么要复制,不用全局数组?
    主要在于其中的for循环
    road 和 choice 都要参与到下一次循环,而我们希望这轮执行完,和初始一致(有的不需要,比如visited数组,就直接用全局很舒服)
    所以 要不就是对road和choice复制后 操作
    或者 操作完,把它恢复原状

    def permute(self, nums):
        """
        :type nums: List[int]
        :rtype: List[List[int]]
        """
    
        k = len(nums)
        result = []
    
        def dfs(road, choice_n):
            if len(road) == k:
                result.append(road)
                return
            else:
                for num_n in choice_n:
                    road_new = road[:]
                    road_new.append(num_n)
                    choice_new = choice_n[:]
                    choice_new.remove(num_n)
                    dfs(road_new, choice_new)
    
        dfs([], nums)
        return result
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    排列顺序不需要考虑:组合,子集

    很巧妙的方法,通过for循环开始的位置
    保证只能遍历后面的

    组合

    截至位置为 有k个数

    def combine(n, k):
        """
        :type n: int
        :type k: int
        :rtype: List[List[int]]
        """
        res=[]
    
        def dfs(track,start,choice):
            print(f"当前track:{track}")
            print(f"当前start:{start}")
            if len(track)==k:
                res.append(track)
                return
            else:
                # 关键是理解 其中的start,每个节点的选择只能是当前节点后面的
                for i in range(start,len(choice)):
                    num=choice[i]
                    track_new=track[:]
                    track_new.append(num)
                    dfs(track_new,i+1,choice)
    
        dfs([],0,[i+1 for i in range(n)])
        return res
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    子集

    每个遍历点都加上

    def subsets(nums):
        res=[]
        def dfs(track,start,choice):
            res.append(track)
            for i in range(start,len(choice)):
                new_track=track[:]
                new_track.append(choice[i])
                dfs(new_track,i+1,choice)
        dfs([],0,nums)
        res.remove([])
        return res
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    没有重复数字的子集,组合,排列

    首先把初始数组排序一下,然后记录last_num,一样则不添加…第一个赋值成" ",字符串还巧滴.
    47. 全排列 II

    def permuteUnique(nums):
        """
        :type nums: List[int]
        :rtype: List[List[int]]
        """
        nums=sorted(nums)
        print(f"排序后:{nums}")
        n=len(nums)
        res=[]
        def dfs(track,choice):
            print(f"track:{track}")
            print(f"choice:{choice}")
            if len(track)==n:
                res.append(track)
                return
            else:
                last_num=" "
                for num in choice:
    
                    if num == last_num:
                        continue
                    last_num=num
                    new_choice=choice[:]
                    new_choice.remove(num)
                    new_track=track[:]
                    new_track.append(num)
                    dfs(new_track,new_choice)
        dfs([],nums)
        return res
    
    if __name__ == '__main__':
        nums=[1,1,2]
        print(permuteUnique(nums))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    41. 缺失的第一个正数 -两个思路

    本地存储

    它要求常数空间复杂度, 立马想到本地存储,本地存储指的是直接在本数组中存储信息,比如全是正数,那么某一位是负数的时候,就代表这一位被标记了.

    ```python
    def firstMissingPositive(nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        n=len(nums)
        # 第一次循环将所有负数全变成n+1
        for i in range(len(nums)):
            if nums[i] <= 0:
                nums[i] = n+1
        print(nums)
        # 第二次循环将所有>0且<=n的数 对应的索引上的数全变成负数
        # 注意索引与该数之间差1哦
        # 防止[1,1,1]这种情况,变成负数的时候,要先检查它是否是正数
        for i in range(len(nums)):
            if abs(nums[i]) <= n and nums[abs(nums[i])-1] >0:
                nums[abs(nums[i])-1] = -nums[abs(nums[i])-1]
    
        print(nums)
        for i in range(len(nums)):
            if nums[i] > 0:
                return i+1
        return n+1
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    跳转遍历

    指的是o(n)时间复杂度的遍历

    需要 能够区分本位置的数对不对
    然后立足于本位置,不断交换

    在这里插入图片描述

    rom typing import List
    
    
    class Solution:
    
        # 3 应该放在索引为 2 的地方
        # 4 应该放在索引为 3 的地方
    
        def firstMissingPositive(self, nums: List[int]) -> int:
            size = len(nums)
            for i in range(size):
                # 先判断这个数字是不是索引,然后判断这个数字是不是放在了正确的地方
                while 1 <= nums[i] <= size and nums[i] != nums[nums[i] - 1]:
                    self.__swap(nums, i, nums[i] - 1)
    
            for i in range(size):
                if i + 1 != nums[i]:
                    return i + 1
    
            return size + 1
    
        def __swap(self, nums, index1, index2):
            nums[index1], nums[index2] = nums[index2], nums[index1]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    50. Pow(x, n)

    记忆化递归

    快速幂算法

    比如 2 10 = 2 5 ∗ 2 5 2^{10}=2^5 * 2^5 210=2525 只需要算pow(2,5) 即可
    利用递归(二分的思路),加上记忆化策略(当函数遇到相同参数时,直接用cache) 语法糖@cache

    class Solution:
        def myPow(self, x: float, n: int) -> float:
            """
            :type x: float
            :type n: int
            :rtype: float
            """
            return dfs(x,n)
    @cache
    def dfs(x,n):
    
        # 如果是1的话
        if n==0:
            return 1
        if n == 1:
            return x
        # 如果是2的话
        if n==2:
            return x*x
        if n==-1:
            return 1/x
        # 如果n是偶数的话
        if n%2==0:
    
            return dfs(x,n//2)*dfs(x,n//2)
        else: # 如果是奇数的话
            return dfs(x,n//2)*dfs(x,n//2)*dfs(x,n%2)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    58. 最后一个单词的长度

    正则表达式 字符串处理

    很多字符串题目可以直接用正则表达式做
    这题是最基础那种,连正则表达式都不需要

    def lengthOfLastWord(s):
        """
        :type s: str
        :rtype: int
        """
        # api 战士
        return len(s.strip().split(" ")[-1])
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    71. 简化路径

    正则表达式+栈

    用re.split 轻松分割
    用栈,类似括号匹配的思路
    遇到… 则弹出一个

    import re
    class Solution:
        def simplifyPath(self, path: str) -> str:
            stack1=[]
            names=re.split(r'/+',path)
            print(names)
            for name in names:
                if name=='..':
                    if len(stack1)!=0:
                        stack1.pop()
                elif name=='.' or name=='':
                    continue
                else:
                    stack1.append(name)
            return "/"+"/".join(stack1)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    125. 验证回文串

    正则表达式

    import re
    class Solution:
        def isPalindrome(self, s: str) -> bool:
            a="".join(re.split(r"[^a-zA-Z0-9]+",s)).lower()
            if len(a)%2==0:
                if a[:len(a)//2]==a[len(a)//2:][::-1]:
                    return True
            if len(a)%2==1:
                if a[:len(a)//2]==a[len(a)//2+1:][::-1]:
                    return True
            return False
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    26. 删除有序数组中的重复项

    本地修改-快慢指针

    需要在数组原地存储,则用慢指针来存储,快指针用来访问

    # 快慢指针
    # 慢指针负责存储
    # 快指针负责查找
    # 当快指针找到一个符合要求的则传给慢指针
    def removeDuplicates(nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        slow=0
        for fast in range(len(nums)):
            if nums[fast] != nums[slow]:
                slow+=1
                nums[slow]=nums[fast]
        return nums[:slow+1]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
  • 相关阅读:
    使用ffmepg实现多路视频流合并
    React Native常用的Text和Image组件
    2.1 C++面向对象编程_访问控制和继承
    CentOS7 离线安装 Zabbix5.0
    Linux_文件权限
    一次请求的来龙去脉 - Tomcat架构解析(一)
    设计模式-观察者模式详解
    云课五分钟-0B快速排序C++示例代码-注释和编译指令
    Golang =比较总结
    LibreOffice编辑excel文档如何在单元格中输入手动换行符
  • 原文地址:https://blog.csdn.net/hch977/article/details/126497477