coding刷题总结-数据结构类题目-使用python语言-由易到难,梯度设置合理

题目目录

547 · 两数组的交集

给出两个数组,写出一个方法求出它们的交集
结果中的每个元素必须是唯一的。

class Solution:
    """
    @param nums1: an integer array
    @param nums2: an integer array
    @return: an integer array
    """
    def intersection(self, nums1, nums2):
        # write your code here
        # 把两个数组变成集合
        # 采用集合的交集运算
        nums1_set = set(nums1)
        nums2_set = set(nums2)

        return list(nums1_set & nums2_set)

二刷,注意list(集合),将集合转为列表

548 · 两数组的交集 II

给定两个数组,计算两个数组的交集
每个元素出现次数得和在数组里一样
答案可以以任意顺序给出
-如果给定的数组已经排序了怎么办?如何优化算法?
-如果nums1的大小比num2的小怎么办?哪种算法更好?
-如果nums2的元素存储在磁盘上,并且内存受到限制,以至于不能一次将所有元素加载到内存中,该怎么办?

class Solution:
    """
    @param nums1: an integer array
    @param nums2: an integer array
    @return: an integer array
    """
    def intersection(self, nums1, nums2):
        # write your code here
        # 感觉题目挺简单的,但是自己没能实现
        # 用字典维护数组1中每个元素出现的次数
        # 然后遍历数组2,如果元素在dict中的次数>0,是交集
        # 将出现次数减去1
        counter = {}
        for num in nums1:
            if num not in counter:
                counter[num] = 1
            else:
                counter[num] += 1
        res = []
        for num in nums2:
            if num in counter and counter[num] > 0:
                res.append(num)
                counter[num] -= 1

        return res    

二刷,一刷的方法应该更好O(n)

下方这个方法,nums2的元素存储在磁盘上,并且内存受到限制,以至于不能一次将所有元素加载到内存中,就没办法用高效地排序了。
如果是已经排序的数组,这样做倒是挺好的。

class Solution:
    """
    @param nums1: an integer array
    @param nums2: an integer array
    @return: an integer array
    """
    def intersection(self, nums1, nums2):
        # write your code here 
        # 两数组排序,然后从头遍历
        # 相等的话就加入结果中
        nums1.sort()
        nums2.sort()
        m, n = len(nums1), len(nums2)
        i, j = 0, 0
        res = []

        while i < m and j < n:
            if i < m and j < n and nums1[i] == nums2[j]:
                res.append(nums1[i])
                i += 1
                j += 1
            if i < m and j < n and nums1[i] < nums2[j]:
                i += 1
            if i < m and j < n and nums1[i] > nums2[j]:
                j += 1

        return res 

793 · 多个数组的交集

给出多个数组,求它们的交集。输出他们交集的大小。

输入的所有数组元素总数不超过500000。
题目数据每个数组里的元素没有重复。

class Solution:
    """
    @param arrs: the arrays
    @return: the number of the intersection of the arrays
    """
    def intersectionOfArrays(self, arrs):
        # write your code here
        # 第一思路是转化为两数组求交集的问题
        # 有点类似于合并K个数组的问题,转化为合并2个数组的问题
        while len(arrs) > 1:
            new_arrs = []
            for i in range(0, len(arrs), 2):
                if i + 1 < len(arrs):
                    new_arrs.append(self.intersection(arrs[i], arrs[i + 1]))
                else:
                    new_arrs.append(arrs[i])
            arrs = new_arrs[:]

        return len(arrs[0])

    def intersection(self, nums1, nums2):
        return list(set(nums1) & set(nums2))

二刷,二刷代码看着更好一些

class Solution:
    """
    @param arrs: the arrays
    @return: the number of the intersection of the arrays
    """
    def intersectionOfArrays(self, arrs):
        # write your code here
        # 因为每个数组里的元素没有重复,可以使用集合来做
        # 多个数组的交集,两两来做
        if len(arrs) == 0:
            return 0

        if len(arrs) == 1:
            return len(arrs[0])
        
        res = set(arrs[0])
        for i in range(1, len(arrs)):
            res = res & set(arrs[i])

        return len(res) 

6 · 合并排序数组

将按升序排序的整数数组A和B合并,新数组也需有序。

class Solution:
    """
    @param A: sorted integer array A
    @param B: sorted integer array B
    @return: A new sorted integer array
    """
    def mergeSortedArray(self, A, B):
        # write your code here
        # 和合并两个排序链表的思路一样
        # 从头遍历两个数组,把小的数放到新数组中
        new_array = []
        index_a, index_b = 0, 0
        while index_a < len(A) and index_b < len(B):
            if A[index_a] < B[index_b]:
                new_array.append(A[index_a])
                index_a += 1
            else:
                new_array.append(B[index_b])
                index_b += 1   

        if index_a < len(A):
            new_array.extend(A[index_a:])
        if index_b < len(B):
            new_array.extend(B[index_b:])

        return new_array

二刷,掌握的很好

class Solution:
    """
    @param A: sorted integer array A
    @param B: sorted integer array B
    @return: A new sorted integer array
    """
    def mergeSortedArray(self, A, B):
        # write your code here
        i, j = 0, 0
        res = []
        while i < len(A) and j < len(B):
            if A[i] < B[j]:
                res.append(A[i])
                i += 1
            else:
                res.append(B[j])
                j += 1 

        while i < len(A):
            res.append(A[i])
            i += 1
        while j < len(B):
            res.append(B[j])
            j += 1

        return res 

三刷,掌握的很好

64 · 合并排序数组(简单版)

合并两个排序的整数数组A和B变成一个新的数组。
你可以假设A具有足够的空间(A数组的大小大于或等于m+n)去添加B中的元素。数组A和B分别含有m和n个数。

class Solution:
    """
    @param: A: sorted integer array A which has m elements, but size of A is m+n
    @param: m: An integer
    @param: B: sorted integer array B which has n elements
    @param: n: An integer
    @return: nothing
    """
    def mergeSortedArray(self, A, m, B, n):
        # write your code here
        # 这个和第6题有什么区别吗?都是排序数组
        # 但是这个题目要求return nothing,我理解合并后的数组放到A中
        # 这次尝试不另开数组,直接存到A中
        # 从后向前遍历,比较的时候,每次取较大的数放到A的后面
        index_a = m - 1
        index_b = n - 1
        tail = m + n - 1
        while index_a >= 0 and index_b >= 0:
            if A[index_a] > B[index_b]:
                A[tail] = A[index_a]
                index_a -= 1
            else:
                A[tail] = B[index_b]
                index_b -= 1
            tail -= 1 
        while index_a >= 0:
            A[tail] = A[index_a]
            index_a -= 1
            tail -= 1
        while index_b >= 0:
            A[tail] = B[index_b]
            index_b -= 1
            tail -= 1

二刷,len得到就是数组的size大小

class Solution:
    """
    @param: A: sorted integer array A which has m elements, but size of A is m+n
    @param: m: An integer
    @param: B: sorted integer array B which has n elements
    @param: n: An integer
    @return: nothing
    """
    def mergeSortedArray(self, A, m, B, n):
        # write your code here
        # 倒序遍历A和B并比较大小
        # 大的数放到A的后面
        i, j = m - 1, n - 1 # len(A) - 1, len(B) - 1是不对的
        tail = m + n - 1
        
        while i >= 0 and j >= 0:
            if A[i] > B[j]:
                A[tail] = A[i]
                i -= 1
                tail -= 1
            else:
                A[tail] = B[j]
                j -= 1
                tail -= 1

        while i >= 0:
            A[tail] = A[i]
            i -= 1
            tail -= 1
        while j >= 0:
            A[tail] = B[j]
            j -= 1
            tail -= 1

486 · 合并k个排序数组

将 k 个有序数组合并为一个大的有序数组。

class Solution:
    """
    @param arrays: k sorted integer arrays
    @return: a sorted array
    """
    def mergekSortedArrays(self, arrays):
        # write your code here
        # 类似合并K个排序链表的思路
        # 转为合并2个排序数组问题
        # 两两合并,直到只剩一个数组
        # tmp = []
        while len(arrays) > 1:
            tmp = []
            for index in range(0, len(arrays), 2):
                if index + 1 < len(arrays):
                    tmp.append(self.merge2SortedArrays(arrays[index], arrays[index + 1]))
                else:
                    tmp.append(arrays[index])
            arrays = tmp[:]

        return arrays[0]

    def merge2SortedArrays(self, array1, array2):
        new_array = []
        index_1, index_2 = 0, 0
        while index_1 < len(array1) and index_2 < len(array2):
            if array1[index_1] < array2[index_2]:
                new_array.append(array1[index_1])
                index_1 += 1
            else:
                new_array.append(array2[index_2])
                index_2 += 1
        if index_1 < len(array1):
            new_array.extend(array1[index_1:])
        if index_2 < len(array2):
            new_array.extend(array2[index_2:])

        return new_array

