Leetcode各种题型题目+思路+代码(共176道题)

文章目录

第一章:Leetcode 每日很多题

1、Leetcode-1047 删除字符串中的所有相邻重复项

题目描述:
在这里插入图片描述
题目思路
使用stack的思路,先把字符串的第一个字母压栈,然后判断下一个待压栈的字母是否与stack[-1]的字母相同,如果相同,该字母不进入stack中,且stack.pop()将重复的字母剔除。如此遍历一遍字符串,最后返回stack中的元素即为消除重复字后的字符串。
举例:"abbaca"

  • 建立栈
  • 把a压栈
  • b与a不相同,压栈
  • 第二个b和stack栈口元素相同,不要第二个b且把栈扣的b pop掉。
  • 第四个元素:a,此时stack中还有一个元素a,相同,不要第四个元素且把stack中的a pop掉
  • 压c,压a
  • 返回ca即为结果

代码:

def main(S):
    stack=[]
    for i in S:
        if stack and stack[-1]==i:
            stack.pop()
        else:
            stack.append(i)
    return "".join(stack)

2、剑指 Offer 53 - I. 在排序数组中查找数字 I

代码实现

class Solution:
    def search(self, nums: List[int], target: int) -> int:
        dic1=collections.defaultdict(int)
        for i in nums:
            dic1[i]+=1
        return dic1[target] if dic1[target] else 0

3、Leetcode704:二分查找

题目描述
在这里插入图片描述
代码实现

class Solution:
    def search(self, nums: List[int], target: int) -> int:

        left=0
        right=len(nums)-1
        while left<=right:
            mid=(left+right)//2
            if nums[mid]>target:
                right=mid-1
            elif nums[mid]<target:
                left=mid+1
            else:
                return mid
        return -1

4、 Leetcode 227:基本计算器II

题目描述:
在这里插入图片描述
解题思路:
首先对于计算器来说有加减乘除四种符号,对于加减的符号,运算主要看加减符号后面的两个数字。对于乘除符号,运算主要看乘除符号前后的数字。解题思路是维护一个栈,遍历输入字符串,当遇到的都是数字那么把它们做累加定义为变量num,当遍历到不是数字时,空格的话忽略。如果是计算符号,在当前时刻查看上一个符号,会有四种情况:

  • “+”:只需把num的数字压栈即可
  • “-”:只需把num的相反数压栈即可
  • “*”:需要从栈中取出上一次压栈的数字并与当前num做乘法压栈。
  • “/”:需要把栈中上一次压栈的数字并与当前num做除法取整即可。
    对于出现计算符号的每个时刻计算的都是它前面保留的num和上一次符号的计算。所以当前时刻计算压栈后,prev_flag定义为当前符号,在下一次出现计算符号开始计算,num作为计数变量也要清零。

代码

class Solution:
    def calculate(self, s: str) -> int:
        s+="$"
        stack=[]
        pre_flag="+"
        num=0
        for i in s:
            if i.isdigit():
                num=num*10+int(i)
            elif i==" ":
                continue
            else:
                if pre_flag=="+":
                    stack.append(num)
                elif pre_flag=="-":
                    stack.append(-(num))
                elif pre_flag=="*":
                    stack.append(stack.pop()*num)
                elif pre_flag=="/":
                    stack.append(int(stack.pop()/num))
                pre_flag=i
                num=0
        return sum(stack)

5、leetcode 224:基本计算器(带括号的计算)

解题思路:
与第九题大致相同,但加入一个递归去计算每次括号中的数字,并且返回,如此递归下去。

class Solution:
    def calculate(self, s: str) -> int:
        def dfs(s,start):
            stack=[]
            prev_flag="+"
            i=start
            num=0
            while i <len(s):
                if s[i]==" ":
                    i+=1
                    continue
                elif s[i].isdigit():
                    num=num*10+int(s[i])
                elif s[i]=="(":
                    i,num=dfs(s,i+1)
                else:
                    if prev_flag=="+":
                        stack.append(num)
                    elif prev_flag=="-":
                        stack.append(-num)
                    if s[i]==")":
                        break
                    prev_flag=s[i]
                    num=0
                i+=1
            return i,sum(stack)
        s+="$"
        return dfs(s,0)[1]

6、Leetcode 15:三数之和:排序+双指针

解题思路:
首先面对三树之和,先将列表用sort进行排序,然后第一层遍历每一个元素,对于每一次每一个位置的元素,都设定左右指针,右指针指list最后,左指针为当前元素的下一个。即:

  • left=i+1
  • right=len(list)-1
    接下来就是一个判别式,具体为三种情况:
  • 如果左右指针对应元素小于target-list[i],说明最小的不够大,left指针加1
  • 如果左右指针对应元素大于target-list[i],说明最大的不够小,right指针减1
  • 如果左右指针对应元素相加正好等于target-list[i],满足题意,把三个数存储在列表排序经过tuple后添加到res集合中。左右指针分别加1减1继续查看。
  • 最后只要把res列表化就可以了

