ble55ing的技术专栏 code analysis ,fuzzing technique and ctf

leetcode 经验

2020-02-22
ble55ing


leetcode 经验

1 一维数组查重要使用hash表

python的 Python 的 dict 和 set 都是使用 hash 表实现的,查找操作复杂度为O(1)

而in list的复杂度为O(n)

def findRepeatNumber(self, nums: List[int]) -> int:
        table = set()
        for i in nums:
            if i in table: 
                return i
            else:
                table.add(i)

2 递增二维数组查重

数组横向递增纵向递增,所以删除第一个数大的行和最后一个数小的列

def findNumberIn2DArray(self, matrix: List[List[int]], target: int) -> bool:
        i = len(matrix) - 1
        j = 0
        while i >= 0 and j < len(matrix[0]):
            if matrix[i][j] > target: i -= 1
            elif matrix[i][j] < target: j += 1
            else: return True
        return False

3 list头插

list.insert(0,xx),list.insert有一个可选参数是插入位置

但是速度很慢。只击败了54%。。但空间消耗很少,击败100%。。发现到现在还都是速度不到100%。。空间都是100%。。

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def reversePrint(self, head: ListNode) -> List[int]:
        list1 =[]
        while head!=None:
            list1.insert(0,head.val)
            head = head.next
        return list1

4 给前序中序,得二叉树

前序为 中左右,中序为 左中右,后序为 左右中

耗时又多了,空间还是击败100%。。

# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def buildTree(self, preorder: List[int], inorder: List[int]) -> TreeNode:    
        if len(preorder)<1:
            return None
        root = TreeNode(preorder[0])
        root.left = self.buildTree(preorder[1:1+inorder.index(preorder[0])],inorder[0:inorder.index(preorder[0])])
        root.right = self.buildTree(preorder[1+inorder.index(preorder[0]):],inorder[1+inorder.index(preorder[0]):])
        return root

5 斐波那契数列

青蛙跳台阶问题

class Solution:
    def fib(self, n: int) -> int:
        if (n<2):
            return n
        n1=0
        n2=1
        for i in range(1,n):
            ret = n1+n2
            n1=n2
            n2=ret
        return ret%1000000007

6 旋转数组的最小数字

第一次双100% !!

就是代码写的有点丑

class Solution:
    def minArray(self, numbers: List[int]) -> int:
        left = 0
        right = len(numbers)-1
        mid =1
        while numbers[left]>=numbers[right]:
            mid = int((left+right)/2)
            if left==mid:
                return numbers[right]
            if (numbers[left]<numbers[mid]):
                left=mid
            elif numbers[left]==numbers[mid]:
                left+=1
            if (numbers[right]>numbers[mid]):
                right = mid
            elif numbers[right]==numbers[mid]:
                right-=1
            

        return numbers[left]

7 二进制中1的个数

处理二进制就应该用位运算

class Solution:
    def hammingWeight(self, n: int) -> int:
        res=0;
        while n>0:
            res += n & 1
            n >>= 1
        return res

8 剪绳子问题

怎么剪绳子各段之积最大

从2到n找最大,知道乘积减小了,证明找到了最大值

class Solution:
    def cuttingRope(self, n: int) -> int:
        pres= 0
        res= 1
        i=1
        while res>pres:
            pres = res
            i+=1
            res = self.mnum(n,i)
        return pres
    def mnum(self,n,m):
        c = n//m
        d = n%m
        res = 1
        for i in range(m):
            if d>0:
                res*=(c+1)
                d-=1
            else:
                res*=c
        return res

9 实现幂运算

二进制表示n,为1 的就乘上

class Solution:
    def myPow(self, x: float, n: int) -> float:
        res= 1.0
        if n < 0:
            x = 1/x
            n = -n
        while n > 0:
            if n & 1:
                res *=x
            x *= x
            n >>= 1
        return res

10 正则匹配

我一开始用递归写的。。改了无数次。。结果时间只击败了5%,空间还是100%

class Solution:
    def isMatch(self, s: str, p: str) -> bool:
        s1=0
        p1=0
        while p1<len(p)-1:
            if p[p1]=='.' and p[p1+1]=='*':
                while s1<=len(s):
                    res = self.isMatch(s[s1:],p[p1+2:])
                    if res==True:
                        return True
                    s1+=1
                return False
            elif p[p1]=='.':
                if s1>=len(s):
                    return False
                return self.isMatch(s[s1+1:],p[p1+1:])
            elif p[p1+1]=='*':
                res = False
                while s1<=len(s):
                    res = self.isMatch(s[s1:],p[p1+2:])
                    if res==True:
                        return True
                    if s1>=len(s):
                        break;
                    elif s[s1]!=p[p1]:
                        break;
                    s1+=1
                return False
            elif s1<len(s) and s[s1]==p[p1]:
                s1+=1
                p1+=1
            else:
                break

        if len(p)==p1 and len(s)==s1:
            return True
        elif len(p)==p1 or len(s)==s1:
            return False
        if p[p1]==s[s1] and s1== len(s)-1:
            return True
        elif p[p1]=='.' and s1== len(s)-1:
            return True
        else:
            return False