二刷,依然可以思考除了两两合并之外的方法

165 · 合并两个排序链表

将两个排序(升序)链表合并为一个新的升序排序链表

"""
Definition of ListNode
class ListNode(object):
    def __init__(self, val, next=None):
        self.val = val
        self.next = next
"""

class Solution:
    """
    @param l1: ListNode l1 is the head of the linked list
    @param l2: ListNode l2 is the head of the linked list
    @return: ListNode head of linked list
    """
    def mergeTwoLists(self, l1, l2):
        # write your code here
        # 依次从头到尾比较两个链表的节点值
        # 把小的节点值赋值到一个新的链表
        dummy = ListNode(0)
        tmp = dummy
        while l1 and l2:
            if l1.val < l2.val:
                tmp.next = l1
                l1 = l1.next
            else:
                tmp.next = l2
                l2 = l2.next
            tmp = tmp.next

        if l1:
            tmp.next = l1
        if l2:
            tmp.next = l2

        return dummy.next

二刷,基本掌握

104 · 合并k个排序链表

合并k个排序链表,并且返回合并后的排序链表。尝试分析和描述其复杂度。

先合并前两个,然后用得到的合并链表和第三个合并,依次向后。这样会time limit exceeded。
这不是一个好的方法

"""
Definition of ListNode
class ListNode(object):

    def __init__(self, val, next=None):
        self.val = val
        self.next = next
"""
class Solution:
    """
    @param lists: a list of ListNode
    @return: The head of one sorted list.
    """
    def mergeKLists(self, lists):
        # write your code here
        # 做过了合并两个排序链表的题目
        # 拆解问题,将合并K个转为合并2个的问题
        # 可以想到的一个容易实现的思路是:
        # 将第一个和第二个合并,得到的新链表和第三个合并
        # 依次向后,直到和最后一个链表合并
        new_listnode = lists[0]
        index = 1
        while index < len(lists):
            l2 = lists[index]
            new_listnode = self.merge2Lists(new_listnode, l2)
            index += 1

        return new_listnode

    def merge2Lists(self, new_listnode, l2):
        dummy = ListNode(0)
        tmp = dummy
        while new_listnode and l2:
            if new_listnode.val < l2.val:
                tmp.next = new_listnode
                new_listnode = new_listnode.next
            else:
                tmp.next = l2
                l2 = l2.next
            tmp = tmp.next
        if new_listnode:
            tmp.next = new_listnode
        if l2:
            tmp.next = l2

        return dummy.next

优化了一下,先把列表中的链表两两合并,这样不停的两两合并,直到只剩一个链表。

"""
Definition of ListNode
class ListNode(object):

    def __init__(self, val, next=None):
        self.val = val
        self.next = next
"""
class Solution:
    """
    @param lists: a list of ListNode
    @return: The head of one sorted list.
    """
    def mergeKLists(self, lists):
        # write your code here
        # 还是转为合并2个排序链表
        # 把链表两两合并,直到只剩下1个链表
        while len(lists) > 1:
            tmp = []
            for index in range(0, len(lists), 2):
                if index + 1 < len(lists):
                    tmp.append(self.merge2Lists(lists[index], lists[index + 1]))
                else:
                    tmp.append(lists[index])
            lists = tmp[:]

        return lists[0]

    def merge2Lists(self, l1, l2):
        dummy = tail = ListNode(0)
        while l1 and l2:
            if l1.val < l2.val:
                tail.next = l1
                l1 = l1.next
            else:
                tail.next = l2
                l2 = l2.next
            tail = tail.next
        if l1:
            tail.next = l1
        if l2:
            tail.next = l2
        
        return dummy.next

839 · 合并两个排序的间隔列表

合并两个已排序的区间列表,并将其作为一个新的有序区间列表返回。新的区间列表应该通过拼接两个列表的区间并按升序排序。

同一个列表中的区间一定不会重叠。
不同列表中的区间可能会重叠。

"""
Definition of Interval.
class Interval(object):
    def __init__(self, start, end):
        self.start = start
        self.end = end
"""

class Solution:
    """
    @param list1: one of the given list
    @param list2: another list
    @return: the new sorted list of interval
    """
    def mergeTwoInterval(self, list1, list2):
        # write your code here
        # 有点类似于合并两个数组
        # 记录最后一个放进去的interval,和下一个interval做比较
        i, j = 0, 0
        intervals = []
        while i < len(list1) and j < len(list2):
            if list1[i].start < list2[j].start:
                self.pushBack(intervals, list1[i])
                i += 1
            else:
                self.pushBack(intervals, list2[j])
                j += 1

        while i < len(list1):
            self.pushBack(intervals, list1[i])
            i += 1
        while j < len(list2):
            self.pushBack(intervals, list2[j])
            j += 1

        return intervals
    
    def pushBack(self, intervals, interval):
        if intervals == []:
            intervals.append(interval)
            return 
        last_interval = intervals[-1]
        if last_interval.end < interval.start:
            intervals.append(interval)
        else:
            last_interval.end = max(last_interval.end, interval.end)

577 · 合并K个排序间隔列表

将K个排序的间隔列表合并到一个排序的间隔列表中,你需要合并重叠的间隔。

"""
Definition of Interval.
class Interval(object):
    def __init__(self, start, end):
        self.start = start
        self.end = end
"""

class Solution:
    """
    @param intervals: the given k sorted interval lists
    @return:  the new sorted interval list
    """
    def mergeKSortedIntervalLists(self, intervals):
        # write your code here
        # 做过了合并两个排序间隔列表
        # 将合并k的问题,转化为合并两个的问题
        # 两两合并,直到只剩一个
        while len(intervals) > 1:
            tmp = []
            for i in range(0, len(intervals), 2):
                if i + 1 < len(intervals):
                    tmp.append(self.merge2SortedIntervalLists(intervals[i], intervals[i + 1]))
                else:
                    tmp.append(intervals[i])
            intervals = tmp[:]

        return intervals[0]

    def merge2SortedIntervalLists(self, interval1, interval2):
        i, j = 0, 0
        res = []
        while i < len(interval1) and j < len(interval2):
            if interval1[i].start < interval2[j].start:
                self.pushBack(res, interval1[i])
                i += 1
            else:
                self.pushBack(res, interval2[j])
                j += 1

        while i < len(interval1):
            self.pushBack(res, interval1[i])
            i += 1
        while j < len(interval2):
            self.pushBack(res, interval2[j])
            j += 1

        return res 

    def pushBack(self, res, interval):
        if res == []:
            res.append(interval)
            return 

        last_interval = res[-1]
        if last_interval.end < interval.start:
            res.append(interval)
        else:
            last_interval.end = max(last_interval.end, interval.end)

224 · 用一个数组实现三个栈

用一个数组实现三个栈。你可以假设这三个栈都一样大并且足够大。你不需要担心如果一个栈满了之后怎么办。

class ThreeStacks:
    """
    @param: size: An integer
    """
    def __init__(self, size):
        # do intialization if necessary
        self.size = size
        self.nums = [[], [], []]

    """
    @param: stackNum: An integer
    @param: value: An integer
    @return: nothing
    """
    def push(self, stackNum, value):
        # Push value into stackNum stack
        self.nums[stackNum].append(value)

    """
    @param: stackNum: An integer
    @return: the top element
    """
    def pop(self, stackNum):
        # Pop and return the top element from stackNum stack
        return self.nums[stackNum].pop()

    """
    @param: stackNum: An integer
    @return: the top element
    """
    def peek(self, stackNum):
        # Return the top element
        return self.nums[stackNum][-1]

    """
    @param: stackNum: An integer
    @return: true if the stack is empty else false
    """
    def isEmpty(self, stackNum):
        # write your code here
        return len(self.nums[stackNum]) == 0

二刷,85分

494 · 双队列实现栈

通过两个队列实现一个栈。队列是先进先出(FIFO)。这意味着不能直接弹出队列中的最后一个元素。
输入:
push(1)
pop()
push(2)
isEmpty() // return false
top() // return 2
pop()
isEmpty() // return true

