leetcode刷题 209~

题目209题

长度最小的子数组

给定一个含有 n 个正整数的数组和一个正整数 s ,找出该数组中满足其和 ≥ s 的长度最小的 连续 子数组,并返回其长度。如果不存在符合条件的子数组,返回 0。

示例:

输入:s = 7, nums = [2,3,1,2,4,3]
输出:2
解释:子数组 [4,3] 是该条件下的长度最小的子数组。

思路

双指针法

实现

class Solution:
    def minSubArrayLen(self, s: int, nums: List[int]) -> int:
        if not nums:
            return 0
        left,right = 0,0
        result = len(nums) + 1
        temp = 0
        while right < len(nums):
            temp += nums[right]
            while temp >= s:
                result = min(result, right-left+1)
                temp -= nums[left]
                left += 1
            right += 1
        return 0 if result == len(nums) + 1 else result

题目210题

课程表II

现在你总共有 n 门课需要选,记为 0 到 n-1。

在选修某些课程之前需要一些先修课程。 例如,想要学习课程 0 ,你需要先完成课程 1 ,我们用一个匹配来表示他们: [0,1]

给定课程总量以及它们的先决条件,返回你为了学完所有课程所安排的学习顺序。

可能会有多个正确的顺序,你只要返回一种就可以了。如果不可能完成所有课程,返回一个空数组。

思路

拓扑排序!

实现

class Solution:
    def findOrder(self, numCourses: int, prerequisites: List[List[int]]) -> List[int]:
        reverse_post = list()

        edges = collections.defaultdict(list)
        length = len(prerequisites)
        flag = True

        for info in prerequisites:
            edges[info[0]].append(info[1])
        visited = [False for _ in range(numCourses)]
        on_stack = [False for _ in range(numCourses)]

        def dfs(course):
            nonlocal flag
            print(reverse_post)
            on_stack[course] = True
            visited[course] = True
            for pre in edges[course]:
                if not on_stack[pre]:
                    if not visited[pre]:
                        dfs(pre)
                else:
                    flag = False
                    return
            on_stack[course] = False
            reverse_post.append(course)

        for i in range(numCourses):
            if not flag:
                return []
            if not visited[i] and flag:
                dfs(i)
        if flag:
            return reverse_post
        else:
            return []

题目211题

添加与搜索单词

请你设计一个数据结构,支持 添加新单词 和 查找字符串是否与任何先前添加的字符串匹配 。

实现词典类 WordDictionary :

WordDictionary() 初始化词典对象
void addWord(word) 将 word 添加到数据结构中,之后可以对它进行匹配
bool search(word) 如果数据结构中存在字符串与 word 匹配,则返回 true ;否则,返回  false 。word 中可能包含一些 '.' ,每个 . 都可以表示任何一个字母。

思路

字典的初始化与添加操作与前缀树相同,但搜索操作可以利用深度优先遍历完成

实现

class Node:
    def __init__(self, val=None ,end = False):
        self.val = val
        self.is_end = end
        self.next = {}


class WordDictionary:

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


    def addWord(self, word: str) -> None:
        """
        Adds a word into the data structure.
        """
        node = self.root
        for i in word:
            if i not in node.next:
                node.next[i] = Node(i)
            node = node.next[i]
        node.is_end = True


    def search(self, word: str) -> bool:
        """
        Returns if the word is in the data structure. A word could contain the dot character '.' to represent any one letter.
        """
        return self.__search(self.root, word)

    def __search(self, pre, word):
        node = pre
        if not word:
            if node.is_end:
                return True
            return False
        if word[0] == ".":
            temp = node.next.keys()
            for t in temp:
                if self.__search(node.next[t],word[1:]):
                    return True
        elif word[0] in node.next.keys():
            return self.__search(node.next[word[0]],word[1:])
        return False

题目100题

打家劫舍II

你是一个专业的小偷,计划偷窃沿街的房屋,每间房内都藏有一定的现金。这个地方所有的房屋都围成一圈,这意味着第一个房屋和最后一个房屋是紧挨着的。同时,相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。