两个问题:

  • 第一个问题是为了达到去重的效果我是把列表sorted后tuple化添加到集合中的,然后再把集合list,其实里面的还是tuple,但是在leetcode中输出的还是list of list的形式。不太明白这段怎么处理。
  • 常见的三数之和也可以使用哈希表加两层for循环查找,但在之前的题目中,我是通过字典存储nums中每个元素是否出现,然后两层for 循环查找是否target-j-k是否在字典中。但该题中列表元素中有重复的,那么使用哈希表就还要存储它在nums中的index,这点没有想到办法处理。只能使用排序+双指针好理解一些。后续的处理是建立一个新列表,遍历集合中的元组列表化插入新的列表。这样就不需要判断和上一次枚举的不同的这个条件了。

代码

class Solution:
    def threeSum(self, nums: List[int]) -> List[List[int]]:
        nums.sort()
        res=set()
        for i in range(len(nums)):
            j=i+1
            k=len(nums)-1
            while j <k:
                if nums[j]+nums[k]<-nums[i]:
                    j+=1
                elif nums[j]+nums[k]>-nums[i]:
                    k-=1
                else:
                    res.add(tuple(sorted([nums[j],nums[k],nums[i]])))
                    k-=1
                    j+=1
        list1=[]
        for j in res:
            list1.append(list(j))
        return list1

7、剑指 offer 38.字符串的排列

问题描述
在这里插入图片描述
解题思路
最直接的办法就是对于一个给定字符串,对于第一个位置可以是任何字符串中的任何一个字母,分类讨论,固定好第一个字母,从剩下的字母中选择去固定下一个字母位置,如此递归,终止条件即位len-1的位置也固定好了以后,返回每一种情况。在其中要注意的是,如果列表中出现重复的字母的话,使用set()去重后,不需要让重复的再进行固定了。
代码

class Solution:
    def permutation(self, s: str) -> List[str]:
        c,res=list(s),[]
        def dfs(x):
            #终止条件:
            if x==len(s)-1:
                res.append("".join(c))
                return 
            dic=set()
            #循环字符串的每一个位置
            for i in range(x,len(c)):
                if c[i] in dic:#重复的不需要固定
                    continue
                dic.add(c[i])
                c[i],c[x]=c[x],c[i]
                dfs(x+1)#对下一位进行递归
                c[i],c[x]=c[x],c[i]#调换回来
        dfs(0)
        return res

8、Leetcode409:最长回文串

题目描述
在这里插入图片描述
代码

class Solution:
    def longestPalindrome(self, s: str) -> int:
        n=len(s)
        li=[s.count(i)%2 for i in set(s)]
        return n - max(0,sum(li)-1)

9、Leetcode 331:验证二叉树的前序序列化

题目描述
在这里插入图片描述
解题思路:
如果对于一个节点,它的两个子节点都是"#",那么可以将这一组节点变为#。
例如
9,#,# ——>#,再去和他的上一层进行比较。遍历一遍前序遍历的列表,如果到最后只剩下["#"]表示序列化正常。
代码实现:

class Solution:
    def isValidSerialization(self, preorder: str) -> bool:
        stack=[]
        for i in preorder.split(","):
            stack.append(i)
            while len(stack)>=3 and stack[-1]==stack[-2]=="#" and stack[-3]!="#":
                stack.pop(),stack.pop(),stack.pop()
                stack.append("#")
        return len(stack)==1 and stack.pop()=="#"

10、Leetcode 705:设计哈希集合

题目描述
在这里插入图片描述
解题思路
对于输入的key使用key%1009作为哈希函数存储,无论是add,remove还是contain都通过查看self.table[hashkey]中是否有当前key来决定操作。self.table是一个列表存储了哈希的键位和值。

代码

class MyHashSet:

    def __init__(self):
        """
        Initialize your data structure here.

        """
        self.buckets=1009
        self.table=[[] for i in range(self.buckets)]
    
    def hash(self,key):
        #将输入的key进入哈希映射
        return key%self.buckets


    def add(self, key: int) -> None:
        hashkey=self.hash(key)
        if key in self.table[hashkey]:
            return
        self.table[hashkey].append(key)


    def remove(self, key: int) -> None:
        hashkey=self.hash(key)
        if key not in self.table[hashkey]:
            return
        self.table[hashkey].remove(key)


    def contains(self, key: int) -> bool:
        """
        Returns true if this set contains the specified element
        """
        hashkey=self.hash(key)
        if key in self.table[hashkey]:
            return True
        else:
            return False

11、Leetcode 13:罗马数字转整数:

题目描述
在这里插入图片描述

解题思路

  • 定义一个字典存储每个罗马数字对应的int值
  • 遍历str,如果当前的这个罗马数字对应的int值是小于下一个的,那么就要在输出值减去当前值
  • 否则,就加上当前罗马数字对应的十进制数字。

代码

class Solution:
    def romanToInt(self, s: str) -> int:
        dic={
   "I":1,"V":5,"X":10,"L":50,"C":100,"D":500,"M":1000}
        ans=0
        for i in range(len(s)):
            if i<len(s)-1 and dic[s[i]]<dic[s[i+1]]:
                ans-=dic[s[i]]
            else:
                ans+=dic[s[i]]
        return ans

