leetcode刷题总结(三)

2019/8/11:求众数和二叉搜索树的最近公共祖先

求众数

https://leetcode-cn.com/problems/majority-element/ 题目地址

题目就不用多说了,可以点击上面的链接去看,其实像这种统计类的题会有很多api提供,但就是因为很多的函数所以才忽略了最初应该怎么写吧,当我拿到这个题目的时候,刚开始并没有想到怎么写,然后大概看了下题解,再自己写了一遍:

两种方案,第一种是利用字典键和值的关系:

class Solution:
    def majorityElement(self, nums: List[int]) -> int:
        leng = len(nums)
        if leng == 1:
            return nums[0]
        dic = {}
        for i in nums:
            if i in dic:
                dic[i] += 1
                if dic[i] >= leng / 2:
                    return i
            else:
                dic[i] = 1

第二种方案是以如果匹配到当前非选择的那个数就减一,对了就加一,如果为0就换数,最终留下来的那个数一定是众数(在考虑给定数组一定是有众数的情况下):

class Solution:
    def majorityElement(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        cnt, ret = 0, 0
        for num in nums:
            if cnt == 0:
                ret = num
            if num != ret:
                cnt -= 1
            else:
                cnt += 1
        return ret

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

百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/lowest-common-ancestor-of-a-binary-search-tree

这题看起来就是相当于考原理,而二叉搜索树(BST)的性质:

节点 N N 左子树上的所有节点的值都小于等于节点 N N 的值
节点 N N 右子树上的所有节点的值都大于等于节点 N N 的值
左子树和右子树也都是 B S T BST

可以直接写出结果:

class Solution:
    def lowestCommonAncestor(self, root, p, q):
        """
        :type root: TreeNode
        :type p: TreeNode
        :type q: TreeNode
        :rtype: TreeNode
        """
        # Value of current node or parent node.
        parent_val = root.val

        # Value of p
        p_val = p.val

        # Value of q
        q_val = q.val

        # If both p and q are greater than parent
        if p_val > parent_val and q_val > parent_val:    
            return self.lowestCommonAncestor(root.right, p, q)
        # If both p and q are lesser than parent
        elif p_val < parent_val and q_val < parent_val:    
            return self.lowestCommonAncestor(root.left, p, q)
        # We have found the split point, i.e. the LCA node.
        else:
            return root

2019/8/12:只出现一次的数字

class Solution(object):
    def singleNumber(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        return 2 * sum(set(nums)) - sum(nums)

2019/8/13:2的幂

题目:
https://leetcode-cn.com/problems/power-of-two/

说明:

这题想到了用二进制来解,因为在之前的求众数中有看到使用二进制解决的,还有刚刷了只出现一次的数字,大概清楚2的倍数一定有一个规律,但刚开始还是想用迭代做一遍,所以代码为:

class Solution:
    def isPowerOfTwo(self, n: int) -> bool:
        if n<=0: 
        	return False
        while n>1:
            if n%2 == 0:
                n //= 2
            else:
                return False
        return True

另外看了几篇博文,对于位运算又了解了一些:
在这里插入图片描述
https://www.cnblogs.com/Coufusion/p/7699614.html

然后因为对于2的倍数来讲,一般都是最高位为1,其余位就为0,那么我们也可以用上述中的与运算,那么两种方案如下:

class Solution:
    def isPowerOfTwo(self, n: int) -> bool:
        if n < 1:
            return False
        i = 1
        while i <= n:
            if i == n:
                return True
            i <<= 1
        return False

class Solution:
    def isPowerOfTwo(self, n: int) -> bool:
        return n > 0 and not n & (n - 1)

2019/8/18:二叉树中的最大路径和

题目链接:https://leetcode-cn.com/problems/binary-tree-maximum-path-sum/

刚开始看这题有点没看懂,然后想了想是困难题,算了,看下答案吧,然后确实官方的题解不是很好理解,反而影响了我的思路,然后看了下讨论,发现了一个非常好理解的思路,然后就懂了:

import sys

class Solution:
    
    result = -sys.maxsize-1
    
    def maxPathSum(self, root):
        """
        :type root: TreeNode
        :rtype: int
        """
        self.maxValue(root)
        return self.result
    
    """
    最大路径和:根据当前节点的角色,路径和可分为两种情况:
    一:以当前节点为根节点
    1.只有当前节点
    2.当前节点+左子树
    3.当前节点+右子书
    4.当前节点+左右子树    
    这四种情况的最大值即为以当前节点为根的最大路径和
    此最大值要和已经保存的最大值比较,得到整个树的最大路径值
    
    二:当前节点作为父节点的一个子节点
    和父节点连接的话则需取【单端的最大值】
    1.只有当前节点
    2.当前节点+左子树
    3.当前节点+右子书
    这三种情况的最大值    
    """
    def maxValue(self,root):
        if root == None:            
            return 0
        
        leftValue = self.maxValue(root.left)
        rightValue = self.maxValue(root.right)
        
        value1 = root.val
        value2 = root.val + leftValue
        value3 = root.val + rightValue
        value4 = root.val + rightValue + leftValue
        
        #以此节点为根节点的最大值
        maxValue = max([value1,value2,value3,value4])
        
        #当前遍历树的最大值
        self.result = max(maxValue, self.result)
        
        #要和父节点关联,则需要取去除情况4的最大值
        return max([value1,value2,value3])

2019/8/19:二叉搜索树中第K小的元素

题目链接:https://leetcode-cn.com/problems/kth-smallest-element-in-a-bst

解答:

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution(object):
    def kthSmallest(self, root, k):
	"""
	:type root: TreeNode
	:type k: int
	:rtype: int
	"""
	res = []
	self.visitNode(root, res)
	return res[k - 1]

    # 中序遍历
    def visitNode(self, root, res):
	if root is None:
	    return
	self.visitNode(root.left, res)
	res.append(root.val)
	self.visitNode(root.right, res)

2019/8/20:二叉树的最近公共祖先

题目链接: https://leetcode-cn.com/problems/lowest-common-ancestor-of-a-binary-tree/

这里通过一篇博文学习了一下DFS回溯的一些用法,之前确实没有触及过——手把手教你中的回溯算法——多一点套路

然后我们来看这题,同样可以用回溯的方式,代码为:

class Solution:
    def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
        self.res = None
        self.dfs(root, p, q)
        return self.res
    def dfs(self, root, p, q):
        if not root: return 0
        left = self.dfs(root.left, p, q)
        right = self.dfs(root.right,p ,q)
        mid = root == p or root == q
        if left + right + mid > 1: self.res = root
        return left or right or mid

以及看题解发现的一个很简单的思路:

class Solution:
    def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
        if root in (None ,p,q):
            return root 
        L = self.lowestCommonAncestor(root.left,p,q)
        R =self.lowestCommonAncestor(root.right,p,q)
        return R if None==L else L if None==R else root

左子树或自己含p 就返回p,右子树或自己含q就返回q,左右子树返回一p一q则返回自己,如果某子树返回了答案(另一子树必然返回None),则返回答案,剩下就是两个子树都返回空,则返回空。 经过逻辑化简:

先分析自己,自己是p,q,None中的一者,自然返回自己。
然后分析左右子树的返回值,如果其中一个是None,则返回另一个,作为传递,无论是传递最终的答案,还是传递p和q。
如果左右子树返回p和q,当然返回root。 Python中的None即C/C++/Java 中的Null/null

2019/8/23:Nim游戏

你和你的朋友,两个人一起玩 Nim 游戏:桌子上有一堆石头,每次你们轮流拿掉 1 - 3 块石头。 拿掉最后一块石头的人就是获胜者。你作为先手。

你们是聪明人,每一步都是最优解。 编写一个函数,来判断你是否可以在给定石头数量的情况下赢得游戏。

示例:

输入: 4
输出: false
解释: 如果堆中有 4 块石头,那么你永远不会赢得比赛;
因为无论你拿走 1 块、2 块 还是 3 块石头,最后一块石头总是会被你的朋友拿走。

说明:这题目套路颇深,我记得去年看过腾讯14年的笔试题,有一道选择题和这个类似,然后选错了看了答案感觉有点逗,现在记得了,代码为:

class Solution:
    def canWinNim(self, n: int) -> bool:
        if n % 4 == 0:
            return False
        else:
            return True

2019/8/24:LRU缓存机制

运用你所掌握的数据结构,设计和实现一个 LRU (最近最少使用) 缓存机制。它应该支持以下操作: 获取数据 get 和 写入数据 put 。

获取数据 get(key) - 如果密钥 (key) 存在于缓存中,则获取密钥的值(总是正数),否则返回 -1。
写入数据 put(key, value) - 如果密钥不存在,则写入其数据值。当缓存容量达到上限时,它应该在写入新数据之前删除最近最少使用的数据值,从而为新的数据值留出空间。

进阶:

你是否可以在 O(1) 时间复杂度内完成这两种操作?

示例:

LRUCache cache = new LRUCache( 2 /* 缓存容量 */ );

cache.put(1, 1);
cache.put(2, 2);
cache.get(1); // 返回 1
cache.put(3, 3); // 该操作会使得密钥 2 作废
cache.get(2); // 返回 -1 (未找到)
cache.put(4, 4); // 该操作会使得密钥 1 作废
cache.get(1); // 返回 -1 (未找到)
cache.get(3); // 返回 3
cache.get(4); // 返回 4

链接:https://leetcode-cn.com/problems/lru-cache

HashMap实现原理分析及简单实现一个HashMap

面试必问—HashMap原理分析

这几天看一下哈希表和双向链表,概念有一些忘记。另外我也是今天才知道有一个有序字典:

from collections import OrderedDict
class LRUCache(OrderedDict):

    def __init__(self, capacity):
        """
        :type capacity: int
        """
        self.capacity = capacity

    def get(self, key):
        """
        :type key: int
        :rtype: int
        """
        if key not in self:
            return - 1
        
        self.move_to_end(key)
        return self[key]

    def put(self, key, value):
        """
        :type key: int
        :type value: int
        :rtype: void
        """
        if key in self:
            self.move_to_end(key)
        self[key] = value
        if len(self) > self.capacity:
            self.popitem(last = False)

2019/8/29:

当时第一次做没有看到边界,然后感觉很简单,版本如下:

class Solution:
    def findMedianSortedArrays(self, nums1, nums2):
        """
        :type nums1: List[int]
        :type nums2: List[int]
        :rtype: float
        """
        nums1.extend(nums2)  # 合并
        add = nums1
        if not add:
            return None
        add.sort()  # 改变原来的列表
        if len(add) % 2:   # 计数不是循环。
            return add[len(add)//2] / 1.0
        else:
            return (add[len(add)//2] + add[(len(add)//2)-1]) / 2.0

不太懂log(m+n)到底是多少复杂度,看说是二分法,然而不太会,先mark一下官方解答:

def median(A, B):
    m, n = len(A), len(B)
    if m > n:
        A, B, m, n = B, A, n, m
    if n == 0:
        raise ValueError

    imin, imax, half_len = 0, m, (m + n + 1) / 2
    while imin <= imax:
        i = (imin + imax) / 2
        j = half_len - i
        if i < m and B[j-1] > A[i]:
            # i is too small, must increase it
            imin = i + 1
        elif i > 0 and A[i-1] > B[j]:
            # i is too big, must decrease it
            imax = i - 1
        else:
            # i is perfect

            if i == 0: max_of_left = B[j-1]
            elif j == 0: max_of_left = A[i-1]
            else: max_of_left = max(A[i-1], B[j-1])

            if (m + n) % 2 == 1:
                return max_of_left

            if i == m: min_of_right = B[j]
            elif j == n: min_of_right = A[i]
            else: min_of_right = min(A[i], B[j])

            return (max_of_left + min_of_right) / 2.0

2019/8/30:删除排序数组中的重复项

class Solution(object):
    def removeDuplicates(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        if not len(nums):
            return len(nums)
        tmp = nums[0]
        index = 0
        for i, v in enumerate(nums):
            if tmp == v:
                continue
            else:
                nums[index] = tmp
                tmp = v
                index += 1
        nums[index] = tmp
        return len(nums[:index+1])

2019/9/1:最大子序和

class Solution(object):
    def maxSubArray(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        for i in range(1, len(nums)):
            # 当前索引i永远存储0~i的最大和
            nums[i] = max(nums[i], nums[i] + nums[i - 1])
        # 返回每个索引最大和的最大值
        return max(nums)

猜你喜欢

转载自blog.csdn.net/submarineas/article/details/99187537