LeetCode: 一系列简单题

简单题不会再开单独的博客了,统一在这里做笔记。

258. 各位相加

给定一个非负整数 num,反复将各个位上的数字相加,直到结果为一位数。

示例:

输入: 38
输出: 2
解释: 各位相加的过程为:3 + 8 = 11, 1 + 1 = 2。 由于 2 是一位数,所以返回 2。

class Solution:
    def addDigits(self, num: int) -> int:
        n = num
        while n >= 10:
            res = 0
            while n:
                res += n % 10
                n = n // 10
            n = res
            if res < 10:
                return res
        return n

O(1)的解法
在这里插入图片描述

226.翻转二叉树

翻转一棵二叉树。

示例:

输入:
4
/ \
2 7
/ \ / \
1 3 6 9
输出:

4
/ \
7 2
/ \ / \
9 6 3 1

核心思路是交换所有节点的左右节点

  • 写法1
class Solution:
    def invertTree(self, root: TreeNode) -> TreeNode:
        def walk(p):
            if p:
                p.left, p.right = p.right, p.left
                walk(p.left)
                walk(p.right)
        walk(root)
        return root     
  • 写法2
class Solution:
    def invertTree(self, root: TreeNode) -> TreeNode:
        if not root:
            return None
        root.left, root.right = self.invertTree(root.right), self.invertTree(root.left)
        return root

237. 删除链表的节点

乍一看题目很简单,不过有点小心思在里面,没有给Head。
方法很简单,
在这里插入图片描述

290. 单词规律

这题和 205.同构字符串本质上是一样的。
给定一种规律 pattern 和一个字符串 str ,判断 str 是否遵循相同的规律。

这里的 遵循 指完全匹配,例如, pattern 里的每个字母和字符串 str 中的每个非空单词之间存在着双向连接的对应规律。

示例1:

输入: pattern = “abba”, str = “dog cat cat dog”
输出: true

  • 解法一,代码写的有点丑,应该写一个函数来处理,不需要重复两次写。
class Solution:
    def wordPattern(self, pattern: str, str: str) -> bool:
        recoder = {}
        flag = False
        max_len = len(pattern)
        if max_len != len(str.split(' ')):
            print(1)
            return False
        for word, p in zip(str.split(' '), pattern):
            if p not in recoder:
                recoder[p] = word
            else:
                if recoder[p] != word:
                    return flag
        flag = True
        flag2 = False
        recoder = {}
        for word, p in zip(str.split(' '), pattern):
            if word not in recoder:
                recoder[word] = p
            else:
                if recoder[word] != p:
                    return flag2
        flag2 = True
        if flag2 and flag:
            return True
        else:
            return False
  • 解法二, 将两个字符串按照相同的映射规则,换到另一个字符串上。说法语的人和中国人,如何交流,让他们都说英语。

235. 二叉搜索树的最近公共祖先

二叉搜索树定义:
若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值; 它的左、右子树也分别为二叉搜索树(又称,二叉排序树,二叉查找树)。插入,删除,搜索操作时间复杂度均为树高,O(logN)。

  • 节点 NN 左子树上的所有节点的值都小于等于节点 NN 的值
  • 节点 NN 右子树上的所有节点的值都大于等于节点 NN 的值
  • 左子树和右子树也都是 BST
class Solution:
    def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
        def walk(root, p, q):
            if not root:
                return
            if p.val > q.val:
                p, q = q, p 
            if p.val < root.val and q.val > root.val:
                return root
            if p.val == root.val or q.val == root.val:
                return root
            if p.val > root.val and q.val > root.val:
                return walk(root.right, p, q)
            if p.val < root.val and q.val < root.val:
                return walk(root.left, p, q)
        return walk(root, p, q)

更简洁的写法

class Solution:
    def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
        if not root:
            return None

        # 由于二叉搜索树排好序,则按条件左右循环游走
        while root:
            if p.val < root.val > q.val:
                root = root.left
            elif p.val > root.val < q.val:
                root = root.right
            else:
                return root

257. 二叉树的所有路径

给定一个二叉树,返回所有从根节点到叶子节点的路径。

说明: 叶子节点是指没有子节点的节点。

示例:

输入:

1
/ \
2 3
\
5

输出: [“1->2->5”, “1->3”]

解释: 所有根节点到叶子节点的路径为: 1->2->5, 1->3

这道题我还是想了很久的,想错方向了,没做出来。就去看了题解,看了思路一下就知道我的问题在哪了。
首先,我想的是,深度遍历,但是具体又该如何把路径存下来呢。其实这个问题很好解决,但我没想到,就是多设置一个形参,按照由顶到底的顺序保存走过的路径就行了。到叶子节点就把路径添加到全局变量中去。

  • 递归写法
from collections import deque
class Solution:
    def binaryTreePaths(self, root: TreeNode) -> List[str]:
        self.paths = []
        def walk(root, path):
            if not root.right and not root.left:
                self.paths.append(path+str(root.val))
                return
            if root.left or root.right:
                path += str(root.val)+'->'
            if root.left:
                walk(root.left, path)
            if root.right:
                walk(root.right, path)
        if not root:
            return []
        walk(root, '')
        return self.paths   