12、Leetcode 88:合并两个有序数组

题目描述
在这里插入图片描述

解题思路
定义两个指针,分别遍历两个nums。终止点是指针到达m和n为止。
这里边要注意的是要对nums1进行浅拷贝。
因为有可能p和q一个遍历完了,一个还没有遍历完,所以while循环后要把剩下的使用extend补齐。

代码

class Solution:
    def merge(self, nums1: List[int], m: int, nums2: List[int], n: int) -> None:
        """
        Do not return anything, modify nums1 in-place instead.

        """
        nums1_copy=nums1[:m]
        nums1[:]=[]
        p=0
        q=0
        while p < m and q<n:
            if nums1_copy[p]<=nums2[q]:
                nums1.append(nums1_copy[p])
                p+=1
            else:
                nums1.append(nums2[q])
                q+=1
        nums1.extend(nums1_copy[p:])
        nums1.extend(nums2[q:])

13、Leetcode 706:设计哈希映射

此题比较简单,就直接放代码了

class MyHashMap:

    def __init__(self):
        """
        Initialize your data structure here.
        """
        self.map=[-1]*1000001


    def put(self, key: int, value: int) -> None:
        """
        value will always be non-negative.
        """
        self.map[key]=value


    def get(self, key: int) -> int:
        """
        Returns the value to which the specified key is mapped, or -1 if this map contains no mapping for the key
        """
        return self.map[key]


    def remove(self, key: int) -> None:
        """
        Removes the mapping of the specified value key if this map contains a mapping for the key
        """
        self.map[key]=-1

14、Leetcode 54 螺旋矩阵:

题目描述
在这里插入图片描述

解题思路
对于顺时针遍历螺旋矩阵,最难的点在于何时更改方向,从例子中可以看到,更改方向的点都是走到了行和列的边缘,或者遇到已经走过的点。那么对于本题,需要创建的除了一个存储所有螺旋便利的列表,还需要一个列表存储下一个点的行列信息是否已经走过的状态列表。遍历行和列所有的点,只要加入一次方向后,再该方向上不是边界外的点且没有遍历过,该点就可以加入res列表。除此之外,direction的列表的方向应该按顺时针书写。
代码

class Solution:
    def spiralOrder(self, matrix: List[List[int]]) -> List[int]:
        #统计行和列的数量
        row=len(matrix)
        col=len(matrix[0])
        #所有的元素个数
        total=row*col
        #建立一个存储是否访问过的矩阵
        visited=[[False ] * col for i in range(row)]
        #建立一个存储路径的列表
        order=[0]*total
        #建立顺时针的方向矩阵
        direction=[[0,1],[1,0],[0,-1],[-1,0]]
        #初始化位置和方向索引
        r,c=0,0
        direction_idx=0

        #开始遍历
        for k in range(total):
            #向order中添加元素信息
            order[k]=matrix[r][c]
            #在vistied 中存储路径
            visited[r][c]=True
            #计算下一个位置的坐标点
            next_r=r+direction[direction_idx][0]
            next_c=c+direction[direction_idx][1]
            #判断这个点是否满足条件
            if not (0<=next_r<row and  0<=next_c<col and not visited[next_r][next_c]):
                #顺时针更新方向,只需要更新一次方向就可以保证一定可以继续走
                direction_idx=(direction_idx+1)%4
            #更新r和c的坐标
            r+=direction[direction_idx][0]
            c+=direction[direction_idx][1]
        return order

15、 Leetcode 14 最长公共前缀

题目描述
在这里插入图片描述
解题思路
Approach 1:纵向查找
纵向查找,只需要以第一个单词的长度为基准,对比其他单词在每一位上是否相同,如果出现了不同或已经到达了任何一个词的长度,只需要返回前面的i-1个单词即可。
Approach 2: 分治
加入这个strs有四个单词,那么把它分成两份,再对其中每一份进行两两之间的比较,返回两两之间的最长公共前缀,再进行回溯,因为最长公共前缀是所有单词的公共前缀。终止条件是左边界等于右边界。

代码

#纵向搜索
class Solution:
    def longestCommonPrefix(self, strs: List[str]) -> str:
        if not strs:
            return ""
        length=len(strs[0])
        count=len(strs)
        for i in range(length):
            if any(i==len(strs[j]) or strs[j][i]!=strs[0][i] for j in range(1,count)):
                return strs[0][:i]
        #如果都相同
        return strs[0][:length]
class Solution:
    def longestCommonPrefix(self, strs: List[str]) -> str:
        #分治的思想
        def dfs(start,end):
            #终止条件:
            if start == end:
                return strs[start]
            #将strs里面的字母分开
            mid=(start+end)//2
            #递归左右两边
            left=dfs(start,mid)
            right=dfs(mid+1,end)
            #对比两个返回的长度,取小的那个
            min_length=min(len(left),len(right))
            #遍历较短的单词
            for j in range(min_length):
                #一旦他们出现了不相等的位置
                if left[j]!=right[j]:
                    return left[:j]
            #如果都相同,return较短的
            return left[:min_length]
        return "" if not strs else dfs(0,len(strs)-1)

16、Leetcode 20:有效的括号