基本概念:队列是先进先出。有放入、取出元素等操作。
栈是后进先出,栈有压入、弹出,访问栈顶元素,栈大小,栈是否为空等操作。
这个题目的思路是一个队列用来保存栈的元素,另一个队列用来配合实现栈的压入、弹出、访问栈顶元素。
2021年6月二刷时对这样方法的理解:入栈操作时,先放到辅助队列,然后把主队列的元素移出放到辅助队列。这样辅助队列的队头元素就是栈顶元素了(最后入的),这是在把辅助队列和主队列交换。

from collections import deque
class Stack:
    """
    queue1用来保存栈的元素
    queue2用来配合实现压入、弹出等操作
    """
    def __init__(self):
        self.queue1 = deque()
        self.queue2 = deque()
    """
    @param: x: An integer
    @return: nothing
    """
    def push(self, x):
        # write your code here
        self.queue2.append(x)
        while self.queue1:
            self.queue2.appendleft(self.queue1.pop())
        self.queue1, self.queue2 = self.queue2, self.queue1
    """
    @return: nothing
    """
    def pop(self):
        # write your code here
        return self.queue1.pop()

    """
    @return: An integer
    """
    def top(self):
        # write your code here
        return self.queue1[-1]

    """
    @return: True if the stack is empty
    """
    def isEmpty(self):
        # write your code here
        return not self.queue1

二刷,掌握的不好

思路时:入栈时看主队列是否为空,不为空的话,移出放到辅助队列。然后入栈放到主队列,再把辅助队列的元素移出放到主队列。这样就实现了主队列的队头元素为栈顶元素。

class Stack:
    # 两个队列,queue1为主队列,存储栈内元素
    # queue2为辅助队列,实现入栈和出栈操作
    # 入栈时,先把主队列元素一一移出放到辅助队列
    # 然后把元素放到主队列,再把辅助队列的元素移出放入主队列
    def __init__(self):
        self.queue1 = []
        self.queue2 = []
    """
    @param: x: An integer
    @return: nothing
    """
    def push(self, x):
        # write your code here
        while self.queue1 != []:
            self.queue2.append(self.queue1.pop())
        self.queue1.append(x)
        while self.queue2 != []:
            self.queue1.append(self.queue2.pop())

    """
    @return: nothing
    """
    def pop(self):
        # write your code here
        self.queue1.pop(0)

    """
    @return: An integer
    """
    def top(self):
        # write your code here
        return self.queue1[0]

    """
    @return: True if the stack is empty
    """
    def isEmpty(self):
        # write your code here
        return not self.queue1

943 · 区间和查询 - 不可变的

给一个整数数组 nums,求出下标从 i 到 j 的元素和(i ≤ j),i 跟 j对应的元素也包括在内。
你可以认为给出的数组不会发生变化。
会调用非常多次 sumRange 函数。

很常用的前缀和思路

class NumArray(object):

    def __init__(self, nums):
        """
        :type nums: List[int]
        """
        # self.nums = nums
        self.prefix_sum = [0] * (len(nums) + 1)
        for i in range(len(nums)):
            self.prefix_sum[i + 1] = self.prefix_sum[i] + nums[i]

    def sumRange(self, i, j):
        """
        :type i: int
        :type j: int
        :rtype: int
        """
        return self.prefix_sum[j + 1] - self.prefix_sum[i]

# Your NumArray object will be instantiated and called as such:
# obj = NumArray(nums)
# param_1 = obj.sumRange(i,j)

665 · 平面范围求和 -不可变矩阵

给一 二维矩阵,计算由左上角 (row1, col1) 和右下角 (row2, col2) 划定的矩形内元素和.

你可以假设矩阵不变
对函数 sumRegion 的调用次数有很多次
你可以假设 row1 ≤ row2 并且 col1 ≤ col2

class NumMatrix:
    """
    @param: matrix: a 2D matrix
    """
    def __init__(self, matrix):
        # do intialization if necessary
        # 运用前缀和的思想,计算(0, 0)到每个点的矩阵和
        # dp[i][j]表示左上角到(i, j)点的矩阵和
        # dp[i][j] = dp[i][j-1] + dp[i-1][j] - dp[i-1][j-1] + matrix[i][j]
        # 另外,为了避免多次重复计算,
        # 在初始化时就计算好前缀和
        if len(matrix) == 0 or len(matrix[0]) == 0:
            return 
            
        n, m = len(matrix), len(matrix[0])
        self.dp = [[0 for col in range(m + 1)] for row in range(n + 1)]
        for row in range(n):
            for col in range(m):
                self.dp[row + 1][col + 1] = self.dp[row][col + 1] + self.dp[row + 1][col] \
                 - self.dp[row][col] + matrix[row][col]

    """
    @param: row1: An integer
    @param: col1: An integer
    @param: row2: An integer
    @param: col2: An integer
    @return: An integer
    """
    def sumRegion(self, row1, col1, row2, col2):
        # write your code here
        return self.dp[row2 + 1][col2 + 1] - self.dp[row2 + 1][col1] - self.dp[row1][col2 + 1] \
         + self.dp[row1][col1]

# Your NumMatrix object will be instantiated and called as such:
# obj = NumMatrix(matrix)
# param_1 = obj.sumRegion(row1,col1,row2,col2)

405 · 和为零的子矩阵

给定一个整数矩阵,请找出一个子矩阵,使得其数字之和等于0.输出答案时,请返回左上数字和右下数字的坐标。

如果有多个答案, 你可以返回其中任意一个.

class Solution:
    """
    @param: matrix: an integer matrix
    @return: the coordinate of the left-up and right-down number
    """
    def submatrixSum(self, matrix):
        # write your code here
        # 第一思路是暴力,枚举所有的子矩阵,求矩阵和
        n, m = len(matrix), len(matrix[0])
        for row1 in range(n):
            for row2 in range(row1, n):
                for col1 in range(m):
                    for col2 in range(col1, m):
                        sum_region = sum(matrix[row1][col1:col2 + 1]) + sum(matrix[row2][col1:col2 + 1])
                        if sum_region == 0:
                            return [[row1, col1], [row2, col2]]

        return [[-1, 1], [-1, -1]]
        # return None 

944 · 最大子矩阵

给出一个大小为 n x n 的矩阵,里面元素为 正整数 和 负整数 ,找到具有最大和的子矩阵。

class Solution:
    """
    @param matrix: the given matrix
    @return: the largest possible sum
    """
    def maxSubmatrix(self, matrix):
        # write your code here
        # 把二维矩阵向下压缩,就变成了一维数组
        # 本题采用这个思想,就变成了求数组的最大子数组
        if len(matrix) == 0 or len(matrix[0]) == 0:
            return 0

        import sys
        res = -sys.maxsize
        m, n = len(matrix), len(matrix[0])

        for i in range(m):
            array = [0] * n
            for j in range(i, m):
                for k in range(n):
                    array[k] += matrix[j][k]
                max_subArraySum = self.maxSubArray(array)
                res = max(res, max_subArraySum)

        return res 

    def maxSubArray(self, array):
        import sys
        max_sum, min_sum = -sys.maxsize, 0
        prefix_sum = 0
        for num in array:
            prefix_sum += num
            max_sum = max(max_sum, prefix_sum - min_sum)
            min_sum = min(min_sum, prefix_sum)

        return max_sum

209 · 第一个只出现一次的字符

给出一个字符串,找出第一个只出现一次的字符。假设只出现一次的字符数量大于等于1。

class Solution:
    """
    @param str: str: the given string
    @return: char: the first unique character in a given string
    """
    def firstUniqChar(self, str):
        # Write your code here
        # 使用hash表存下每个char出现的次数
        # 遍历str,如果char出现次数为1则返回
        counter = {}
        for char in str:
            counter[char] = counter.get(char, 0) + 1
        for char in str:
            if counter[char] == 1:
                return char

657 · O(1)实现数组插入/删除/随机访问

设计一个数据结构实现在平均 O(1) 的复杂度下执行以下所有的操作。
insert(val): 如果这个元素不在set中,则插入。
remove(val): 如果这个元素在set中,则从set中移除。
getRandom: 随机从set中返回一个元素。每一个元素返回的可能性必须相同。