看大家的题解都是动态规划,也学着写了写

动态规划,将问题转化为数学问题的递推

dp[i][j]表示s的前i项和p的前j项是否匹配,

然后找每个dp和之前的dp的关系

class Solution:
    def isMatch(self, s: str, p: str) -> bool:
        s, p = '#'+s, '#'+p
        m, n = len(s), len(p)
        [[False for _ in range(n)] for _ in range(m)]
        dp[0][0] = True
        
        for i in range(m):
            for j in range(1, n):
                if i == 0:
                    dp[i][j] = j > 1 and p[j] == '*' and dp[i][j-2]
                elif p[j] ==s[i] or p[j]=='.':
                    dp[i][j] = dp[i-1][j-1]
                elif p[j] == '*':
                    dp[i][j] = j > 1 and dp[i][j-2] 
                    if p[j-1] ==s[i] or p[j-1]=='.':
                        dp[i][j] |= dp[i-1][j]
                else:
                    dp[i][j] = False
        return dp[m-1][n-1]

烂橘子问题

网格里有橘子,每分钟烂橘子会将周围橘子变烂,问多少分钟后,橘子会烂完?或者橘子烂不完

这里首先将网络往外扩了一圈,用于减少之后的判断

class Solution:
    def orangesRotting(self, grid: List[List[int]]) -> int:
        ydo = 1
        turn =-1
        list22 =[]
        listnull =[]
        for j in range(len(grid[0])+2):
            listnull.append(0)
        for i in range(len(grid)):
            for j in range(len(grid[i])):
                if grid[i][j]==2:
                    list22.append((i+1,j+1))
            grid[i].insert(0,0)
            grid[i].append(0)
        grid.append(listnull)
        grid.insert(0,listnull)
        while ydo:
            ydo=0
            turn+=1
            len2= len(list22)
            for _ in range(len2):
                i,j = list22[0][0],list22[0][1]
                if grid[i][j-1]==1:
                    grid[i][j-1]=2
                    list22.append((i,j-1))
                    ydo=1
                if grid[i-1][j]==1:
                    grid[i-1][j]=2
                    list22.append((i-1,j))
                    ydo=1
                if grid[i+1][j]==1:
                    grid[i+1][j]=2
                    list22.append((i+1,j))
                    ydo=1
                if grid[i][j+1]==1:
                    grid[i][j+1]=2
                    list22.append((i,j+1))
                    ydo=1
                del list22[0]
        for i in range(len(grid)):
            for j in range(len(grid[i])):
                if grid[i][j]==1:
                    return -1
        return turn

和为s的连续正数序列

又一次双百,用数列求和来算,对偶数2n,为target%2n==n时是能够得到序列,target%(2n+1)==0时为能够得到,还要注意序列不能为0开始

class Solution:
    def findContinuousSequence(self, target: int) -> List[List[int]]:
        res = []
        n=1
        while (1+2*n)*n <= target:
            if target%(2*n)==n:
                left = target//(2*n)-n+1
                res1 = [ _ for _ in range(left,left+2*n)]
                res.insert(0,res1)
            if target%(2*n+1)==0:
                left = target//(2*n+1)-n
                if left>0:
                    res1 = [_ for _ in range(left,left+2*n+1)]
                    res.insert(0,res1)
            n+=1
        return res

字符串最大公因子

此处给出的是官网的,不是我写的,因为其非常直白的表现了python在字符串处理上的优点。

class Solution:
    def gcdOfStrings(self, str1: str, str2: str) -> str:
        for i in range(min(len(str1), len(str2)), 0, -1):
            if (len(str1) % i) == 0 and (len(str2) % i) == 0:
                if str1[: i] * (len(str1) // i) == str1 and str1[: i] * (len(str2) // i) == str2:
                    return str1[: i]
        return ''

数组中不连续上升子序列

数组中不连续的最长上升子序列,要求复杂度O(nlogn0),考虑用辅助数组。

class Solution:
    def lengthOfLIS(self, nums: List[int]) -> int:
        if not nums: return 0
        dp = [1 for _ in len(nums)]
        for i in range(len(nums)):
            for j in range(i):
                if nums[j] < nums[i]:
                    dp[i] = max(dp[i], dp[j] + 1)
        return max(dp)

拼写单词

用给的字符串里的字符拼单词,返回能拼的单词的总长度

官网题解是给的Counter,比我的慢一倍多。。

class Solution:
    def countCharacters(self, words: List[str], chars: str) -> int:
        chlist = [0 for _ in range(26)]
        wolist = [0 for _ in range(26)]
        res = 0
        for c in chars:
            chlist[ord(c)-ord('a')]+=1
        for word in words:
            for i in range(26):
                wolist[i]=0
            flag=1
            for w in word:
                r = ord(w)-ord('a')
                wolist[r]+=1
                if wolist[r]>chlist[r]:
                    flag=0
                    break;
            if flag==1:
                res+=len(word)
        return res

上一篇 上手latex

下一篇 pwn docker 搭建

Content