2021-08-15254周赛感想

快速幂+贪心思想

  • p=x+y
  • min(xy)
    R(x,y)=xy+v(p-x-y)
    易知(v,v)是R的最大值,而向x,y距离越远,xy值越小,多变量亦具有该性质

给你一个正整数 p 。你有一个下标从 1 开始的数组 nums ,这个数组包含范围 [1, 2p - 1] 内所有整数的二进制形式(两端都 包含)。你可以进行以下操作 任意 次:
从 nums 中选择两个元素 x 和 y 。
选择 x 中的一位与 y 对应位置的位交换。对应位置指的是两个整数 相同位置 的二进制位。
比方说,如果 x = 1101 且 y = 0011 ,交换右边数起第 2 位后,我们得到 x = 1111 和 y = 0001 。
请你算出进行以上操作 任意次 以后,nums 能得到的 最小非零 乘积。将乘积对 109 + 7 取余 后返回。
注意:答案应为取余 之前 的最小值。

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

mod = 1000000007

class Solution:
    def minNonZeroProduct(self, p: int) -> int:
        if p==1:
            return 1
        hi=(1<>1,mod)*hi%mod

快速幂算法:

int qpow(int a, int n){
    int ans = 1;
    while(n){
        if(n&1)        //如果n的当前末位为1
            ans *= a;  //ans乘上当前的a
        a *= a;        //a自乘
        n >>= 1;       //n往右移一位
    }
    return ans;
}

解码方法

一条包含字母 A-Z 的消息通过以下映射进行了 编码 :
'A' -> 1
'B' -> 2
...
'Z' -> 26
要 解码 已编码的消息,所有数字必须基于上述映射的方法,反向映射回字母(可能有多种方法)。例如,"11106" 可以映射为:
"AAJF" ,将消息分组为 (1 1 10 6)
"KJF" ,将消息分组为 (11 10 6)
注意,消息不能分组为 (1 11 06) ,因为 "06" 不能映射为 "F" ,这是由于 "6" 和 "06" 在映射中并不等价。
给你一个只含数字的 非空 字符串 s ,请计算并返回 解码 方法的 总数 。
题目数据保证答案肯定是一个 32 位 的整数。

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

class Solution:
    def numDecodings(self, s: str) -> int:
        hash_set=set()
        for i in range(1,27):
            hash_set.add(str(i))

        dp=[0]*(len(s)+1)
        #dp[0]=-1
        if len(s)==1:
            if s in hash_set:
                return 1
        cnt=0
        for i in range(len(s)):
            if s[i]=='0' and cnt==0:
                cnt+=1
                if dp[i]==0 or i>0 and int(s[i-1])>2 :
                    return 0
                else:
                    dp[i+1]=dp[i-1]
            elif cnt>0:
                cnt=0
                #print('cnt!=0')
                #print(s[i])
                if s[i]=='0':
                    #print('here')
                    return 0
                else:
                    dp[i+1]=dp[i]
                    #print('hi')
            elif cnt==0:
                dp[0]=1
                dp[i+1]=dp[i]
                if s[i-1:i+1] in hash_set:
                    #print('he')
                    dp[i+1]+=dp[i-1]
        #print(dp)
        return dp[len(s)]
image.png

其中关键点有二:

  • 前导零问题
  • 二位数是否在编码范围之内

故改进代码如下

class Solution:
    def numDecodings(self, s: str) -> int:
        hash_set=set()
        for i in range(1,27):
            hash_set.add(str(i))

        dp=[0]*(len(s)+1)
        dp[0]=1
        for i in range(len(s)):
            if s[i]=='0':
                if i==0 or i>0 and s[i-1] not in ['1','2']:
                    return 0
                else:
                    dp[i+1]=dp[i-1]
            else:
                if i>0:
                    '''
                    if s[i-1]!='0':
                        if s[i-1:i+1] in hash_set:
                            dp[i+1]=dp[i]+dp[i-1]
                        else:
                            dp[i+1]=dp[i]
                    else:
                        dp[i+1]=dp[i]
                    '''
                    dp[i+1]=dp[i]#长度为1转移一定可以实现
                    if  s[i-1]!='0' and s[i-1:i+1] in hash_set:#唯一的长度为2转移条件
                        dp[i+1]+=dp[i-1]
                else:
                    dp[i+1]=1
        return dp[-1]

关于DNA的模式识别,利用其只有ACGT

给定一个二维矩阵 matrix,以下类型的多个请求:
计算其子矩形范围内元素的总和,该子矩阵的左上角为 (row1, col1) ,右下角为 (row2, col2) 。
实现 NumMatrix 类:
NumMatrix(int[][] matrix) 给定整数矩阵 matrix 进行初始化
int sumRegion(int row1, int col1, int row2, int col2) 返回左上角 (row1, col1) 、右下角 (row2, col2) 的子矩阵的元素总和。

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

