Leetcode刷题1

一、数组

双指针,注意慢指针更新

二、链表

1.设置虚拟头结点(哨兵)dummy = ListNode(next=head)

2.滚动向前,两个指针分别指向node1 node2节点。然后每次

node1.next = node2.next node1 = node1.next,此时node1已更新到第三个node
node2.next = node1.next node2 = node2.next,此时node2已更新到第四个node
循环以上操作,完成滚动更新,最终将node1.next指向node2开始位置,即可。

3.链表插新值:cur.next = ListNode(val)

24. 两两交换链表中的节点

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def swapPairs(self, head: Optional[ListNode]) -> Optional[ListNode]:
        if head is None or head.next is None  :
            return head

        pre = dummy = ListNode(next=head)
        while pre.next and pre.next.next:
            first,second = pre.next,pre.next.next
            pre.next,first.next = second,second.next
            second.next = first
            pre = pre.next.next
        return dummy.next

160. 相交链表

给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 null 。

图示两个链表在节点 c1 开始相交

题目数据 保证 整个链式结构中不存在环。

注意,函数返回结果后,链表必须 保持其原始结构 。

自定义评测:

评测系统 的输入如下(你设计的程序 不适用 此输入):

  • intersectVal - 相交的起始节点的值。如果不存在相交节点,这一值为 0
  • listA - 第一个链表
  • listB - 第二个链表
  • skipA - 在 listA 中(从头节点开始)跳到交叉节点的节点数
  • skipB - 在 listB 中(从头节点开始)跳到交叉节点的节点数

评测系统将根据这些输入创建链式数据结构,并将两个头节点 headA 和 headB 传递给你的程序。如果程序能够正确返回相交节点,那么你的解决方案将被 视作正确答案 。

 

解决idea

class Solution:
    def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> Optional[ListNode]: 
        A, B = headA, headB
        while A != B:
            A = A.next if A else headB
            B = B.next if B else headA
        return A

92. 反转链表 II

给你单链表的头指针 head 和两个整数 left 和 right ,其中 left <= right 。请你反转从位置 left 到位置 right 的链表节点,返回 反转后的链表 。

示例 1:

输入:head = [1,2,3,4,5], left = 2, right = 4 
输出:[1,4,3,2,5]
class Solution:
    def reverseBetween(self, head: Optional[ListNode], left: int, right: int) -> Optional[ListNode]:
        p0 = dummy = ListNode(next=head)
        for _ in range(left-1):
            p0 = p0.next
        
        pre = None
        cur = p0.next

        for _ in range(right-left+1):
            nxt = cur.next
            cur.next = pre
            pre = cur
            cur = nxt

        p0.next.next = cur
        p0.next = pre
        return dummy.next

最后循环结束后,p0.next指向2,再next(2.next)是指把尾巴续上 

p0.next就是指向翻转后链表的pre。

三、栈

Python 中的栈直接以列表为主,增加使用append(),出栈为pop()

实现栈的思路分析:

  1. 使用数组来记性模拟栈
  2. 定义一个top来代表栈顶,初始化-1
  3. 入栈的操作,当有数据加入的时候,top++,stack[top] = data
  4. 出栈的操作,value = stack[top] 

最小栈

155. 最小栈

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

实现 MinStack 类:

  • MinStack() 初始化堆栈对象。
  • void push(int val) 将元素val推入堆栈。
  • void pop() 删除堆栈顶部的元素。
  • int top() 获取堆栈顶部的元素。
  • int getMin() 获取堆栈中的最小元素。
class MinStack:
    def __init__(self):
        self.stack = []
        self.min_stack = []
    def push(self, x: int) -> None:
        self.stack.append(x)
        if not self.min_stack or x <= self.min_stack[-1]: 
            self.min_stack.append(x)
    def pop(self) -> None:
        if self.stack.pop() == self.min_stack[-1]:
            self.min_stack.pop()
    def top(self) -> int:
        return self.stack[-1]
    def getMin(self) -> int:
        return self.min_stack[-1]

 题目要求在常数时间内获得栈中的最小值,因此不能在 getMin() 的时候再去计算最小值,最好应该在 push 或者 pop 的时候就已经计算好了当前栈中的最小值。因此可以用一个栈,这个栈同时保存的是每个数字 x 进栈的时候的值 与 插入该值后的栈内最小值。即每次新元素 x 入栈的时候保存一个元组:(当前值 x,栈内最小值)