class RandomizedSet:
    
    def __init__(self):
        # do intialization if necessary
        # 数组用来保存元素
        # 字典用来保存元素和其在数组中的索引
        self.nums = []
        self.val2index = {}

    """
    @param: val: a value to the set
    @return: true if the set did not already contain the specified element or false
    """
    def insert(self, val):
        # write your code here
        if val in self.val2index:
            return False
        self.nums.append(val)
        self.val2index[val] = len(self.nums) - 1
        return True

    """
    @param: val: a value from the set
    @return: true if the set contained the specified element or false
    """
    def remove(self, val):
        # write your code here
        if val not in self.val2index:
            return False
        index = self.val2index[val]
        self.val2index[self.nums[-1]] = index
        self.nums[index], self.nums[-1] = self.nums[-1], self.nums[index]
        self.nums.pop()
        del self.val2index[val]
        return True
    
    """
    @return: Get a random element from the set
    """
    def getRandom(self):
        # write your code here
        import random
        return self.nums[random.randint(0, len(self.nums) - 1)]
# Your RandomizedSet object will be instantiated and called as such:
# obj = RandomizedSet()
# param = obj.insert(val)
# param = obj.remove(val)
# param = obj.getRandom()

642 · 数据流滑动窗口平均值

给出一串整数流和窗口大小,计算滑动窗口中所有整数的平均值。

注意不必要把所有的数据流都存在数组中,一边存新的一边删除老的

class MovingAverage(object):
    """
    @param: size: An integer
    """
    def __init__(self, size):
        # do intialization if necessary
        self.size = size
        self.nums = []
        self.sum = 0

    """
    @param: val: An integer
    @return:  
    """
    def next(self, val):
        # write your code here
        if len(self.nums) == self.size:
            self.sum -= self.nums[0]
            del self.nums[0]
        self.sum += val
        self.nums.append(val)
        return self.sum / len(self.nums)


# Your MovingAverage object will be instantiated and called as such:
# obj = MovingAverage(size)
# param = obj.next(val)

544 · 前K大数

在一个数组中找到前K大的数

class Solution:
    """
    @param nums: an integer array
    @param k: An integer
    @return: the top k largest numbers in array
    """
    def topk(self, nums, k):
        # write your code here
        # 时间复杂度O(nlogn)
        nums.sort()
        return nums[-1:-k - 1:-1]

40 · 用栈实现队列

正如标题所述,你只能使用两个栈来实现队列的一些操作。
队列应支持push(element),pop() 和 top(),其中pop是弹出队列中的第一个(最前面的)元素。
pop和top方法都应该返回第一个元素的值。
假设调用pop()函数的时候,队列非空
挑战
仅使用两个栈来实现它,不使用任何其他数据结构,push,pop 和 top的复杂度都应该是均摊O(1)的

看答案使用两个列表来实现的,并没有使用栈。先自己实现了看看。
栈1来保存元素,栈2来辅助实现队列的操作
其实列表的结构和栈是挺像的,append类似push,pop也是类似的。也是先进的后出,后进的先出。
先把元素放到栈2,然后再倒出来放到栈1

class MyQueue:
    
    def __init__(self):
        # do intialization if necessary
        self.stack1 = []
        self.stack2 = []

    """
    @param: element: An integer
    @return: nothing
    """
    def push(self, element):
        # write your code here
        self.stack2.append(element)

    """
    @return: An integer
    """
    def pop(self):
        # write your code here
        if self.stack1:
            return self.stack1.pop()
        while self.stack2:
            self.stack1.append(self.stack2.pop())
        
        return self.stack1.pop()

    """
    @return: An integer
    """
    def top(self):
        # write your code here
        if self.stack1:
            return self.stack1[-1]
        while self.stack2:
            self.stack1.append(self.stack2.pop())
        
        return self.stack1[-1]

二刷,掌握的不好

从一个栈依次pop放入另一栈以后,原来在栈顶的元素就跑到栈底了,而原来在栈底的元素就到了栈顶。
队列却没有这样的特点,从一个队列依次弹出放入另一个队列,元素的顺序不变。

class MyQueue:
    # 两个栈,一个为主栈,存储元素
    # 一个为辅助栈,
    # 入队列时,先入辅助栈,然后把主栈元素也放入辅助栈
    # 这样在辅助栈就实现了后入的元素在栈底
    # 交换辅助栈和主站

    # 上面写的思路是错误的。。。
    # 先入辅助栈,pop的时候看主栈是否为空,为空的话,
    # 把辅助栈的移出放到主栈,然后pop
    # 不为空的话,就直接pop
    def __init__(self):
        # do intialization if necessary
        self.stack1 = []
        self.stack2 = []

    """
    @param: element: An integer
    @return: nothing
    """
    def push(self, element):
        # write your code here
        self.stack2.append(element)

    """
    @return: An integer
    """
    def pop(self):
        # write your code here
        if self.stack1:
            return self.stack1.pop()
        else:
            while self.stack2:
                self.stack1.append(self.stack2.pop())
            return self.stack1.pop()

    """
    @return: An integer
    """
    def top(self):
        # write your code here
        if self.stack1:
            return self.stack1[-1]
        else:
            while self.stack2:
                self.stack1.append(self.stack2.pop())
            return self.stack1[-1]

495 · 实现栈

实现一个栈,可以使用除了栈之外的数据结构

class Stack:
    def __init__(self):
        # 使用列表来实现栈操作试试
        self.nums = []
    """
    @param: x: An integer
    @return: nothing
    """
    def push(self, x):
        # write your code here
        self.nums.append(x)

    """
    @return: nothing
    """
    def pop(self):
        # write your code here
        return self.nums.pop()

    """
    @return: An integer
    """
    def top(self):
        # write your code here
        return self.nums[-1]

    """
    @return: True if the stack is empty
    """
    def isEmpty(self):
        # write your code here
        return not self.nums

二刷,90分

力扣155. 最小栈

设计一个支持 push ,pop ,top 操作,并能在常数时间内检索到最小元素的栈。

push(x) —— 将元素 x 推入栈中。
pop() —— 删除栈顶的元素。
top() —— 获取栈顶元素。
getMin() —— 检索栈中的最小元素。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/min-stack
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

class MinStack:

    def __init__(self):
        """
        initialize your data structure here.
        """
        # 构造一个辅助栈,放每个栈顶元素对应的最小值
        # 每push一个元素,和辅助栈栈顶元素比较大小
        self.stack = []
        self.min_stack = [math.inf]


    def push(self, val: int) -> None:
        self.stack.append(val)
        if val < self.min_stack[-1]:
            self.min_stack.append(val)
        else:
            self.min_stack.append(self.min_stack[-1])

    def pop(self) -> None:
        self.stack.pop()
        self.min_stack.pop()
        
    def top(self) -> int:
        return self.stack[-1]
        
    def getMin(self) -> int:
        return self.min_stack[-1]

# Your MinStack object will be instantiated and called as such:
# obj = MinStack()
# obj.push(val)
# obj.pop()
# param_3 = obj.top()
# param_4 = obj.getMin()

二刷,60分

class MinStack:
    # 用列表来实现栈,在用一个辅助列表来存储主栈栈顶元素对应的最小值

    def __init__(self):
        """
        initialize your data structure here.
        """
        self.stack1 = []
        self.stack2 = []

    def push(self, val: int) -> None:
        self.stack1.append(val)
        if self.stack2 == []:
            self.stack2.append(val)
        else:
            if val < self.stack2[-1]:
                self.stack2.append(val)
            else:
                self.stack2.append(self.stack2[-1])

    def pop(self) -> None:
        self.stack1.pop()
        self.stack2.pop()

    def top(self) -> int:
        return self.stack1[-1]

    def getMin(self) -> int:
        return self.stack2[-1]

685 · 数据流中第一个唯一的数字

给一个连续的数据流,写一个函数返回终止数字到达时的第一个唯一数字(包括终止数字),如果找不到这个终止数字, 返回 -1.

class Solution:
    """
    @param nums: a continuous stream of numbers
    @param number: a number
    @return: returns the first unique number
    """
    def firstUniqueNumber(self, nums, number):
        # Write your code here
        # 遍历数据流,记录下每个数字出现的次数
        # 再次遍历,返回第一个唯一的数字
        counter = {}
        for digit in nums:
            counter[digit] = counter.get(digit, 0) + 1
            if digit == number:
                break
        else:
            return -1

        for digit in counter:
            if counter[digit] == 1:
                return digit
        
        return -1

613 · 优秀成绩