题目描述
在这里插入图片描述

解题思路
采用栈的思想,遍历字符串中的每一个括号,分成四类讨论:

  • 如果是")“且上一个也是”(",那么把上一个出栈
  • 如果是”]“且栈的上一个是"[",那么把上一个出栈
  • 如果是"}“且栈的最后一个是”{",那么把栈的最后一个出栈。
  • 如果不满足上述四个,将当前括号类型压栈。
    如果最后stack的长度为0说明符合标准,返回True,否则返回False。

代码

class Solution:
    def isValid(self, s: str) -> bool:
        stack=[]
        n=len(s)
        for i in s:
            if stack and i=="]" and stack[-1]=="[":
                stack.pop()
            elif stack and i==")" and stack[-1]=="(":
                stack.pop()
            elif stack and i=="}" and stack[-1]=="{":
                stack.pop()
            else:
                stack.append(i)
        return True if len(stack)==0 else False

17、Leetcode 21:合并两个有序的链表

题目描述

加粗样式

递归方法

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def mergeTwoLists(self, l1: ListNode, l2: ListNode) -> ListNode:
        if l1 is None:
            return l2
        elif l2 is None:
            return l1
        elif l1.val > l2.val:
            l2.next=self.mergeTwoLists(l1,l2.next)
            return l2
        else:
            l1.next=self.mergeTwoLists(l1.next,l2)
            return l1

迭代方法

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def mergeTwoLists(self, l1: ListNode, l2: ListNode) -> ListNode:
        #迭代的方法
        #建立一个节点
        head=ListNode(-1)
        #定义指针
        pre=head
        while l1 and l2:
            if l1.val>l2.val:
                pre.next=l2
                l2=l2.next
            else:
                pre.next=l1
                l1=l1.next
            #比较完要移动一次指针
            pre=pre.next
        #将剩下的没有添加完的添加进head
        pre.next=l1 if l1 is not None else l2
        return head.next

18、Leetcode 139:单词拆分问题

题目描述
在这里插入图片描述

解题思路
本题使用动态规划解决,建立一个dp列表长度为n+1,每个位置储存的状态为false,dp[i]表示从str[:i]能否满足题意,遍历str的长度,遍历每个i前面的所有字母,只要s[j-1:i]存在在字典,那么dp[i]和dp[j-1]的状态是一样的。

代码

class Solution:
    def wordBreak(self, s: str, wordDict: List[str]) -> bool:
        #建立一个DP列表
        n=len(s)
        dp=[False]*(n+1)
        #初始化
        dp[0]=True

        #遍历
        for i in range(1,n+1):
            for j in range(i,-1,-1):
                if  s[j-1:i] in wordDict:
                    dp[i]|=dp[j-1]
        return dp[n]

19、剑指Offer 29:顺时针打印矩阵

该题和螺旋矩阵相同,直接上代码

class Solution:
    def spiralOrder(self, matrix: List[List[int]]) -> List[int]:
        #计算行的长度
        row=len(matrix)
        if row==0:
            return []
        #计算列的长度
        col=len(matrix[0])

        #计算有多少个数字
        total=col*row
        #定义一个存储访问的矩阵
        visted=[[False]*col for i in range(row)]
        #定义一个最后输出的矩阵
        res=[0]*total
        #定义方向的列表
        direction=[(0,1),(1,0),(0,-1),(-1,0)]
        #定义col和row的起始位置
        r,c=0,0
        direction_id=0
        #开始遍历
        for i in range(total):
            res[i]=matrix[r][c]
            visted[r][c]=True
            #定义direction id
            new_r=r+direction[direction_id][0]
            new_c=c+direction[direction_id][1]
            #判断这个点是否满足条件
            if not (0<=new_r<row and 0<=new_c<col and not visted[new_r][new_c]):
                direction_id=(direction_id+1)%4
            r+=direction[direction_id][0]
            c+=direction[direction_id][1]
        return res

20、LCP 11: 期望个数统计

class Solution:
    def expectNumber(self, scores: List[int]) -> int:
        return len(set(scores))

21、Leetcode 59:螺旋矩阵II

题目描述

在这里插入图片描述
解题思路
这道题和原本的螺旋矩阵类似,但是不需要维护一个状态的矩阵,只需要判断matrix中下一个位置的值是否为初始值0。
代码

class Solution:
    def generateMatrix(self, n: int) -> List[List[int]]:
        #设定行和列的数量
        row,col=n,n
        #建立一个填入的矩阵
        matrix=[[0]*n for _ in range(n)]
        #建立方向
        direction=[(0,1),(1,0),(0,-1),(-1,0)]
        #建立初始坐标和方向索引
        r,c,d=0,0,0
        #开始添加
        for i in range(n*n):
            matrix[r][c]=i+1
            new_r=r+direction[d][0]
            new_c=c+direction[d][1]
            #查看下一个坐标位置是否符合规则
            if not(0<=new_c<col and 0<=new_r<row and matrix[new_r][new_c]==0):
                #方向顺时针转动一次
                d=(d+1)%4
            #更新坐标
            r+=direction[d][0]
            c+=direction[d][1]
        return matrix