这个元组是一个整体,同时进栈和出栈。即栈顶同时有值和栈内最小值,top()函数是获取栈顶的当前值,即栈顶元组的第一个值; getMin() 函数是获取栈内最小值,即栈顶元组的第二个值;pop() 函数时删除栈顶的元组。

每次新元素入栈时,要求新的栈内最小值:比较当前新插入元素 x 和 当前栈内最小值(即栈顶元组的第二个值)的大小。

新元素入栈:当栈为空,直接保存元组 (x, x);当栈不空,保存元组 (x, min(此前栈内最小值, x)))
出栈:删除栈顶的元组。

class MinStack(object):

    def __init__(self):
        self.stack = []
        
    def push(self, x):
        if not self.stack:
            self.stack.append((x, x))
        else:
            self.stack.append((x, min(x, self.stack[-1][1])))
        
    def pop(self):
        self.stack.pop()
        

    def top(self):
        return self.stack[-1][0]
        

    def getMin(self):
        return self.stack[-1][1]

32. 最长有效括号

给你一个只包含 '(' 和 ')' 的字符串,找出最长有效(格式正确且连续)括号子串的长度。

class Solution:
    def longestValidParentheses(self, s: str) -> int:
        if not s: return 0

        stack = []
        ans = 0
        for i in range(len(s)):
            # 入栈条件
            if not stack or s[i] == '(' or s[stack[-1]] == ')':
                stack.append(i)     # 下标入栈
            else:
                # 计算结果
                stack.pop()
                ans = max(ans, i - (stack[-1] if stack else -1))
        return ans

224. 基本计算器

给你一个字符串表达式 s ,请你实现一个基本计算器来计算并返回它的值。

注意:不允许使用任何将字符串作为数学表达式计算的内置函数,比如 eval() 。

 preSign的作用:判断某个数的正负(括号内的求和结果,也可以看作是某个数)

什么时候数字入栈:

1.遇到")",弹出栈顶数字做求和运算后,再入栈

2.遇到"+"或"-",把当前数字加入栈顶

3.遍历到最后一位,无论是什么字符(空格,右括号或数字),当前数字num都要入栈

注意一:数字入栈的时候一定要根据preSign判断正负后,再入栈

注意二:数字入栈之后,需要把num重置为0(对于情况3而言可以不重置)

"+"或"-"符号何时会出现:

1.在左括号前:储存该符号至preSign中,且需要入栈,当遇到右括号时,将栈顶至该符号后的数字进行求和计算

2.在数字前:储存该符号至preSign中,

何时更新preSign:使用后立即更新

1.遇到左括号,把该preSign加入栈中,待会儿遇到右括号的时候会用到(这等价于已经被使用了),更新为默认的"+"

2.遇到下一个"+"或"-",此时需要把num加入栈中,preSign被使用后,更新

class Solution:
    def calculate(self, s: str) -> int:
        preSign = "+"
        stack = list()
        num = 0
        for i, ch in enumerate(s):
            if (ch == " " and i != len(s)-1):
                continue
            elif ch == "(":
                stack.append(preSign)
                preSign = "+"                                   # 更新preSign情况1
            elif ch == ")":
                cur_sum = (num if preSign == "+" else -num)     # 数字入栈情况1
                while(type(stack[-1]) is int):  # 对栈顶元素做求和
                    cur_sum += stack.pop()
                stack.append(cur_sum if stack.pop() == "+" else -cur_sum)
                num = 0                                         # 重置num情况1
            elif ch.isdigit():
                num = num*10 + int(ch)
            elif ch == "+" or ch == "-":                        
                stack.append(num if preSign == "+" else -num)   # 数字入栈情况2
                num = 0                                         # 重置num情况2
                preSign = ch                                    # 更新preSign情况2
        stack.append(num if preSign == "+" else -num)           # 数字入栈情况3
        return sum(stack)

394. 字符串解码

给定一个经过编码的字符串,返回它解码后的字符串。

编码规则为: k[encoded_string],表示其中方括号内部的 encoded_string 正好重复 k 次。注意 k 保证为正整数。

你可以认为输入字符串总是有效的;输入字符串中没有额外的空格,且输入的方括号总是符合格式要求的。

此外,你可以认为原始数据不包含数字,所有的数字只表示重复的次数 k ,例如不会出现像 3a 或 2[4] 的输入。