每个学生有两个属性 ID 和 scores。找到每个学生最高的5个分数的平均值。

'''
Definition for a Record
class Record:
    def __init__(self, id, score):
        self.id = id
        self.score = score
'''
class Solution:
    # @param {Record[]} results a list of <student_id, score>
    # @return {dict(id, average)} find the average of 5 highest scores for each person
    # <key, value> (student_id, average_score)
    def highFive(self, results):
        # Write your code here
        # 遍历找到每个学习最高的5个分数
        hash = {}
        for student in results:
            if student.id not in hash:
                hash[student.id] = []

            hash[student.id].append(student.score)
            if len(hash[student.id]) > 5:
                index = 0
                for i in range(1, 6):
                    if hash[student.id][i] < hash[student.id][index]:
                        index = i
                hash[student.id].pop(index)

        for student in hash:
            hash[student] = sum(hash[student]) / 5.0
        
        return hash

4 · 丑数 II

如果一个数只有质数因子2,3,5 ,那么这个数是一个丑数。
前10个丑数分别为 1, 2, 3, 4, 5, 6, 8, 9, 10, 12…设计一个算法,找出第N个丑数。
我们可以认为 1 也是一个丑数。

class Solution:
    """
    @param n: An integer
    @return: return a  integer as description.
    """
    def nthUglyNumber(self, n):
        # write your code here
        # 用堆来做,自己尝试实现一下
        # 每次弹出一个,弹到第n次的时候就是
        # 第n个丑数
        import heapq
        heap = [1]
        visited = set([1])
        for i in range(n):
            val = heapq.heappop(heap)
            for factor in [2, 3, 5]:
                if val * factor in visited:
                    continue
                visited.add(val * factor)
                heapq.heappush(heap, val * factor)

        return val

461 · 无序数组K小元素

找到一个无序数组中第K小的数
挑战:O(nlogn)的算法固然可行, 但如果你能 O(n) 解决, 那就非常棒了.

第k小元素,第k大元素,三种方法
内置排序算法、利用堆、快速选择
需要好好理解和掌握快速选择的程序,记住模板。