22、Leetcode 101 : 对称二叉树

题目描述
在这里插入图片描述

代码实现
Approach 1:递归
使用递归做,就是定义函数不断地去判断每个左节点下的左子节点,和右节点下的右子节点和左节点下的右子节点和右节点下的左子节点是否相同。这里比较麻烦的是终止条件:

  • 条件1:如果left和right都为空,为true:not(left or right)
  • 条件2:如果left和right 有一个为空,为False:not(left and right)
  • 条件3:如果left和right的val不同,为False
# 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: TreeNode) -> bool:
        if not root:
            return True
        def dfs(left,right):
            #left代表左叶节点,left代表右叶节点
            #终止条件1:如果left和right为空
            if not (left or right):
                return True
            #终止条件2:如果left和right有一个为空:
            if not (left and right):
                return False
            #终止条件3,left和right不相等
            if left.val!=right.val:
                return False
            #进入递归
            return dfs(left.left,right.right) and dfs(left.right,right.left)
        return dfs(root.left,root.right)

Approach 2:队列迭代

# 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: TreeNode) -> bool:
        #建立一个队列
        queue=collections.deque()
        queue.extend([root.left,root.right])
        while queue:
            #拿出第一对
            left=queue.popleft()
            right=queue.popleft()
            #如果left和right都为空
            if not (left or right):
                continue
            #如果一个为空:
            if not (left and right):
                return False
            if left.val!=right.val:
                return False
            #将left的左节点,right的右节点添加队列
            queue.extend([left.left,right.right])
            #将left的右节点,right的左节点添加队列
            queue.extend([left.right,right.left])

        return True

23、Leetcode 115:不同的子序列

题目描述
在这里插入图片描述

解题思路
转移方程的话已经在代码中写到了,解题思路感觉这个大佬写的最清晰,即如果当前对比的位置字符相同,我可以选择进行匹配或者不进行匹配,因为从右往左的顺序进行匹配的话,即使相同前面可能也会有相同的,所以有两种选择。
在这里插入图片描述

代码实现

class Solution:
    def numDistinct(self, s: str, t: str) -> int:
        #统计两个字符串的长度
        m,n=len(s),len(t)
        #以t为子串,如果t比s长,不符合题意
        if m<n:
            return 0
        #建立储存的状态矩阵
        dp=[[0]*(n+1) for _ in range(m+1)]
        #初始化,如果n=0,那么它可以使s的任何子串
        for i in range(m+1):
            dp[i][n]=1
        #如果m=0,没有字串
        #开始遍历
        for i in range(m-1,-1,-1):
            for j in range(n-1,-1,-1):
                #如果当前字母匹配
                if s[i]==t[j]:
                    #那么有可能是从s+1,j+1转移,也可能是s+1,j转移
                    dp[i][j]=dp[i+1][j+1]+dp[i+1][j]
                else:
                    #如果不相等,只能考虑s+1,j
                    dp[i][j]=dp[i+1][j]
        return dp[0][0]

24、Leetcode 1603 :设计停车系统

题目描述
在这里插入图片描述

解题思路
这题想通过还是很简单的,不做赘述了。

代码实现

class ParkingSystem:

    def __init__(self, big: int, medium: int, small: int):
        self.big=big
        self.medium=medium
        self.small=small


    def addCar(self, carType: int) -> bool:
        if carType==3:
            if self.small>=1:
                self.small-=1
                return True
            else:
                return False
        elif carType==2:
            if self.medium>=1:
                self.medium-=1
                return True
            else:
                return False
        else:
            if self.big>=1:
                self.big-=1
                return True
            else:
                return False

25、Leetcode 290:单词规律

题目描述
在这里插入图片描述

解题思路

  • 使用两个哈希表
    word2char:存储当前词key对应的字母value
    char2word:存储当前字母key对应的单词value
  • 那么判断其为false的就有两个条件
    1、当前词已经出现在word2char中了,但对应的char并不是当前的char
    2、当前char已经出现在char2word里了,但对应的word不是当前的word
  • 使用zip(pattern,word_list)进行打包遍历

代码实现

class Solution:
    def wordPattern(self, pattern: str, s: str) -> bool:
        word2chr={
   }
        chr2word={
   }
        #如果长度不相等,直接返回错
        word_list=s.split()
        if len(pattern)!=len(word_list):
            return False
        for char,word in zip(pattern,word_list):
            #如果词在词典中出现,但对应的字母和word2chr的不同
            #如果字母在字典中出现,但对应的词和chr2word存储的不同
            if (word in word2chr and word2chr[word] !=char) or (char in chr2word and chr2word[char]!=word):
                return False
            word2chr[word]=char
            chr2word[char]=word
        return True

26、Leetcode 6:Z字形变换

题目描述
在这里插入图片描述

解题思路
把这道题想得简单些,加入输入的numsRows有三行,那么添加字符串中的顺序应该是012|1|012|1
也就是说只要定义一个变量去存储方向状态即可

  • i==0时,flag为+1
  • 达到i==row-1后,flag为-1

代码实现