class NumMatrix:
    
    def __init__(self, matrix: List[List[int]]):
        self.n=len(matrix[0])
        self.m=len(matrix)

        self.matrix =[[matrix[i][j] for j in range(self.n)] for i in range(self.m)]
        self.dp=[[0]*self.n for _ in range(self.m)]
        for i in range(self.m):
            for j in range(self.n):
                self.dp[i][j]=self.matrix[i][j]
                if i>=1:
                    self.dp[i][j]+=self.dp[i-1][j]
                if j>=1:
                    self.dp[i][j]+=self.dp[i][j-1]
                if i>=1 and j>=1:
                    self.dp[i][j]-=self.dp[i-1][j-1]


    def sumRegion(self, row1: int, col1: int, row2: int, col2: int) -> int:
        #前缀和矩阵[]
        ans=self.dp[row2][col2]
        if col1>0:
            ans-=self.dp[row2][col1-1]
        if row1>0:
            ans-=self.dp[row1-1][col2]
        if col1>0 and row1>0:
            ans+=self.dp[row1-1][col1-1]
        return ans

  • 前缀和+容斥原理
  • 容斥原理:为了不重不漏,使用AUB=A+B-A^B,即把所用包含的集合相加,再相减其重叠部分

给你一个下标从 1 开始的二进制矩阵,其中 0 表示陆地,1 表示水域。同时给你 row 和 col 分别表示矩阵中行和列的数目。
一开始在第 0 天,整个 矩阵都是 陆地 。但每一天都会有一块新陆地被 水 淹没变成水域。给你一个下标从 1 开始的二维数组 cells ,其中 cells[i] = [ri, ci] 表示在第 i 天,第 ri 行 ci 列(下标都是从 1 开始)的陆地会变成 水域 (也就是 0 变成 1 )。
你想知道从矩阵最 上面 一行走到最 下面 一行,且只经过陆地格子的 最后一天 是哪一天。你可以从最上面一行的 任意 格子出发,到达最下面一行的 任意 格子。你只能沿着 四个 基本方向移动(也就是上下左右)。
请返回只经过陆地格子能从最 上面 一行走到最 下面 一行的 最后一天 。

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

二分答案+多源DFS

特别注意check函数的书写

  • 一条性质,此时是找到mid满足后依然记录,试图找到mid满足的最小值
  • mid满足即mid天可以从第一行走到最后一行
class Solution:
    def latestDayToCross(self, row: int, col: int, cells: List[List[int]]) -> int:
        #直接一次过
        def check(day):
            grid=[[0]*col for _ in range(row)]
            for i,j in cells[:day]:
                grid[i-1][j-1]=1
            for i in range(col):
                if dfs(0,i,row,col,grid):
                    return True
            return False

        def dfs(x,y,row,col,grid):
            if 0<=x>1
            if check(mid):
                res=max(res,mid)
                l=mid
            else:
                r=mid-1
        return res
                
        

给定一个未排序的整数数组,找到最长递增子序列的个数。
示例 1:
输入: [1,3,5,4,7]
输出: 2
解释: 有两个最长递增子序列,分别是 [1, 3, 4, 7] 和[1, 3, 5, 7]。

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

想到一个O(N^3)的方法,被卡住过不去

二维数组dp_s[i][j]是到位置i元素,长度为j的不同排列个数

class Solution:
    def findNumberOfLIS(self, nums: List[int]) -> int:
        #算法正确性是有的,但是不具备高效性
        dict_,n={},len(nums)
        #dp=[1]*n
        dp_s=[[0]*n for _ in range(n)]
        for i in range(n):
            dp_s[i][0]=1
        for i in range(n):
            for j in range(i):
                for jj in range(j+1):
                    if nums[i]>nums[j]:
                        #print('here')
                        dp_s[i][jj+1]+=dp_s[j][jj]
            #dict_[dp[i]]=dict_.get(dp[i],0)+1
        #print(dp_s)
        max_=0
        for i in range(n-1,-1,-1):
            for j in range(n):
                if dp_s[j][i]==0:
                    continue
                else:
                    max_=max(max_,dp_s[j][i])
            if max_!=0:
                ans=0
                for j in range(n):
                   ans+=dp_s[j][i]
                return ans
        #print(dict_)
        #return dict_[max(dp)]
        return 0

标解一,使用空间(其实并不是多占了内存,而是多个独立的变量相比二维数组功能更强大)换取时间。

class Solution:
    def findNumberOfLIS(self, nums: List[int]) -> int:
        n=len(nums)
        length=[0]*n
        count=[1]*n
        for i in range(n):
            for j in range(i):
                if nums[i]>nums[j]:
                    if length[j]>=length[i]:#记录最大值的专业个数,以及长度,以及使用长度作为判断条件
                        length[i]=length[j]+1
                        count[i]=count[j]
                    elif length[j]==length[i]-1:
                        count[i]+=count[j]
        max_=max(length)
        return sum([c for i,c in enumerate(count) if length[i]==max_])

给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。
你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。
示例 1:
输入:head = [1,2,3,4]
输出:[2,1,4,3]

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

本想省内存,结果在时间复杂度上更突出

# 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: ListNode) -> ListNode:
        #省内存的方式
        if not head or not head.next:
            return head
        head_new=head.next
        tail=head
        tail.next=head_new.next
        head_new.next=tail
        while tail.next and tail.next.next:
            mery=tail.next.next
            tail.next.next=mery.next
            mery.next=tail.next
            tail.next=mery
            tail=tail.next.next
        return head_new
image.png

你可能感兴趣的:(2021-08-15254周赛感想)