关键就是这个path形参记录了根节点到父节点的路径

  • 迭代写法,用队列或者栈都OK,关键是path传递的信息。
from collections import deque
class Solution:
    def binaryTreePaths(self, root: TreeNode) -> List[str]:
        if not root:
            return []
        paths = []
        queue = deque([(root, str(root.val))])
        while len(queue) != 0:
            node, path = queue.popleft()
            if node.right == None and node.left == None:
                paths.append(path)
            if node.left:
                pathl = path + '->' + str(node.left.val)
                queue.append((node.left, pathl))
            if node.right:
                pathr = path + '->' + str(node.right.val)
                queue.append((node.right, pathr))
        return paths

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

437. 路径总和 |||

给定一个二叉树,它的每个结点都存放着一个整数值。

找出路径和等于给定数值的路径总数。

路径不需要从根节点开始,也不需要在叶子节点结束,但是路径方向必须是向下的(只能从父节点到子节点)。

二叉树不超过1000个节点,且节点数值范围是 [-1000000,1000000] 的整数。

思路:

  • 用数组记录走过路径的前缀和,(又是前缀和,之前有道动态规划的题目用到了前缀和)。如果最后一个数字和前面的数的差就是sum,那就找到一条路径了。
  • 回溯遍历,先序遍历。
# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def pathSum(self, root: TreeNode, sum: int) -> int:
        path_sum = [0]
        cnt = 0
        if not root:
            return cnt
        def walk(p):
            nonlocal path_sum, cnt
            if not p:
                return
            pre_sum = path_sum[-1]
            path_sum.append(p.val+pre_sum)
            # print(path_sum)
            for k in range(len(path_sum)-1):
                if path_sum[k] + sum == path_sum[-1]:
                    cnt += 1
            if p.left:
                walk(p.left)
                path_sum.pop()
            if p.right:
                walk(p.right)
                path_sum.pop()
        walk(root)
        return cnt

459. 重复的子字符串

给定一个非空的字符串,判断它是否可以由它的一个子串重复多次构成。给定的字符串只含有小写英文字母,并且长度不超过10000。

  • 思路: 维护一个repeat字符串,记录目前最大的不满足条件的从第一个字符到当前遍历的字符之间的所有字符串。
class Solution:
    def repeatedSubstringPattern(self, s: str) -> bool:
        repeat = s[0]
        for i in range(1, len(s)):
            k = i
            while s[k:k+len(repeat)] == repeat:
                if k+len(repeat) == len(s):
                    return True
                k += len(repeat)
                if k+len(repeat) > len(s):
                    print(1)
                    break
            repeat = repeat+s[i]
            if len(repeat) > 0.5 * len(s):
                return False
        return False

162. 寻找峰值

峰值元素是指其值大于左右相邻值的元素。
给定一个输入数组 nums,其中 nums[i] ≠ nums[i+1],找到峰值元素并返回其索引。数组可能包含多个峰值,在这种情况下,返回任何一个峰值所在位置即可
算法要求在logn时间内求解。二分没跑了
开始思考条件:当一个位置大于后一个位置,说明这个位置处在下降区域上

class Solution:
    def findPeakElement(self, nums):
        n = len(nums)
        nn = sorted(nums)
        i = 0
        j = n-1
        mid = 0
        if n == 1:
            return 0
        if n > 1:
            if nums[0] > nums[1]:
                return 0
            elif nums[-1] > nums[-2]:
                return n - 1
        while i < j:
            mid = (i + j) >> 1
            if nums[mid-1] < nums[mid] > nums[mid+1]:
                break
            elif nums[mid] > nums[mid+1]:  # 处于下降位置
                j = mid
            else:
                i = mid +1
        return mid
注意,这里的条件,最好用mid位置的值是否大于mid+1, 如果用mid-1和mid的比较,也许会陷入死循环。

650. 只有两个键的键盘

本质是素数分解,分解的数子全部都是素数,然后这些数字的和就是答案。原因是当p,q都大于等于2时, q + p是小于p * q的。

class Solution:
    def minSteps(self, n: int) -> int:
        d = 2 # 质数从小到大开始加
        ans = 0
        while n > 1:  
            while n % d ==0: # 用while, 把d的因子全部去掉,比如当d为4的时候,
             #4不会是n的因子,因为d为2的时候,已经去除了2的倍数的因子
                ans += d
                n //= d
            d += 1
        return ans

11. 盛最多水的容器

题目是给一个list,装了值代表高度。哪两个index位置的高度能组成的面积最大

  • 双指针思想。i指向第一个位置,j指向最后一个位置。
  • 计算一次面积,同时如果第i的值比第j的位置的值小,则i+1;否则j-1
class Solution:
    def maxArea(self, height: List[int]) -> int:
        i, j = 0, len(height) - 1
        res = 0
        while i < j:
            temp = (j-i) * min(height[i], height[j])
            res =  max(temp, res)
            if height[i] > height[j]:
                j -= 1
            else:
                i += 1
        return res
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值