class Solution:
    def convert(self, s: str, numRows: int) -> str:
        if numRows < 2: return s
        res = ["" for _ in range(numRows)]
        i, flag = 0, -1
        for c in s:
            res[i] += c
            if i == 0 or i == numRows - 1: flag = -flag
            i += flag
        return "".join(res)

作者:jyd
链接:https://leetcode-cn.com/problems/zigzag-conversion/solution/zzi-xing-bian-huan-by-jyd/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

27、Leetcode 914:卡牌分组

题目描述
在这里插入图片描述

代码实现+步骤详解

class Solution:
    def hasGroupsSizeX(self, deck: List[int]) -> bool:
        #统计牌组中每一种牌出现的次数
        count_list=collections.Counter(deck)
        #统计长度
        n=len(deck)
        #对X进行遍历
        for x in range(2,n+1):
            #条件1:x是长度的约数
            if n%x==0:
                #条件2:x是每个牌出现次数的约数
                if all(v%x==0 for v in count_list.values()):
                    return True
        #如果遍历完所有x取值的可能都没达到条件,返回False
        return False

28、面试题 01.08 零矩阵:

题目描述
在这里插入图片描述

代码实现
第一次遍历,存储matrix位置为0的row和col,第二次遍历将row和
col为0的所有位置都变成0。

class Solution:
    def setZeroes(self, matrix: List[List[int]]) -> None:
        """
        Do not return anything, modify matrix in-place instead.
        """
        row=len(matrix)
        col=len(matrix[0])
        r,c=[0]*row,[0]*col
        for i in range(row):
            for j in range(col):
                if matrix[i][j]==0:
                    r[i]=1
                    c[j]=1
        for i in range(row):
            for j in range(col):
                if r[i]==1 or c[j]==1:
                    matrix[i][j]=0

29、Leetcode 150:逆波兰表达式求值

题目描述
在这里插入图片描述

解题思路
维护一个栈,遍历tokens

  • 如果token为数字,压栈
  • 当遇到了加减乘除符号,拿出栈的后两个进行计算后,将计算值压栈。
  • 返回stack中最后的值。

代码实现

class Solution:
    def evalRPN(self, tokens: List[str]) -> int:
        stack=[]
        for token in tokens:
            if token in ["+","-","/","*"]:
                b=stack.pop()
                c=stack.pop()
                if token=="*":
                    stack.append(b*c)
                elif token=="/":
                    stack.append(int(c/b))
                elif token=="+":
                    stack.append(b+c)
                else:
                    stack.append(c-b)
            else:
                stack.append(int(token))
        return int(stack[-1])

30、Leetcode 232:用栈实现队列

题目描述

在这里插入图片描述

解题思路
这种简单的题是真实存在的么…

代码实现

class MyQueue:

    def __init__(self):
        """
        Initialize your data structure here.
        """
        self.queue=[]


    def push(self, x: int) -> None:
        """
        Push element x to the back of queue.
        """
        self.queue.append(x)

    def pop(self) -> int:
        """
        Removes the element from in front of queue and returns that element.
        """
        return self.queue.pop(0)


    def peek(self) -> int:
        """
        Get the front element.
        """
        return self.queue[0]

    def empty(self) -> bool:
        """
        Returns whether the queue is empty.
        """
        return len(self.queue)==0

31、Leetcode 503:下一个更大元素II

题目描述

在这里插入图片描述

解题思路
做多了dp感觉这种题还是很简单的。主要说一下三个核心点:

  • 1、因为是循环数组,所以遍历n*2-1次,每个位置用i对n取模达到定位
  • 2、代码中,res列表存储的是每个位置的下一个最大值,stack中存储的是nums中每个的下标。
  • 3、对于当前nums[i]的值来说,遍历stack中其他的下标,如果stack中其他下标对应的值小于了nums[i],那么先要将res对应的位置添加nums[i],说明这些位置的下一个最大值就是nums[i],然后再把nums[i]压栈去寻找nums[i]的下一个最大元素。

代码实现

class Solution:
    def nextGreaterElements(self, nums: List[int]) -> List[int]:
        n=len(nums)
        #维护一个列表储存每个下标对应的下一个最大值
        res=[-1]*n
        #建立一个栈,存储的是下标
        stack=[]
        #因为是循环数组,遍历2n次
        for i in range(n*2-1):
            #只要栈中的元素比当前元素小,就pop
            while stack and nums[stack[-1]]<nums[i%n]:
                res[stack.pop()]=nums[i%n]
            stack.append(i%n)
        return res

32、Leetcode 131:分割回文串

题目描述
在这里插入图片描述

解题思路
这道题分为递归和dp两个部分
1、dp部分::判断
判断i到j是否为回文串,如果当前i和j的位置相等,且i+1到j-1的位置也是回文串,那么 d p [ i ] [ j ] dp[i][j] dp[i][j]是回文串。
2、递归部分::遍历
对于当前位置的i,遍历i后面的所有元素,判断i,j是否为回文串,如果是,将level中存储这部分的值,因为i,j已经是回文串了,那么要对j+1开始判断是j+1,n是否为回文串,当j到达n时,把这部分的值存储到res中。返回上一层,每返回一层还要讲该层的信息删除pop掉。

代码实现