class Solution:
    """
    @param k: An integer
    @param nums: An integer array
    @return: kth smallest element
    """
    def kthSmallest(self, k, nums):
        # write your code here
        # 直接使用内置的排序算法就行,但是时间复杂度是O(nlogn)
        # 感觉nlogn已经挺快了,不知道为啥非要努力实现O(n)
        # version 1 O(nlogn)
        # nums.sort()
        # return nums[k - 1]

        # version 2
        # 快速选择算法,其实用的也是划分的思想
        # 或者说划分借鉴了快速选择算法
        return self.quickSelect(nums, 0, len(nums) - 1, k - 1)

    def quickSelect(self, nums, start, end, k):
        if start == end:
            return nums[start]
        left = start
        right= end
        pivot = nums[(left + right) // 2]
        while left <= right:
            while left <= right and nums[left] < pivot:
                left += 1
            while left <= right and nums[right] > pivot:
                right -= 1
            if left <= right:
                nums[left], nums[right] = nums[right], nums[left]
                left += 1
                right -= 1
        if k <= right and right >= start:
            self.quickSelect(nums, start, right, k)
        if k >= left and left <= end:
            self.quickSelect(nums, left, end, k)

        return nums[k]

606 · 第K大的元素 II

找到数组中第K大的元素,N远大于K。请注意你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素
你可以改变数组中元素的位置

相关的题目还有第五题,要掌握快速选择算法,掌握堆的使用

class Solution:
    """
    @param nums: an integer unsorted array
    @param k: an integer from 1 to n
    @return: the kth largest element
    """
    def kthLargestElement2(self, nums, k):
        # write your code here
        # 直接把数组sort,然后返回nums[-k]?
        # 时间复杂度时O(nlogn)
        # nums.sort()
        
        # return nums[-k] 

        # 题目应该不是让这么做的,那是让怎么做的呢?
        # 用堆来做试试,遍历数组,让堆里保持只有k个
        # 时间复杂度是O(n)
        import heapq
        heap = []
        for num in nums:
            heapq.heappush(heap, num)
            if len(heap) > k:
                heapq.heappop(heap)

        return heapq.heappop(heap)

545 · 前K大数 II

实现一个数据结构,提供下面两个接口
1.add(number) 添加一个元素
2.topk() 返回此数据结构中最大的k个数字。当我们创建数据结构时,k是给定的。

先用数组试试,没add一个数就把数组排序一次

class Solution:
    """
    @param: k: An integer
    """
    def __init__(self, k):
        # do intialization if necessary
        self.k = k
        self.nums = []

    """
    @param: num: Number to be added
    @return: nothing
    """
    def add(self, num):
        # write your code here
        self.nums.append(num)
        self.nums.sort()

    """
    @return: Top k element
    """
    def topk(self):
        # write your code here
        if self.k > len(self.nums):
            return self.nums[-1::-1]
        else:
            return self.nums[-1:-self.k - 1:-1]

用堆来实现试试,如果堆里的数超过k了,就弹出最小的。

import heapq
class Solution:
    """
    @param: k: An integer
    """
    def __init__(self, k):
        # do intialization if necessary
        self.k = k
        self.heap = []

    """
    @param: num: Number to be added
    @return: nothing
    """
    def add(self, num):
        # write your code here
        heapq.heappush(self.heap, num)
        if len(self.heap) > self.k:
            heapq.heappop(self.heap)
       
    """
    @return: Top k element
    """
    def topk(self):
        # write your code here
        return sorted(self.heap, reverse=True)

612 · K个最近的点

在二维空间里给定一些 points 和一个 origin,从 points 中找到 k 个离 origin 欧几里得距离最近的点。按照欧几里得距离由小到大返回。如果两个点有相同欧几里得距离,则按照x值来排序;若x值也相同,就再按照y值排序。

"""
Definition for a point.
class Point:
    def __init__(self, a=0, b=0):
        self.x = a
        self.y = b
"""

class Solution:
    """
    @param points: a list of points
    @param origin: a point
    @param k: An integer
    @return: the k closest points
    """
    def kClosest(self, points, origin, k):
        # write your code here
        # 要k个距离最近的点,可以考虑使用堆
        # 堆顶是最小的元素,超过k以后,就弹出堆顶元素
        # 所以存入堆的应该是距离的负数,坐标的负数
        import heapq
        heap = []
        for point in points:
            distance = self.getDistance(point, origin)
            heapq.heappush(heap, (-distance, -point.x, -point.y))
            if len(heap) > k:
                heapq.heappop(heap)

        res = []
        while heap:
            _, x, y = heapq.heappop(heap)
            res.append(Point(-x, -y))
        res.reverse()
        return res

    def getDistance(self, point1, point2):
        return (point1.x - point2.x) ** 2 + (point1.y - point2.y) ** 2

868 · 子数组的最大平均值

给定一个由n个整数组成的数组,找到给定长度k的连续子数组,该子数组具有最大平均值。你需要输出最大平均值。

1 <= k <= n <= 30,000.
给定数组的元素范围是[-10,000, 10,000]。

class Solution:
    """
    @param nums: an array
    @param k: an integer
    @return: the maximum average value
    """
    def findMaxAverage(self, nums, k):
        # Write your code here
        # 因为是给定长度的子数组
        # 题目可以转化为求给定长度的和最大的子数组
        # 运用前缀和的思想,遍历数组
        prefix_sum = [0] * (len(nums) + 1)
        for i in range(len(nums)):
            prefix_sum[i + 1] = prefix_sum[i] + nums[i]

        import sys
        max_sum = -sys.maxsize
        for i in range(len(nums)):
            if i + k > len(nums):
                break 
            max_sum = max(max_sum, prefix_sum[i + k] - prefix_sum[i])

        return max_sum * 1.0 / k

617 · 子数组的最大平均值 II

给出一个整数数组,有正有负。找到这样一个子数组,他的长度大于等于 k,且平均值最大。

保证数组的大小 >= k

class Solution:
    """
    @param nums: an array with positive and negative numbers
    @param k: an integer
    @return: the maximum average
    """
    def maxAverage(self, nums, k):
        # write your code here
        # 遍历长度大于等于k的子数组,求平均值,顺便打擂台
        prefix_sum = [0] * (len(nums) + 1)
        for i in range(len(nums)):
            prefix_sum[i + 1] = prefix_sum[i] + nums[i]

        import sys
        max_average = -sys.maxsize
        for i in range(len(nums)):
            if i + k - 1 > len(nums) - 1:
                break 
            for j in range(i + k - 1, len(nums)):
                average = (prefix_sum[j + 1] - prefix_sum[i]) / (j - i + 1)
                max_average = max(max_average, average)

        return max_average

138 · 子数组之和

给定一个整数数组,找到和为 0 的子数组。你的代码应该返回满足要求的子数组的起始位置和结束位置
至少有一个子数组的和为 0

class Solution:
    """
    @param nums: A list of integers
    @return: A list of integers includes the index of the first number and the index of the last number
    """
    def subarraySum(self, nums):
        # write your code here
        # 前缀和的思路
        # 如果[start, end]区间的和为0
        # 那么start之前的数之和、end之前包括end的数之和
        # 是相等的
        # 遍历前缀和,直到遇到相等的前缀和
        prefix_hash = {0: -1}
        prefix_sum = 0
        for i in range(len(nums)):
            prefix_sum += nums[i]
            if prefix_sum in prefix_hash:
                return [prefix_hash[prefix_sum] + 1, i]
            prefix_hash[prefix_sum] = i

        return [-1, -1]

139 · 最接近零的子数组和

给定一个整数数组,找到一个和最接近于零的子数组。返回满足要求的子数组的起始位置和结束位置。

class Solution:
    """
    @param: nums: A list of integers
    @return: A list of integers includes the index of the first number and the index of the last number
    """
    def subarraySumClosest(self, nums):
        # write your code here
        # 开始也没有思路,看了答案
        # 运用前缀和思想
        # 将前缀和排序,相邻两个是最接近的
        # 找到最接近的,记录索引
        prefix_sum = [(0, -1)]
        for i in range(len(nums)):
            prefix_sum.append((prefix_sum[-1][0] + nums[i], i))

        prefix_sum.sort()
        import sys
        closest = sys.maxsize
        res = []
        for i in range(1, len(prefix_sum)):
            if closest > prefix_sum[i][0] - prefix_sum[i - 1][0]:
                closest = prefix_sum[i][0] - prefix_sum[i - 1][0]
                left = min(prefix_sum[i][1], prefix_sum[i - 1][1]) + 1
                right = max(prefix_sum[i][1], prefix_sum[i - 1][1])
                res = [left, right]

        return res 

404 · 子数组求和 II

给定一个正整数数组 A 和一个区间. 返回和在给定区间范围内的子数组数量.

子数组是原数组下标连续的一段元素,至少包含一个元素.

class Solution:
    """
    @param A: An integer array
    @param start: An integer
    @param end: An integer
    @return: the number of possible answer
    """
    def subarraySumII(self, A, start, end):
        # write your code here
        # 运用前缀和的思想
        # 然后遍历前缀和,统计在给定区间的子数组数量
        # prefix_sum = [0]
        # counter = 0
        # for num in A:
        #     prefix_sum.append(prefix_sum[-1] + num)
        # for i in range(len(prefix_sum)):
        #     for j in range(i + 1, len(prefix_sum)):
        #         if start <= prefix_sum[j] - prefix_sum[i] <= end:
        #             counter += 1
        
        # return counter

        # 上面的解法会超时,

41 · 最大子数组

给定一个整数数组,找到一个具有最大和的子数组,返回其最大和。
每个子数组的数字在数组中的位置应该是连续的。

import sys
class Solution:
    """
    @param nums: A list of integers
    @return: A integer indicate the sum of max subarray
    """
    def maxSubArray(self, nums):
        # write your code here
        # 先参考答案中的前缀和思路来做
        # prefix_sum表示前i个数的和
        # max_sum表示最大的子数组和
        # min_sum表示前i个数中最小的前缀和
        # 遍历每一个前缀和,
        # 打擂台得到max_sum和min_sum
        max_sum, min_sum = -sys.maxsize, 0
        prefix_sum = 0
        for num in nums:
            prefix_sum += num
            max_sum = max(max_sum, prefix_sum - min_sum)
            min_sum = min(min_sum, prefix_sum)

        return max_sum

二刷,需要三刷

class Solution:
    """
    @param nums: A list of integers
    @return: A integer indicate the sum of max subarray
    """
    def maxSubArray(self, nums):
        # write your code here
        # 最大子数组的题目有很多,
        # 这是比较基础的一个
        # 再做一遍
        # 动规的思想
        # 遍历数组,求以nums[i]为结尾的子数组的最大和
        # 那就只需要记录这之前的最小前缀和即可
        # prefix_sum记录前i个数的和,
        # max_sum记录全局最大值,min_sum记录前i个数中0-k的最小值
        if len(nums) == 0:
            return 0
            
        prefix_sum = 0
        import sys
        max_sum, min_sum = -sys.maxsize, 0
        for num in nums:
            prefix_sum += num
            max_sum = max(max_sum, prefix_sum - min_sum)
            min_sum = min(min_sum, prefix_sum)

        return max_sum

620 · 最大子数组 IV

给定一个整数数组,找到长度大于或等于 k 的连续子序列使它们的和最大,返回这个最大的和,如果数组中少于k个元素则返回 0

确保返回结果为整型
k > 0

class Solution:
    """
    @param nums: an array of integer
    @param k: an integer
    @return: the largest sum
    """
    def maxSubarray4(self, nums, k):
        # write your code here
        # 运用前缀和思想
        # 应该用动规会时间复杂度好一些,这里先不用
        if len(nums) < k:
            return 0
            
        prefix_sum = [0]
        for i in range(1, len(nums) + 1):
            prefix_sum.append(prefix_sum[i - 1] + nums[i - 1])

        # 子数组长度大于等于k
        import sys
        res = -sys.maxsize

        for i in range(len(nums) - k + 1):
            for j in range(i + k - 1, len(nums)):
                res = max(res, prefix_sum[j + 1] - prefix_sum[i])

        return res 

42 · 最大子数组 II

给定一个整数数组,找出两个 不重叠 子数组使得它们的和最大。
每个子数组的数字在数组中的位置应该是连续的。
返回最大的和。

子数组最少包含一个数

class Solution:
    """
    @param: nums: A list of integers
    @return: An integer denotes the sum of max two non-overlapping subarrays
    """
    def maxTwoSubArrays(self, nums):
    #     # write your code here
    #     # 因为两个子数组是不重叠的
    #     # 所以必定是在某一个位置的两边
    #     # left[i]记录0-i数组的最大子数组
    #     # right[i]记录i+1到n-1数组的最大子数组
    #     # 这样就转化为了求数组的最大子数组问题,41题
    #     import sys
    #     res = -sys.maxsize
    #     for i in range(len(nums)):
    #         left = self.maxSubArray(nums[:i + 1])
    #         right = self.maxSubArray(nums[i + 1:])
    #         res = max(res, left + right)

    #     return res 

    # def maxSubArray(self, nums):
    #     prefix_sum = 0
    #     import sys
    #     max_sum, min_sum = -sys.maxsize, 0
    #     for num in nums:
    #         prefix_sum += num
    #         max_sum = max(max_sum, prefix_sum - min_sum)
    #         min_sum = min(min_sum, prefix_sum)

    #     return max_sum 

    # 上述解法的时间复杂度是O(n^2),会超时
    # 怎么优化到O(n)呢?
    # 还是转化为41题的解法。但是,
    # 不嵌套求,分别求出到0到i数组的最大子数组
    # i到n-1数组的最大子数组
        prefix_sum = 0  # 记录前缀和
        import sys
        max_sum, min_sum = -sys.maxsize, 0
        left_max = [0] * len(nums)  # 记录0到i数组的最大子数组和
        for i in range(len(nums)):
            prefix_sum += nums[i]
            # prefix_sum - min_sum表示以nums[i]为结尾的子数组的最大和
            max_sum = max(max_sum, prefix_sum - min_sum)
            min_sum = min(min_sum, prefix_sum)
            left_max[i] = max_sum

        prefix_sum = 0
        max_sum, min_sum = -sys.maxsize, 0
        right_max = [0] * len(nums)  # 记录i到n - 1数组的最大子数组和
        for i in range(len(nums) - 1, -1, -1):
            prefix_sum += nums[i]
            # prefix_sum - min_sum表示以nums[i]为起点的子数组的最大和
            max_sum = max(max_sum, prefix_sum - min_sum)
            min_sum = min(min_sum, prefix_sum)
            right_max[i] = max_sum
        
        res = -sys.maxsize
        for i in range(len(nums) - 1):
            res = max(res, left_max[i] + right_max[i + 1])

        return res 

45 · 最大子数组差

给定一个整数数组,找出两个不重叠的子数组A和B,使两个子数组和的差的绝对值|SUM(A) - SUM(B)|∣SUM(A)−SUM(B)∣最大。返回这个最大的差值。
子数组最少包含一个数

class Solution:
    """
    @param nums: A list of integers
    @return: An integer indicate the value of maximum difference between two substrings
    """
    def maxDiffSubArrays(self, nums):
        # write your code here
        # 因为两个子数组不重叠,所以肯定一个在左边,一个在右边
        # 参考两个最大子数组和的问题
        # 枚举每个数,找到它左边的最大子数组、最小子数组
        # 它右边的最大子数组,最小子数组
        # 打擂台获得最大的子数组差值
        # if len(nums) == 2:
        #     return abs(nums[0] - nums[1])

        max_diff = 0
        for i in range(len(nums) - 1):
            leftMaxSubArray = self.maxSubArray(nums[:i + 1])
            leftMinAubArray = self.minSubArray(nums[:i + 1])
            rightMaxAubArray = self.maxSubArray(nums[i + 1:])
            rightMinSubArray = self.minSubArray(nums[i + 1:])
            max_diff = max(max_diff, \
            abs(leftMaxSubArray - rightMinSubArray), abs(leftMinAubArray - rightMaxAubArray))

        return max_diff

    def maxSubArray(self, nums):
        prefix_sum = 0
        import sys
        max_sum, min_sum = -sys.maxsize, 0
        for num in nums:
            prefix_sum += num
            max_sum = max(max_sum, prefix_sum - min_sum)
            min_sum = min(min_sum, prefix_sum)

        return max_sum

    def minSubArray(self, nums):
        # 用动规来做吧

        dp = [0] * len(nums)
        dp[0] = nums[0]
        for i in range(1, len(nums)):
            dp[i] = min(dp[i - 1] + nums[i], nums[i])
        

        return min(dp)

二刷,一刷的解法会超时

还是会超时。。。

class Solution:
    """
    @param nums: A list of integers
    @return: An integer indicate the value of maximum difference between two substrings
    """
    def maxDiffSubArrays(self, nums):
        # write your code here
        # 比较典型的动规题目
        # 因为两个子数组不重叠,在分割线两边
        # 采用枚举分割线的方法
        # 维护4个数组,max1, min1, max2, min2
        # 分别表示截至到nums[i]且包含nums[i]最大子数组,最小子数组
        # 以nums[i]为起点的最大子数组,最小子数组
        import sys
        max1 = [-sys.maxsize] * len(nums)
        min1 = [sys.maxsize] * len(nums)
        max1[0] = nums[0]
        min1[0] = nums[0]
        forward = [(0, 0)] * len(nums)
        forward[0] = (nums[0], nums[0])
        # prefix_sum = n

        for i in range(1, len(nums)):
            # prefix_sum += nums[i]
            max1[i] = max(max1[i - 1] + nums[i], nums[i])
            min1[i] = min(min1[i - 1] + nums[i], nums[i])
            forward[i] = (max(max1), min(min1))

        max2 = [-sys.maxsize] * len(nums)
        min2 = [sys.maxsize] * len(nums)
        max2[-1] = nums[-1]
        min2[-1] = nums[-1]
        backward = [(0, 0)] * len(nums)
        backward[-1] = (nums[-1], nums[-1])

        for i in range(len(nums) -2, -1, -1):
            max2[i] = max(nums[i], nums[i] + max2[i + 1])
            min2[i] = min(nums[i], nums[i] + min2[i + 1])
            backward[i] = (max(max2), min(min2))

        import sys
        res = -sys.maxsize
        for i in range(0, len(nums) - 1):
            res = max(res, \
            abs(forward[i][0] - backward[i + 1][1]), abs(forward[i][1] - backward[i + 1][0]))

        return res 

191 · 乘积最大子序列

找出一个序列中乘积最大的连续子序列(至少包含一个数)。

数组长度不超过20000
乘积最大的子序列的积,小于2147483647

class Solution:
    """
    @param nums: An array of integers
    @return: An integer
    """
    def maxProduct(self, nums):
        # write your code here
        # 典型的动规题目
        # 有正有负,需要维护两个数组
        # dp1[i]表示计算到nums[i]时的最大值
        # dp2[i]表示计算到nums[i]时的最小值
        # dp1[i] = dp1[i-1] * nums[i] if nums[i] > 0 else \
        # dp2[i-1] * nums[i]
        import sys
        dp1 = [-sys.maxsize] * len(nums)
        dp2 = [sys.maxsize] * len(nums)
        dp1[0] = nums[0]
        dp2[0] = nums[0]

        for i in range(1, len(nums)):
            dp1[i] = max(dp1[i - 1] * nums[i], dp2[i - 1] * nums[i], nums[i])
            dp2[i] = min(dp1[i - 1] * nums[i], dp2[i - 1] * nums[i], nums[i])

        return max(dp1)

471 · 最高频的K个单词

给定一个单词列表和一个整数k,求出这个列表中出现频次最高的K个单词。
你需要按照单词的词频排序后输出,越高频的词排在越前面。如果两个单词出现的次数相同,则词典序小的排在前面。

class Solution:
    """
    @param words: an array of string
    @param k: An integer
    @return: an array of string
    """
    def topKFrequentWords(self, words, k):
        # write your code here
        # 先统计每个单词的出现频次
        # 将单词按照频次从高到底和词典序排列
        hash = {}
        for word in words:
            if word not in hash:
                hash[word] = 1
            else:
                hash[word] += 1
        
        p = []
        for key, value in hash.items():
            p.append((value, key))
        import functools
        p.sort(key=functools.cmp_to_key(self.cmp))
        res = []
        for i in range(k):
            res.append(p[i][1])

        return res

    def cmp(self, a, b):
        if a[0] > b[0]:
            return -1
        elif a[0] == b[0] and a[1] < b[1]:
            return -1
        elif a[0] == b[0] and a[1] == b[1]:
            return 0
        else:
            return 1

526 · 负载均衡器

为网站实现一个负载均衡器,提供如下的 3 个功能:

添加一台新的服务器到整个集群中 => add(server_id)。
从集群中删除一个服务器 => remove(server_id)。
在集群中随机(等概率)选择一个有效的服务器 => pick()。
最开始时,集群中一台服务器都没有。每次 pick() 调用你需要在集群中随机返回一个 server_id。

class LoadBalancer:
    def __init__(self):
        # do intialization if necessary
        # 用列表存储id,用哈希表存储id在列表中对应的index
        # add时,在列表中添加id,在哈希表中添加对应的index
        # remove时,得到需要remove的id的index,和列表中最后一个id互换
        # 同时哈希表中的index也相应修改
        # pick时,根据id个数,随机返回一个数,就是index
        self.ids = []
        self.id2index = {}

    """
    @param: server_id: add a new server to the cluster
    @return: nothing
    """
    def add(self, server_id):
        # write your code here
        self.ids.append(server_id)
        self.id2index[server_id] = len(self.ids) - 1

    """
    @param: server_id: server_id remove a bad server from the cluster
    @return: nothing
    """
    def remove(self, server_id):
        # write your code here
        index = self.id2index[server_id]
        self.id2index[self.ids[-1]] = index
        self.ids[index], self.ids[-1] = self.ids[-1], self.ids[index]
        self.ids.pop()

    """
    @return: pick a server in the cluster randomly with equal probability
    """
    def pick(self):
        # write your code here
        import random
        return self.ids[random.randint(0, len(self.ids) - 1)]

124 · 最长连续序列

给定一个未排序的整数数组,找出最长连续序列的长度。
要求你的算法复杂度为O(n)

class Solution:
    """
    @param num: A list of integers
    @return: An integer
    """
    def longestConsecutive(self, num):
        # write your code here
        # 遍历数组中的每一个数,找到这个数的最长连续序列
        # 有一个技巧是已经形成连续序列的数不用再判断了
        num_set = set(num)
        maxlength = 1
        for x in num:
            length = 0
            if x in num_set:
                length += 1
                num_set.remove(x)
                right = x + 1
                left = x - 1
                while right in num_set:
                    length += 1
                    num_set.remove(right)
                    right += 1
                while left in num_set:
                    length += 1
                    num_set.remove(left)
                    left -= 1
                if maxlength < length:
                    maxlength = length

        return maxlength

149 · 买卖股票的最佳时机

假设有一个数组,它的第i个元素是一支给定的股票在第i天的价格。如果你最多只允许完成一次交易(例如,一次买卖股票),设计一个算法来找出最大利润。

class Solution:
    """
    @param prices: Given an integer array
    @return: Maximum profit
    """
    def maxProfit(self, prices):
        # write your code here
        # 刚开始是没有思路的,看了答案后觉得也很简单
        # 不过答案的思路也很巧妙
        # 遍历数据,记录股票低点,打擂台记录盈利
        import sys
        low = sys.maxsize
        total = 0
        for x in prices:
            if x - low > total:
                total = x - low
            if x < low:
                low = x 

        return total

150 · 买卖股票的最佳时机 II

给定一个数组 prices 表示一支股票每天的价格.

交易次数不限, 不过你不能同时参与多个交易 (也就是说, 如果你已经持有这支股票, 在再次购买之前, 你必须先卖掉它).

设计一个算法求出最大的利润.

class Solution:
    """
    @param prices: Given an integer array
    @return: Maximum profit
    """
    def maxProfit(self, prices):
        # write your code here
        # 想利润最大的话,就低买高卖
        # 遍历价格,如果高于low,并后一天是降低的,就卖出
        total_profit = 0
        import sys
        low = sys.maxsize
        for i in range(len(prices)):
            if prices[i] > low:
                if i + 1 >= len(prices) or (i + 1 < len(prices) and prices[i + 1] < prices[i]):
                    total_profit += prices[i] - low
                    low = prices[i + 1] if i + 1 < len(prices) else low
            if prices[i] < low:
                low = prices[i]

        return total_profit

151 · 买卖股票的最佳时机 III

假设你有一个数组,它的第i个元素是一支给定的股票在第i天的价格。设计一个算法来找到最大的利润。你最多可以完成两笔交易。

你不可以同时参与多笔交易(你必须在再次购买前出售掉之前的股票)

class Solution:
    """
    @param prices: Given an integer array
    @return: Maximum profit
    """
    def maxProfit(self, prices):
        # write your code here
        # 收益最大:最低点买入,最高点卖出
        # 也是分成两部分,第一次交易的部分,第二次交易的部分
        # 这个和找两个不重叠子数组最大和类似
        # dp1[i]表示截止到第i天第一次交易结束的最大收益
        # dp2[i]表示第i天以后进行第二次交易的最大收益
        # 第一次交易:初始在第0天买入,从第一天顺序遍历
        # 第i天价格比最低点低,重新在当天买入
        # 第i天价格比最低点高,假设在当天卖出,计算利润
        if len(prices) == 0:
            return 0
            
        dp1 = [0] * len(prices)
        min_price = prices[0]
        for i in range(1, len(prices)):
            min_price = min(min_price, prices[i])
            dp1[i] = max(dp1[i - 1], prices[i] - min_price)

        # 第二次交易:初始最后一天卖出,从倒数第二天倒序遍历
        # 第i天价格最高点高,重新在这天卖出
        # 第i天价格比最高点低,在这天买入,在最高点那天卖出
        dp2 = [0] * len(prices)
        max_price = prices[-1]
        for i in range(len(prices) - 2, -1, -1):
            max_price = max(max_price, prices[i])
            dp2[i] = max(dp2[i + 1], max_price - prices[i])

        import sys
        res = -sys.maxsize
        for i in range(len(prices)):
            res = max(res, dp1[i] + dp2[i])

        return res 

551 · 嵌套列表的加权和

给一个嵌套的整数列表, 返回列表中所有整数由它们的深度加权后的总和. 每一个元素可能是一个整数或一个列表(其元素也可能是整数或列表)

"""
This is the interface that allows for creating nested lists.
You should not implement it, or speculate about its implementation

class NestedInteger(object):
    def isInteger(self):
        # @return {boolean} True if this NestedInteger holds a single integer,
        # rather than a nested list.

    def getInteger(self):
        # @return {int} the single integer that this NestedInteger holds,
        # if it holds a single integer
        # Return None if this NestedInteger holds a nested list

    def getList(self):
        # @return {NestedInteger[]} the nested list that this NestedInteger holds,
        # if it holds a nested list
        # Return None if this NestedInteger holds a single integer
"""


class Solution(object):
    # @param {NestedInteger[]} nestedList a list of NestedInteger Object
    # @return {int} an integer
    def depthSum(self, nestedList):
        # Write your code here
        res = 0
        # depth = 1
        stack = []
        for elem in nestedList:
            stack.append((elem, 1))
        
        while stack:
            elem, depth = stack.pop()
            if elem.isInteger():
                res += elem.getInteger() * depth
            else:
                for elem in elem.getList():
                    stack.append((elem, depth + 1))

        return res 

528 · 摊平嵌套的列表

给你一个嵌套的列表,实现一个迭代器将其摊平。
一个列表的每个元素可能是整数或者一个列表。

你不需要实现删除方法

"""
This is the interface that allows for creating nested lists.
You should not implement it, or speculate about its implementation

class NestedInteger(object):
    def isInteger(self):
        # @return {boolean} True if this NestedInteger holds a single integer,
        # rather than a nested list.

    def getInteger(self):
        # @return {int} the single integer that this NestedInteger holds,
        # if it holds a single integer
        # Return None if this NestedInteger holds a nested list

    def getList(self):
        # @return {NestedInteger[]} the nested list that this NestedInteger holds,
        # if it holds a nested list
        # Return None if this NestedInteger holds a single integer
"""

class NestedIterator(object):

    def __init__(self, nestedList):
        # Initialize your data structure here.
        self.nestedList = nestedList
        self.next_elem = None
        self.stack = []
        for elem in reversed(self.nestedList):
            self.stack.append(elem)
        
    # @return {int} the next element in the iteration
    def next(self):
        # Write your code here
        return self.next_elem
        
    # @return {boolean} true if the iteration has more element or false
    def hasNext(self):
        # Write your code here
        while self.stack:
            top = self.stack.pop()
            if top.isInteger():
                self.next_elem = top.getInteger()
                return True 
            else:
                for elem in reversed(top.getList()):
                    self.stack.append(elem)

        return False 

# Your NestedIterator object will be instantiated and called as such:
# i, v = NestedIterator(nestedList), []
# while i.hasNext(): v.append(i.next())

601 · 摊平二维向量

设计一个迭代器来实现摊平二维向量的功能

class Vector2D(object):

    # @param vec2d {List[List[int]]}
    def __init__(self, vec2d):
        # Initialize your data structure here
        self.stack = []
        self.next_elem = None
        for elem in reversed(vec2d):
            self.stack.append(elem)

    # @return {int} a next element
    def next(self):
        # Write your code here
        return self.next_elem
        
    # @return {boolean} true if it has next element
    # or false
    def hasNext(self):
        # Write your code here
        while self.stack:
            top = self.stack.pop()
            if isinstance(top, int):
                self.next_elem = top
                return True 
            self.stack.extend(top[::-1])

        return False 

# Your Vector2D object will be instantiated and called as such:
# i, v = Vector2D(vec2d), []
# while i.hasNext(): v.append(i.next())

575 · 字符串解码

给出一个表达式 s,此表达式包括数字,字母以及方括号。在方括号前的数字表示方括号内容的重复次数(括号内的内容可以是字符串或另一个表达式),请将这个表达式展开成一个字符串。

数字只能出现在“[]”前面。

class Solution:
    """
    @param s: an expression includes numbers, letters and brackets
    @return: a string
    """
    def expressionExpand(self, s):
        # write your code here
        # 把所有字符一个一个放到stack里,直到遇到]
        # 找到]前面的字符串和重复次数,decode后
        # 再放到stack里
        stack = []
        for c in s:
            if c != ']':
                stack.append(c)
                continue 
            
            strs = []
            while stack and stack[-1] != '[':
                strs.append(stack.pop())
            stack.pop()  # 去掉[
            
            repeats = 0
            base = 1
            while stack and stack[-1].isdigit():
                repeats += (ord(stack.pop()) - ord('0')) * base 
                base *= 10
            
            stack.extend(strs[::-1] * repeats)

        return ''.join(stack)

654 · 稀疏矩阵乘法

给定两个 稀疏矩阵 A 和 B,返回AB的结果。
您可以假设A的列数等于B的行数。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值