给定一个代表每个房屋存放金额的非负整数数组,计算你在不触动警报装置的情况下,能够偷窃到的最高金额。

思路

动态规划,与198题相比,环状排列意味着第一个房子和最后一个房子中只能选择一个偷窃,因此可以把此环状排列房间问题约化为两个单排排列房间子问题。

在不偷窃第一个房子的情况下(即 nums[1:]),最大金额是 p1
在不偷窃最后一个房子的情况下(即 nums[:n-1]),最大金额是 p2

max(p1,p2)则是环状排列的最大金额

实现

class Solution:
    def rob(self, nums: List[int]) -> int:
        return max(self.__rob(nums[:-1]),self.__rob(nums[1:])) if len(nums) != 1 else nums[0]

    def __rob(self, nums: List[int]) -> int:
        cur, pre = 0, 0
        for num in nums:
            cur, pre = max(pre + num, cur), cur
        return cur

题目215题

数组中的第k个最大元素

在未排序的数组中找到第 k 个最大的元素。请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。

思路

堆排序

实现

class Solution:
    def findKthLargest(self, nums: List[int], k: int) -> int:
        heapSize = len(nums)
        self.buildMaxHeap(nums, heapSize-1)
        cin = 0
        heapSize -= 1
        while cin < k-1:         
            cin +=1
            nums[0],nums[heapSize] = nums[heapSize], nums[0]
            heapSize -= 1
            self.sink(nums, 0, heapSize)
        return nums[0]

    def buildMaxHeap(self, nums, Size):
        k = int(Size/2)
        while k >= 0:
            self.sink(nums, k, Size)
            k -= 1

    def sink(self, nums, start, end):
        i, j = start, 2*start
        while j <= end:
            if j < end and nums[j] < nums[j+1]:
                j += 1
            if nums[i] < nums[j]:
                nums[i], nums[j] = nums[j], nums[i]
                i = j
                j = 2 *i
            else:
                break

题目216题

组合总和III

找出所有相加之和为 n 的 k 个数的组合。组合中只允许含有 1 - 9 的正整数,并且每种组合中不存在重复的数字。

说明:

所有数字都是正整数。
解集不能包含重复的组合。 

思路

深度优先遍历

实现

class Solution:
    def combinationSum3(self, k: int, n: int) -> List[List[int]]:
        result = []
        def com(k,n,index,temp):
            if n == 0 and k == 0:
                result.append(temp)
            if n >= index and k >0:
                for i in range(index,10):
                    com(k-1,n-i, i+1,temp+[i])
        com(k,n,1,[])
        return result

题目217题

存在重复元素

给定一个整数数组,判断是否存在重复元素。

如果任意一值在数组中出现至少两次,函数返回 true 。如果数组中每个元素都不相同,则返回 false 。

思路

将数组放入一个set中,若set的长度和list长度不同,则重复

实现

class Solution:
    def containsDuplicate(self, nums: List[int]) -> bool:
        return not len(nums) == len(set(nums))

题目219题

存在重复元素II

给定一个整数数组和一个整数 k,判断数组中是否存在两个不同的索引 i 和 j,使得 nums [i] = nums [j],并且 i 和 j 的差的 绝对值 至多为 k。

思路

实现

class Solution:
    def containsNearbyDuplicate(self, nums: List[int], k: int) -> bool:
        key = dict()
        for num in range(len(nums)):
            if nums[num] not in key.keys():
                key[nums[num]] = num
            else:
                if num - key[nums[num]] <=k:
                    return True
                key[nums[num]] = num
        return False

题目220题

存在重复的元素

在整数数组 nums 中,是否存在两个下标 i 和 j,使得 nums [i] 和 nums [j] 的差的绝对值小于等于 t ,且满足 i 和 j 的差的绝对值也小于等于 ķ 。

如果存在则返回 true,不存在返回 false。

思路

桶排序:桶排序是一种把元素分散到不同桶中的排序算法。接着把每个桶再独立地用不同的排序算法进行排序。