示例 1:输入:s = "3[a]2[bc]"                         输出:"aaabcbc"
示例 2:输入:s = "3[a2[c]]"                           输出:"accaccacc"
示例 3:输入:s = "2[abc]3[cd]ef"                  输出:"abcabccdcdcdef"
示例 4:输入:s = "abc3[cd]xyz"                    输出:"abccdcdcdxyz"

算法流程:

1.构建辅助栈 stack, 遍历字符串 s 中每个字符 c;

  • 当 c 为数字时,将数字字符转化为数字 multi,用于后续倍数计算;
  • 当 c 为字母时,在 res 尾部添加 c;
  • 当 c 为 [ 时,将当前 multi 和 res 入栈,并分别置空置 0:
    • 记录此 [ 前的临时结果 res 至栈,用于发现对应 ] 后的拼接操作;
    • 记录此 [ 前的倍数 multi 至栈,用于发现对应 ] 后,获取 multi × [...] 字符串。
    • 进入到新 [ 后,res 和 multi 重新记录。
  • 当 c 为 ] 时,stack 出栈,拼接字符串 res = last_res + cur_multi * res,其中:
    • last_res是上个 [ 到当前 [ 的字符串,例如 "3[a2[c]]" 中的 a;
    • cur_multi是当前 [ 到 ] 内字符串的重复倍数,例如 "3[a2[c]]" 中的 2。

2.返回字符串 res。

class Solution:
    def decodeString(self, s: str) -> str:
        stack, res, multi = [], "", 0
        for c in s:
            if c == '[':
                stack.append([multi, res])
                res, multi = "", 0
            elif c == ']':
                cur_multi, last_res = stack.pop()
                res = last_res + cur_multi * res
            elif '0' <= c <= '9':
                multi = multi * 10 + int(c)            
            else:
                res += c
        return res

四、单调栈 

42. 接雨水

给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。

输入:height = [0,1,0,2,1,0,1,3,2,1,2,1]
输出:6
解释:上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。

 每个位置能接的水取决你他左右两边的高,因此找出它左右两边的最大值,然后减去它本身的高度即可知道当前位置可以盛多少水。

算法流程:首先分别计算每个位置的前后高度最大值,之后计算获取每个位置的前后高度中的最小值,然后减去当前位置高度就可以得到当前位置的盛水量

class Solution:
    def trap(self, height: List[int]) -> int:
        n = len(height)
        pre_max = [0] * n
        pre_max[0] = height[0]
        for i in range(1, n):
            pre_max[i] = max(pre_max[i - 1], height[i])

        suf_max = [0] * n
        suf_max[-1] = height[-1]
        for i in range(n - 2, -1, -1):
            suf_max[i] = max(suf_max[i + 1], height[i])

        ans = 0
        for h, pre, suf in zip(height, pre_max, suf_max):
            ans += min(pre, suf) - h
        return ans

84. 柱状图中最大的矩形

给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。

求在该柱状图中,能够勾勒出来的矩形的最大面积。

输入:heights = [2,1,5,6,2,3]      输出:10

依次找出当前位置左右的一个小于它的值,然后 

class Solution:
    def largestRectangleArea(self, heights: List[int]) -> int:
        res = 0
        n = len(heights)
        for i in range(n):
            left_i = i
            right_i = i
            while left_i >= 0 and heights[left_i] >= heights[i]:
                left_i -= 1
            while right_i < n and heights[right_i] >= heights[i]:
                right_i += 1
            res = max(res, (right_i - left_i - 1) * heights[i])
        return res

'''单调栈'''
class Solution:
    def largestRectangleArea(self, heights: List[int]) -> int:
        stack = []
        heights = [0] + heights + [0]
        res = 0
        for i in range(len(heights)):
            #print(stack)
            while stack and heights[stack[-1]] > heights[i]:
                tmp = stack.pop()
                res = max(res, (i - stack[-1] - 1) * heights[tmp])
            stack.append(i)
        return res

739. 每日温度

给定一个整数数组 temperatures ,表示每天的温度,返回一个数组 answer ,其中 answer[i] 是指对于第 i 天,下一个更高温度出现在几天后。如果气温在这之后都不会升高,请在该位置用 0 来代替。

输入: temperatures= [73,74,75,71,69,72,76,73]        输出: [1,1,4,2,1,1,0,0]

当stack为空时,运行stack.append(idx),则stack=[0];然后仅当遍历元素 t 小于stack顶端的值时append进去,这会导致stack中idx代表的元素是单调递减的,如果此时遍历到一个 t,大于stack顶端的值,那这个t就是离stack顶端值最近的那个大值。然后pop出来,还是要注意stack.pop出来的是idx,这样res这一串0里对应位置的0就会被替换成应有的值。                    再进入while循环判断t和stack.pop后的新的顶端值哪个大。

class Solution:
    def dailyTemperatures(self, T: List[int]) -> List[int]:
        l = len(T)
        stack = []    
        res = [0] * l   

        for idx, t in enumerate(T):  
            while stack and t > T[stack[-1]]:  
                res[stack.pop()] = idx-stack[-1] 
            stack.append(idx)
        return res

五、队列、优先队列

栈实现队列

232. 用栈实现队列

请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(pushpoppeekempty):

实现 MyQueue 类:

  • void push(int x) 将元素 x 推到队列的末尾
  • int pop() 从队列的开头移除并返回元素
  • int peek() 返回队列开头的元素
  • boolean empty() 如果队列为空,返回 true ;否则,返回 false

说明:

  • 你 只能 使用标准的栈操作 —— 也就是只有 push to toppeek/pop from topsize, 和 is empty 操作是合法的。
  • 你所使用的语言也许不支持栈。你可以使用 list 或者 deque(双端队列)来模拟一个栈,只要是标准的栈操作即可。
​class MyQueue(object):

    def __init__(self):
        self.stack1 = []  #  输入栈
        self.stack2 = []  #  输出栈

    def push(self, x):
        self.stack1.append(x) # 入栈

    def pop(self):
        if not self.stack2:
            while self.stack1:
                self.stack2.append(self.stack1.pop())
        return self.stack2.pop()

    def peek(self):
        if not self.stack2:
            while self.stack1:
                self.stack2.append(self.stack1.pop())
        return self.stack2[-1]

    def empty(self):
        return not self.stack1 and not self.stack2

​

双端队列

641. 设计循环双端队列

设计实现双端队列。

实现 MyCircularDeque 类:

  • MyCircularDeque(int k) :构造函数,双端队列最大为 k 。
  • boolean insertFront():将一个元素添加到双端队列头部。 如果操作成功返回 true ,否则返回 false 。
  • boolean insertLast() :将一个元素添加到双端队列尾部。如果操作成功返回 true ,否则返回 false 。
  • boolean deleteFront() :从双端队列头部删除一个元素。 如果操作成功返回 true ,否则返回 false 。
  • boolean deleteLast() :从双端队列尾部删除一个元素。如果操作成功返回 true ,否则返回 false 。
  • int getFront() ):从双端队列头部获得一个元素。如果双端队列为空,返回 -1 。
  • int getRear() :获得双端队列的最后一个元素。 如果双端队列为空,返回 -1 。
  • boolean isEmpty() :若双端队列为空,则返回 true ,否则返回 false  。
  • boolean isFull() :若双端队列满了,则返回 true ,否则返回 false 。

链表 

class MyCircularDeque:

    def __init__(self, k: int):
        self.k = k
        self.len = 0
        self.head = LinkedNode(-1)
        self.head.next = self.head.prev = self.head

    def insertFront(self, value: int) -> bool:
        if self.len == self.k:
            return False
        self.head.next = LinkedNode(value, self.head, self.head.next)
        self.head.next.next.prev = self.head.next # 新建的节点成为了头节点的下一个节点,而原先的头节点成为了新建节点的前一个节点,从而完成了节点的插入操作。
        self.len += 1
        return True

    def insertLast(self, value: int) -> bool:
        if self.len == self.k:
            return False
        self.head.prev = LinkedNode(value, self.head.prev, self.head)
        self.head.prev.prev.next = self.head.prev  # 新建的节点成为了头节点的前一个节点,而原先的头节点成为了新建节点的后一个节点,从而完成了节点的插入操作。
        self.len += 1
        return True

    def deleteFront(self) -> bool:
        if not self.len:
            return False
        self.head.next = self.head.next.next
        self.head.next.prev = self.head
        self.len -= 1
        return True

    def deleteLast(self) -> bool:
        if not self.len:
            return False
        self.head.prev = self.head.prev.prev
        self.head.prev.next = self.head
        self.len -= 1
        return True

    def getFront(self) -> int:
        return -1 if not self.len else self.head.next.val

    def getRear(self) -> int:
        return -1 if not self.len else self.head.prev.val

    def isEmpty(self) -> bool:
        return self.len == 0

    def isFull(self) -> bool:
        return self.len == self.k


# Your MyCircularDeque object will be instantiated and called as such:
# obj = MyCircularDeque(k)
# param_1 = obj.insertFront(value)
# param_2 = obj.insertLast(value)
# param_3 = obj.deleteFront()
# param_4 = obj.deleteLast()
# param_5 = obj.getFront()
# param_6 = obj.getRear()
# param_7 = obj.isEmpty()
# param_8 = obj.isFull()

class LinkedNode:
    def __init__(self, val, prev=None, next=None):
        self.val = val
        self.prev = prev
        self.next = next

列表

class MyCircularDeque:

    def __init__(self, k: int):
        self.lst = list()
        self.k = k


    def insertFront(self, value: int) -> bool:
        if len(self.lst) < self.k:
            self.lst.insert(0, value)
            return True
        return False


    def insertLast(self, value: int) -> bool:
        if len(self.lst) < self.k:
            self.lst.append(value)
            return True
        return False

    def deleteFront(self) -> bool:
        if not self.lst:
            return False
        self.lst.pop(0)
        return True

    def deleteLast(self) -> bool:
        if not self.lst:
            return False
        self.lst.pop(-1)
        return True

    def getFront(self) -> int:
        if not self.lst:
            return -1
        return self.lst[0]

    def getRear(self) -> int:
        if not self.lst:
            return -1
        return self.lst[-1]

    def isEmpty(self) -> bool:
        return len(self.lst) == 0

    def isFull(self) -> bool:
        return len(self.lst) == self.k

六、哈希表和哈希集合 

哈希集合

  • hash = [ ]
  • hash.git(i)   # 查看是否在哈希集合中
  • hash[i] = 1 # 把值加入到哈希集合中

存入哈希集合中

哈希表

  • hash = { }
  • hash[num[i]] = i   #   值:索引

索引 存入哈希表中

res = {}
for a in s:
    if a not in res:
        res[a] = 1
    else:
        res[a] = res[a] + 1
frequency = collections.Counter(s)m # 统计字符个数
        for i, ch in enumerate(s):
            # i 顺序  ch是字符  frequency[ch]次数

七、前缀和 

303. 区域和检索 - 数组不可变

给定一个整数数组  nums,处理以下类型的多个查询:

  1. 计算索引 left 和 right (包含 left 和 right)之间的 nums 元素的  ,其中 left <= right

实现 NumArray 类:

  • NumArray(int[] nums) 使用数组 nums 初始化对象
  • int sumRange(int i, int j) 返回数组 nums 中索引 left 和 right 之间的元素的 总和 ,包含 left 和 right 两点(也就是 nums[left] + nums[left + 1] + ... + nums[right] )
class NumArray:

    def __init__(self, nums: List[int]):
        N = len(nums)
        self.preSum = [0] * (N + 1)
        for i in range(N):
            self.preSum[i + 1] = self.preSum[i] + nums[i]

    def sumRange(self, i: int, j: int) -> int:
        return self.preSum[j + 1] - self.preSum[i]

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

1588. 所有奇数长度子数组的和

给你一个正整数数组 arr ,请你计算所有可能的奇数长度子数组的和。

子数组 定义为原数组中的一个连续子序列。

请你返回 arr 中 所有奇数长度子数组的和 。

# 注:求某段区间和时常用前缀和数组,这里只不过是只求奇数部分,故设k为奇数跨度,分别求1,3,5,…,n的区间和
class Solution:
    def sumOddLengthSubarrays(self, arr: List[int]) -> int:
        nums=[0]+list(accumulate(arr))   # 前缀和数组 accumulate函数对一个序列进行累加操作,并返回一个迭代器。因此,使用list()函数将返回的迭代器转化为列表类型。
        n=len(nums)
        res=0
        k=1   # 奇数跨度:从1开始
        while k<n:
            for i in range(k,n):
                res=res+nums[i]-nums[i-k]   # 求相应的奇数长度数组和并累加
            k=k+2
        return res

560. 和为 K 的子数组

给你一个整数数组 nums 和一个整数 k ,请你统计并返回 该数组中和为 k 的连续子数组的个数 

class Solution:
    def subarraySum(self, nums: List[int], k: int) -> int:
        dic={0:1}
        sums,res=0,0
        for num in nums:
            sums+=num
            res+=dic.get(sums-k,0)
            dic[sums]=dic.get(sums,0)+1
        return res

        #  等价
        # for i in range(len(nums)):
        #     summ += nums[i]
        #     if summ-k in dic.keys():
        #         res += dic[summ-k]
        #     if summ not in dic.keys():
        #         dic[summ] = 1
        #     else:
        #         dic[summ] += 1
        # return res

利用字典存储前缀和以及对应个数。枚举前缀和数组,当枚举到sums[j]时,假设有键值对
sums[j]−k:v,可知存在v个(ai ,j)满足要求,把v加入最终答案即可,并将sums[i]更新到字典当中。

49. 字母异位词分组

给你一个字符串数组,请你将 字母异位词 组合在一起。可以按任意顺序返回结果列表。

字母异位词 是由重新排列源单词的所有字母得到的一个新单词。

输入: strs = ["eat", "tea", "tan", "ate", "nat", "bat"]
输出: [["bat"],["nat","tan"],["ate","eat","tea"]]

class Solution:
    def groupAnagrams(self, strs: List[str]) -> List[List[str]]:
        table = {}
        for s in strs:
            s_ = "".join(sorted(s))
            if s_ not in table:
                table[s_] = [s]
            else:
                table[s_].append(s)
        return list(table.values())
238. 除自身以外数组的乘积

给你一个整数数组 nums,返回 数组 answer ,其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。

题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在  32 位 整数范围内。

不要使用除法,且在 O(n) 时间复杂度内完成此题。

输入: nums = [1,2,3,4]
输出: [24,12,8,6]

原数组:       [1       2       3       4]
左部分的乘积:   1       1      1*2    1*2*3
右部分的乘积: 2*3*4    3*4      4      1
结果:        1*2*3*4  1*3*4   1*2*4  1*2*3*1

 个人理解:当前位置 = 左边乘积*右边乘积。首先res依次计算前n-1项的累乘(左边乘积),然后从最后开始依次取数进行累乘(右边),

class Solution:
    def productExceptSelf(self, nums: [int]) -> [int]:
        res, p, q = [1], 1, 1
        for i in range(len(nums) - 1): # bottom triangle
            p *= nums[i]
            res.append(p) # 等于计算当前数字左边的乘积
        for i in range(len(nums) - 1, 0, -1): # top triangle
            q *= nums[i]  # 从右边依次取数累乘,等于计算当前数字右边乘积
            res[i - 1] *= q  # 当前乘积 = 左边 * 右边
        return res

class Solution:
    def constructArr(self, a: List[int]) -> List[int]:
        b, tmp = [1] * len(a), 1
        for i in range(1, len(a)):
            b[i] = b[i - 1] * a[i - 1] # 下三角
        for i in range(len(a) - 2, -1, -1):
            tmp *= a[i + 1]            # 上三角
            b[i] *= tmp                # 下三角 * 上三角
        return b
304. 二维区域和检索 - 矩阵不可变

给定一个二维矩阵 matrix,以下类型的多个请求:

  • 计算其子矩形范围内元素的总和,该子矩阵的 左上角 为 (row1, col1) ,右下角 为 (row2, col2) 。

实现 NumMatrix 类:

  • NumMatrix(int[][] matrix) 给定整数矩阵 matrix 进行初始化
  • int sumRegion(int row1, int col1, int row2, int col2) 返回 左上角 (row1, col1) 、右下角 (row2, col2) 所描述的子矩阵的元素 总和 。

class NumMatrix:

    def __init__(self, matrix: List[List[int]]):
        if not matrix or not matrix[0]:
            M, N = 0, 0
        else:
            M, N = len(matrix), len(matrix[0])
        self.preSum = [[0] * (N + 1) for _ in range(M + 1)]
        for i in range(M):
            for j in range(N):
                self.preSum[i + 1][j + 1] = self.preSum[i][j + 1] + self.preSum[i + 1][j]  - self.preSum[i][j] + matrix[i][j]


    def sumRegion(self, row1: int, col1: int, row2: int, col2: int) -> int:
        return self.preSum[row2 + 1][col2 + 1] - self.preSum[row2 + 1][col1] - self.preSum[row1][col2 + 1] + self.preSum[row1][col1]

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值