class Solution:
    def partition(self, s: str) -> List[List[str]]:
        n=len(s)
        #DP部分,表示i-j部分的字符串是否为回文串的判断
        dp=[[True]*n for _ in range(n)]
        for i in range(n-1,-1,-1):
            for j in range(i+1,n):
                #i=j是回文串的条件是当前元素对应值相等且i+1:j-1也是回文串
                dp[i][j]=dp[i+1][j-1] and s[i]==s[j]
        #存储所有结果
        res=[]
        #递归过程中存储每个结果
        level=[]
        def dfs(i):
            #终止条件:
            if i==n:
                res.append(level[:])
                return
            #对于每个i进行分析
            for j in range(i,n):
                #如果当前是回文串
                if dp[i][j]:
                    level.append(s[i:j+1])
                    #对于j+1开始判断
                    dfs(j+1)
                    #删除前面的可能
                    level.pop()
        dfs(0)
        return res

33、Leetcode 92:反转链表II

题目描述

在这里插入图片描述

解题思路

  • 先将指针定位到反转区域的前一个元素,定义pre,cur,next
  • 对于需要反转的区域,每次不算的把pre cur next的位置翻转为pre next cur。pre是固定的

代码实现

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def reverseBetween(self, head: ListNode, left: int, right: int) -> ListNode:
        #设置头节点
        dummy=ListNode(-1)
        dummy.next=head
        #前节点
        pre=dummy
        #定位到left的前一个位置
        for i in range(left-1):
            pre=pre.next
        #定位到left的第一个位置
        cur=pre.next
        #遍历需要反转的区域
        for j in range(right-left):
            #找到前一个节点
            next=cur.next
            #将cur指向前一个的前一个
            cur.next=next.next
            #将next指向cur
            next.next=pre.next
            #将pre指向next
            pre.next=next
        return dummy.next

第二章 二叉树/N叉树

1、Leetcode 94:二叉树的中序遍历

题目描述:
在这里插入图片描述

使用递归的思想
使用递归的思想即为对于每个根节点都按照左根右的方式进行遍历,递归的思路即为先对根节点的左子节点进行递归,然后打印或添加,然后再对根节点的右子节点进行递归。如果对于当前递归层的节点来说,它不是root,则返回上一层递归操作。

代码实现

# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def inorderTraversal(self, root: TreeNode) -> List[int]:
        res=[]
        def dfs(root):
            if not root:
                return
            dfs(root.left)
            res.append(root.val)
            dfs(root.right)
        dfs(root)
        return res

颜色标记法
使用stack的思想,先进后出。定义新的节点为白色,已经遍历过的节点为灰色,如果第一次看到的节点是白色,就要把当前节点的按照右,中,左的顺序依次入栈。同时还要不算的出栈,出栈的顺序即为左、中、右。对于每一次节点的进栈,它本身的节点已经被看过了,将其变成灰色标记存入栈中,即下次出栈出到这个节点时,它本身就是灰色,不需要处理,直接出栈即可。而它的左子节点和右子节点还没有被看过,需要先进栈再出栈才算被看过,所以标记为白色。

代码实现:

# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def inorderTraversal(self, root: TreeNode) -> List[int]:
        res=[]
        white,gray=0,1
        stack=[(white,root)]
        while stack:
            color,node=stack.pop()
            if node is None:
                continue
            if color==white:
                stack.append((white,node.right))
                stack.append((gray,node))
                stack.append((white,node.left))
            else:
                res.append(node.val)
        return res

维护一个栈迭代的思想

# 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 inorderTraversal(self, root: TreeNode) -> List[int]:
        if not root:
            return []
        res=[]
        stack=[root]
        while stack:
            while root.left:
                stack.append(root.left)
                root=root.left
            cur=stack.pop()
            res.append(cur.val)
            if cur.right:
                stack.append(cur.right)
                root=cur.right
        return res

2、Leetcode 144:二叉树的前序遍历

递归的思路

# 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 preorderTraversal(self, root: TreeNode) -> List[int]:
        
        res=[]
        def dfs(root):
            if root:
                res.append(root.val)
                dfs(root.left)
                dfs(root.right)
        dfs(root)
        return res

颜色标记法

# 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 preorderTraversal(self, root: TreeNode) -> List[int]:
        
        res=[]
        white,gray=0,1
        stack=[(white,root)]
        while stack:
            color,node=stack.pop()
            if node is None:
                continue
            if color==white:
                stack.append((white,node.right))
                stack.append((white,node.left))
                stack.append((gray,node))
            else:
                res.append(node.val)
        return res

迭代的方法维护一个栈

# 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 preorderTraversal(self, root: TreeNode) -> List[int]:
        if not root:
            return []
        res=[]
        stack=[]
        node=root
        while stack or node:
            while node:
                res.append(node.val)
                stack.append(node)
                node=node.left
            node=stack.pop()
            node=node.right
            
        return res

3、Leetcode 145:二叉树的后序遍历

使用递归的思想

# 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 postorderTraversal(self, root: TreeNode) -> List[int]:
        if not root:
            return []
        res=[]
        def dfs(root):
            if root:
                dfs(root.left)
                dfs(root.right)
                res.append(root.val)
        dfs(root)
        return res