设计一些桶,让他们分别包含区间 ..., [0,t], [t+1, 2t+1], ......,[0,t],[t+1,2t+1],...。我们把桶来当做窗口,于是每次我们只需要检查 xx 所属的那个桶和相邻桶中的元素就可以了。

实现

class Solution:
    def containsNearbyAlmostDuplicate(self, nums: List[int], k: int, t: int) -> bool:
        key = dict()
        for i in range(len(nums)):
            id = self.__getid(nums[i], t)
            if id in key.keys():
                return True
            if (id -1) in key.keys() and abs(key[id-1]-nums[i])<=t:
                return True
            if (id +1) in key.keys() and abs(key[id+1]-nums[i])<=t:
                return True
            key[id] = nums[i]
            if len(key) > k:
                del_id = self.__getid(nums[i-k], t)
                del key[del_id]
        return False
            
        
    def __getid(self, num, t):
        return num//(t+1)

题目221题

最大正方形

在一个由 0 和 1 组成的二维矩阵内,找到只包含 1 的最大正方形,并返回其面积。

示例:

输入:

1 0 1 0 0
1 0 1 1 1
1 1 1 1 1
1 0 0 1 0

输出: 4

思路

动态规划:用 dp(i, j) 表示以(i,j) 为右下角,且只包含1的正方形的边长最大值。

dp(i,j)=min(dp(i1,j),dp(i1,j1),dp(i,j1))+1

实现

class Solution:
    def maximalSquare(self, matrix: List[List[str]]) -> int:
        if len(matrix) == 0 or len(matrix[0]) == 0:
            return 0
        
        maxSide = 0
        rows, columns = len(matrix), len(matrix[0])
        dp = [[0 for _ in range(columns)] for _ in range(rows)]
        for i in range(rows):
            for j in range(columns):
                if matrix[i][j] == '1':
                    if i == 0 or j == 0:
                        dp[i][j] = 1
                    else:
                        dp[i][j] = min(dp[i-1][j],dp[i-1][j-1],dp[i][j-1])+1
                    maxSide = max(maxSide, dp[i][j])
        return maxSide*maxSide

题目222题

完全二叉树的节点个数

给出一个完全二叉树,求出该树的节点个数。

思路

1. 递归

2.广度优先遍历

但前两种方法都没有利用到完全二叉树的特性

3.二分搜索

这个问题的实质是最后一层的叶子节点树量

实现

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

class Solution:
    def countNodes(self, root: TreeNode) -> int:
    return 1 + self.countNodes(root.right) + self.countNodes(root.left) if root else 0
2.
class Solution:
    def countNodes(self, root: TreeNode) -> int:
        if not root:
            return 0
        queue = collections.deque()
        queue.append(root)
        result = 0
        while queue:
            node = queue.popleft()
            result += 1
            if node.left:
                queue.append(node.left)
            if node.right:
                queue.append(node.right)
        return result
3.
class Solution:
    def conutlevel(self, node):
        level = 0
        while node.left:
            node = node.left
            level += 1         
        return level

    def exists(self, idx, level, node):
        left, right = 0, 2**level - 1
        for _ in range(level):
            mid = left + (right - left)//2
            if idx <= mid:
                node = node.left
                right = mid
            else:
                node = node.right
                left = mid + 1
        return node is not None

    def lastlevel(self, level, node):
        left, right = 0, 2**level - 1
        while left <= right:
            mid = left + (right - left)//2
            if self.exists(mid, level, node):
                left = mid + 1
            else:
                right = mid - 1
        return left

    def countNodes(self, root: TreeNode) -> int:
        if not root:
            return 0
        level = self.conutlevel(root)
        if level == 0:
            return 1
        last = self.lastlevel(level,root)
        return 2**level - 1 + last

题目223题

矩形面积

在二维平面上计算出两个由直线构成的矩形重叠后形成的总面积。

思路

有两种情况:有重叠和无重叠

计算时将两个矩形面积和减去重叠面积,当重叠部分的边为负数时,取0

实现