使用颜色标记法

# 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 postorderTraversal(self, root: TreeNode) -> List[int]:
        if not root:
            return []
        white, gray=0,1
        stack=[(white,root)]
        res=[]
        while stack:
            color , node =stack.pop()
            if not node:
                continue
            if color==white:
                stack.append((gray,node))
                stack.append((white,node.right))
                stack.append((white,node.left))
            else:
                res.append(node.val)
        return res

使用迭代的思想
实现左右根的思路感觉很难,所以将前序遍历中的根左右,变为根右左再逆序就得到了左右根。

# 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 postorderTraversal(self, root: TreeNode) -> List[int]:
        res,stack=[],[]
        node=root
        while node or stack:
            while node:
                res.append(node.val)
                stack.append(node)
                node=node.right
            cur=stack.pop()
            node=cur.left
            
        return res[::-1]

4、N叉树的后续遍历

使用递归的思想
对于N叉树的后续遍历其实与二叉树差不多,只不过对于每个节点,需

  • 12
    点赞
  • 158
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 这道是一道字符串处理。给定一个字符串 s,它的所有的字符都是小写的英文字母。要求把这个字符串变成一个按照字典序排序的字符串,并且要求在变换过程中只能在原来的字符串中交换两个相邻的字符。 解思路: - 从前往后扫描字符串 s,找到第一个不满足字典序的字符,记为字符 x。 - 从 x 往后扫描,找到最后一个比 x 大的字符 y,将 x 与 y 交换。 - 将 x 后面的字符串倒序排列,这样就得到了字典序更大的字符串。 下面是 Java 代码的实现: ``` class Solution { public String nextPermutation(String s) { char[] chars = s.toCharArray(); // 从后往前找到第一个不满足字典序的字符 x int i = chars.length - 2; while (i >= 0 && chars[i] >= chars[i + 1]) { i--; } // 如果 i < 0,说明原来的字符串已经是字典序最大的字符串,直接返回倒序排列的字符串 if (i < 0) { reverse(chars, 0, chars.length - 1); return new String(chars); } // 从 x 往后扫描,找到最后一个比 x 大的字符 y int j = chars.length - 1; while (j > i && chars[j] <= chars[i]) { j--; } // 将 x 与 y 交换 swap(chars, i ### 回答2: 题目LeetCode第38:报数 题目描述: 给定一个正整数n,输出报数序列前n个数。 报数规则:从1开始报数,数到3的倍数时报Fizz,数到5的倍数时报Buzz,数到同时是3和5的倍数时报FizzBuzz,其他情况下则直接报数。 解思路: 使用循环遍历1到n的所有数字,按照报数规则进行判断并输出。 具体步骤如下: 1. 创建一个StringBuilder对象res,用于存储报数序列。 2. 使用for循环从1遍历到n。 3. 判断当前数字是否同时是3和5的倍数,如果是,则将"FizzBuzz"添加到res中。 4. 判断当前数字是否是3的倍数,如果是,则将"Fizz"添加到res中。 5. 判断当前数字是否是5的倍数,如果是,则将"Buzz"添加到res中。 6. 如果以上条件都不满足,则将当前数字转换为字符串并添加到res中。 7. 循环结束后,将res转换为字符串并返回。 Java代码如下: ```java public String countAndSay(int n) { StringBuilder res = new StringBuilder(); for (int i = 1; i <= n; i++) { if (i % 3 == 0 && i % 5 == 0) { res.append("FizzBuzz"); } else if (i % 3 == 0) { res.append("Fizz"); } else if (i % 5 == 0) { res.append("Buzz"); } else { res.append(Integer.toString(i)); } } return res.toString(); } ``` 以上代码可以将1到n的报数序列输出,并按照题目要求进行相应转换。 ### 回答3: 题目要求是根据给定的正整数 n,返回一个字符串,该字符串包含从 1 到 n 的所有数字对应的字符串,并且满足以下条件: 1. 如果数字能被 3 整除,则使用字母 "Fizz" 替代该数字。 2. 如果数字能被 5 整除,则使用字母 "Buzz" 替代该数字。 3. 如果数字能同时被 3 和 5 整除,则使用字母 "FizzBuzz" 替代该数字。 解思路: 利用循环遍历从 1 到 n 的所有数字,使用条件语句判断每个数字是否满足以上三个条件,然后根据条件替换数字并存入结果字符串中,最后返回结果。 Java代码如下: ```java class Solution { public String fizzBuzz(int n) { StringBuilder result = new StringBuilder(); for (int i = 1; i <= n; i++) { if (i % 3 == 0 && i % 5 == 0) { result.append("FizzBuzz"); } else if (i % 3 == 0) { result.append("Fizz"); } else if (i % 5 == 0) { result.append("Buzz"); } else { result.append(i); } if (i != n) { result.append(" "); } } return result.toString(); } } ``` 这段代码使用StringBuilder来构建结果字符串,判断每个数字是否满足条件,并根据条件拼接对应的字符串,每个数字之间用空格隔开。最后将StringBuilder转换成String并返回。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值