class Solution:
    def computeArea(self, A: int, B: int, C: int, D: int, E: int, F: int, G: int, H: int) -> int:
        x1 = max(A,E)
        y1 = max(B,F)
        x2 = min(C,G)
        y2 = min(D,H)
        cover = max(0,(x2-x1))* max(0,(y2-y1))
        total =  (C-A)*(D-B) +(G-E)*(H-F)
        return total - cover

题目225题

用队列实现栈

思路实现

class MyStack:

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


    def push(self, x: int) -> None:
        """
        Push element x onto stack.
        """
        self.stack.append(x)


    def pop(self) -> int:
        """
        Removes the element on top of the stack and returns that element.
        """
        return self.stack.pop()


    def top(self) -> int:
        """
        Get the top element.
        """
        return self.stack[-1]


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

题目227题

基本计算器

实现一个基本的计算器来计算一个简单的字符串表达式的值。

字符串表达式仅包含非负整数,+, - ,*/ 四种运算符和空格  。 整数除法仅保留整数部分。

思路

实现

class Solution:
    def calculate(self, s: str) -> int:
        stack = []
        num = "0123456789"
        op = "+"
        temp = 0
        idx = 0
        for i in range(len(s)):
            wait = s[i]
            if wait.isdigit():
                temp = temp*10 + int(wait)
            if wait in "+-*/" or i == len(s)-1:
                if op is "+":
                    stack.append(temp)
                elif op is "-":
                    stack.append(-temp)
                elif op is "*":
                    pre = stack.pop()
                    stack.append(pre*temp)
                elif op is "/":
                    pre = stack.pop()
                    stack.append(int(pre/temp))
                op = wait
                temp = 0
        return sum(stack)

题目228题

汇总区间

给定一个无重复元素的有序整数数组 nums 。

返回 恰好覆盖数组中所有数字 的 最小有序 区间范围列表。也就是说,nums 的每个元素都恰好被某个区间范围所覆盖,并且不存在属于某个范围但不属于 nums 的数字 x 。

列表中的每个区间范围 [a,b] 应该按如下格式输出:

"a->b" ,如果 a != b
"a" ,如果 a == b

思路

双指针

实现

class Solution:
    def summaryRanges(self, nums: List[int]) -> List[str]:
        if not nums:
            return []
        left,right = 0, 0
        temp = []
        result = []
        while left<=right and right != len(nums):
            if nums[right] == nums[left] or nums[right] == nums[right-1] + 1:
                temp.append(str(nums[right]))
                right += 1
            elif nums[right] > nums[right-1] + 1:
                if len(temp) > 1:
                    result.append(temp[0]+"->"+temp[-1])
                else:
                    result.append(temp[0])
                temp = []
                left = right
        if len(temp) > 1:
            result.append(temp[0]+"->"+temp[-1])
        else:
            result.append(temp[0])
        return result

题目229题

求众数II

给定一个大小为 n 的数组,找出其中所有出现超过 ⌊ n/3 ⌋ 次的元素。

进阶:尝试设计时间复杂度为 O(n)、空间复杂度为 O(1)的算法解决此问题。

思路

利用字典非常容易,但是无法满足空间复杂度为1。因此采用摩尔投票法。

摩尔投票法分为两个阶段:抵消阶段和计数阶段。

抵消阶段:两个不同投票进行对坑,并且同时抵消掉各一张票,如果两个投票相同,则累加可抵消的次数;

计数阶段:在抵消阶段最后得到的抵消计数只要不为 0,那这个候选人是有可能超过一半的票数的,为了验证,则需要遍历一次,统计票数,才可确定。

摩尔投票法经历两个阶段最多消耗 O(2n) 的时间,也属于 O(n) 的线性时间复杂度,另外空间复杂度也达到常量级。

实现

class Solution:
    def majorityElement(self, nums: List[int]) -> List[int]:
        if not nums:
            return []
        n = len(nums)
        cand1, count1 = nums[0], 0
        cand2, count2 = nums[0], 0
        result = []
        for num in nums:
            if cand1 == num:
                count1 += 1
                continue
            if cand2 == num: 
                count2 += 1
                continue
            if count1 == 0:
                cand1 = num
                count1 += 1
                continue
            if count2 == 0: 
                cand2 = num
                count2 += 1
                continue
            count1 -= 1
            count2 -= 1
        count1, count2 = 0, 0
        for num in nums:
            if num == cand1:
                count1 += 1
            elif num == cand2:
                count2 += 1
        if count1 > n/3 :
            result.append(cand1)
        if count2 > n/3:
            result.append(cand2)
        return result

题目230题

二叉搜索树中第k小的元素

给定一个二叉搜索树,编写一个函数 kthSmallest 来查找其中第 k 个最小的元素。

思路

深度优先遍历

实现

class Solution:
    def kthSmallest(self, root: TreeNode, k: int) -> int:
        
        def dfs(node):
            return dfs(node.left) + [node.val] + dfs(node.right) if node else []
        
        return dfs(root)[k-1]

题目231题

2的幂

给定一个整数,编写一个函数来判断它是否是 2 的幂次方。

思路

1. 递归

2.位运算:

2 的幂在二进制中是有一个 1 后跟一些 0;不是 2 的幂的二进制中有一个以上的 1

x & (-x) 将保留最右边的 1。并将其他的位设置为 0。因此判断是否为 2 的幂的关键是:判断 x & (-x) == x

实现

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

题目232题

用栈实现队列

使用栈实现队列的下列操作:

push(x) -- 将一个元素放入队列的尾部。
pop() -- 从队列首部移除元素。
peek() -- 返回队列首部的元素。
empty() -- 返回队列是否为空。

思路实现

class MyQueue:

    def __init__(self):
        """
        Initialize your data structure here.
        """
        self.s1 = list()
        self.s2 = list()
        self.front = None


    def push(self, x: int) -> None:
        """
        Push element x to the back of queue.
        """
        if len(self.s1) == 0:
            self.front = x
        self.s1.append(x)

    def pop(self) -> int:
        """
        Removes the element from in front of queue and returns that element.
        """
        if len(self.s2) == 0:
            while self.s1:
                self.s2.append(self.s1.pop())
        return self.s2.pop()
        
    def peek(self) -> int:
        """
        Get the front element.
        """
        if len(self.s2) != 0:
            return self.s2[-1]
        return self.front

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

题目234题

回文链表

请判断一个链表是否为回文链表。

思路

递归

实现

class Solution:
    def isPalindrome(self, head: ListNode) -> bool:
        self.pre = head
        def prev(node: ListNode):
            if node:
                if not prev(node.next):
                    return False
                if self.pre.val != node.val:
                    return False
                self.pre = self.pre.next
            return True
        return prev(head)

题目235题

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

给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。

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

思路

利用二叉搜索树的特性

我们从根节点开始遍历;

如果当前节点的值大于 p和 q 的值,说明 p 和 q 应该在当前节点的左子树,因此将当前节点移动到它的左子节点;

如果当前节点的值小于 p和 q的值,说明 p 和 q 应该在当前节点的右子树,因此将当前节点移动到它的右子节点;

如果当前节点的值不满足上述两条要求,那么说明当前节点就是「分岔点」。此时,pp 和 qq 要么在当前节点的不同的子树中,要么其中一个就是当前节点。

实现

class Solution:
    def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
        node = root
        while node:
            if node.val < q.val and node.val < p.val:
                node = node.right
            elif node.val > q.val and node.val > p.val:
                node = node.left
            else:
                return node

题目236题

二叉树的最近公共祖先

给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。

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

思路实现

class Solution:
    def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
        result = []
        def dfs(node, ans, target):
            if node:
                if node is target:
                    result.append(ans + [node])
                dfs(node.left, ans + [node], target)
                dfs(node.right, ans + [node], target)
        dfs(root, [],q)
        dfs(root, [],p)
        m = result[0]
        n = result[1]
        for i in range( min(len(m), len(n)) ):
            if m[i] != n[i]:
                break
            res = m[i]
        return res

 

原文地址:https://www.cnblogs.com/mgdzy/p/13813475.html