【4月】LeetCode:很缓慢地存些东西

总之就是每天搞一道题。
有时两题,有时零题。挑一些自我反省来写。
我常常因为自己太菜而一道题写半天.jpg

4.2

题目链接

2. 两数相加

很喜欢的解法(哑结点)
class Solution:
    def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode:
        dummyHead = ListNode(0)
        curr, carry = dummyHead, 0
        while l1 or l2:
            sum = 0
            if l1:
                sum += l1.val
                l1 = l1.next
            if l2:
                sum += l2.val
                l2 = l2.next
            sum += carry
            carry = sum // 10
            curr.next = ListNode(sum % 10)
            curr = curr.next
        if carry > 0:
            curr.next = ListNode(1)
        return dummyHead.next;
自己第一反应的解法
class Solution:
    def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode:
        b=ListNode(0)
        c=b
        while l1 or l2:
            c.val+=sum(list(map(lambda x:0 if x==None else x.val,[l1,l2])))
            l1,l2=list(map(lambda x:x if x==None else x.next,[l1,l2]))
            c.next=[ListNode(c.val//10),None][c.val<10 and l1==l2==None]
            c.val%=10
            c=c.next
        return b
感想
  • 发现自己的解法太过耗脑就不要一直莽,想想别的出路。就好像这道题,做一个哑节点会让逻辑和操作都清晰很多。
  • lambda真的很酷炫,也很容易沉迷……但别瞎用。这东西对于提升运行效率并无助益,平时跑起来感觉不到什么,但其实会很慢。慢到想死。
  • 多看数据结构,多看数据结构,多看数据结构。

4.3

题目链接

8. 字符串转换整数 (atoi)

很喜欢的解法(正则)
class Solution:
    def myAtoi(self, str: str) -> int:
        return max(min(int(*re.findall('^[\+\-]?\d+', str.lstrip())), 2**31 - 1), -2**31)
自己第一反应的解法
class Solution:
    def myAtoi(self, str: str) -> int:
        r=''
        l='0123456789'
        for i in str:
            if (i==' ' and r!='') or (i not in l+'-+ '):
                break
            if (i in '-+') and (len(r)!=0 or ('-' in r or '+' in r)):
                if len(r)==1:return 0
                else:break
            if i in l+'-+':
                r+=i
        if r in '-+':
            return 0
        return max(min(int(r),2**31-1),-2**31)
感想
  • 正则可以省很多事,能上正则的时候就尽量上正则。
  • 不要觉得一个技巧很酷就一直用,要多多依赖自带函数。就好像在这道题里str.lstrip()比遍历判断空格更好用,min(r,2**31-1)[r,2**31-1][r>=2**31-1]更清晰。虽然用列表来写判断很有趣,但不要遇事不决上列表(……)本道理同样适用于lambda x
  • 造测试样例很重要(……)尽可能把所有可能的情况都包含上比较好,想的不够多又相信自己的脑子就会出很多WA和RE(。

4.17

隔很多天又去A了一下每日一题(……)
要么太难要么太简单,今天正好难度适中动了动脑子(……)

题目链接

35.跳跃游戏

很喜欢的解法
class Solution:
    def canJump(self, nums) :
        max_i = 0       #初始化当前能到达最远的位置
        for i, jump in enumerate(nums):   #i为当前位置,jump是当前位置的跳数
            if max_i>=i and i+jump>max_i:  #如果当前位置能到达,并且当前位置+跳数>最远位置  
                max_i = i+jump  #更新最远能到达位置
        return max_i>=i
自己第一反应的解法
class Solution:
    def canJump(self, nums: List[int]) -> bool:
        maxc=nums[0]
        for i in range(len(nums)):
            if i>maxc:break
            if (i+nums[i])>=(len(nums)-1):return True
            maxc=max(maxc,nums[i]+i)
        return False
感想
  • enumerate()是不是比range(len())要快啊!好不安,总之度了一下,大家说尽量用enumerate取代掉range,那就这样叭(
  • 想了想其实初始值直接maxc=0就好了(……)不过这样子赋值也没什么影响,大概。

4.18

题目链接

11. 盛最多水的容器

自己暴力开冲超时以后的修改解法(双指针)
class Solution:
    def maxArea(self, height: List[int]) -> int:
        maxm=0
        i,j=0,len(height)-1
        while i!=j:
            maxm=max(maxm,(j-i)*min(height[i],height[j]))
            if height[i]
感想
  • 关于解法的说明:尝试过程中矩形底边必定不断变小,而矩形的高又是min(height[i],height[j]),所以只能通过改变min值来增加矩形面积,亦即改变这两个值中的较小值……也就是较矮一端的柱子。
    视频:【双指针法】的合理性证明 - LeetCode
  • 后来去看了看题解,在判断那里可以再加一下。如果下一个位置比现在的位置数值还要小,可以直接跳过,免得重复计算面积(……)天才吗(

4.19

题目链接

5388. 重新格式化字符串

很喜欢的解法
class Solution:
    def reformat(self, s: str) -> str:
        a=re.findall(r'\d',s)
        b=re.findall(r'[a-z]',s)
        if abs(len(a)-len(b))>1:
            return ''
        a,b=sorted([a,b],key=len)
        return ''.join(map(''.join,itertools.zip_longest(b,a,fillvalue='')))
自己第一反应的解法
class Solution:
    def reformat(self, s: str) -> str:
        a=re.findall('[a-z]',s)
        b=re.findall('[0-9]',s)
        if not (-1<=(len(a)-len(b))<=1):
            return ""
        if len(b)>len(a):a,b=b,a
        c=''.join([y for x in zip(a,b) for y in x])
        if len(a)!=len(b):c+=a[-1]
        return c
感想
  • 是我读的函数太少,是我太菜,我根本没掌握map的正确用法,下次一定写abssorted,dbq,dbq

4.20

题目链接

219. 存在重复元素 II

很喜欢的解法(HashSet)
class Solution:
    def containsNearbyDuplicate(self, nums: List[int], k: int) -> bool:
        tmp=set()
        for i in range(len(nums)):
            if nums[i] in tmp:return True
            tmp.add(nums[i])
            if len(tmp)>k:
                tmp.remove(nums[i-k])
        return False
自己安定超时的第一反应
class Solution:
    def containsNearbyDuplicate(self, nums: List[int], k: int) -> bool:
        for i in range(len(nums)):
            for j in range(len(nums)):
                if j!=i and nums[j]==nums[i] and -k<=(i-j)<=k:
                    return True
        return False
感想
  • 暴力不可取,停止套娃。
  • 能搞懂各种数据结构的应用场合是快乐做题的关键一步(?)
题目链接

200. 岛屿数量

看了题解的解法(BFS)
class Solution:
    def numIslands(self, grid: List[List[str]]) -> int:
        def bfs(grid,i,j):
            if i<0 or j<0 or i>=len(grid) or j>=len(grid[0]) or grid[i][j]!='1':
                return 0
            grid[i][j]=0
            bfs(grid,i,j-1)
            bfs(grid,i,j+1)
            bfs(grid,i-1,j)
            bfs(grid,i+1,j)

        count=0
        for i in range(len(grid)):
            for j in range(len(grid[0])):
                if grid[i][j]=='1':
                    bfs(grid,i,j)
                    count+=1
        return count
感想
  • 知道“有这么个东西”和“能把概念和实际情景联系上”,差别真的很大(……)我的数据结构学得仿佛白瞎(。总之还是要多练,任重道远(

4.21

题目链接

1248. 统计「优美子数组」

看了题解的解法
class Solution:
    def numberOfSubarrays(self, nums: List[int], k: int) -> int:
        tmp=[i for i in range(len(nums)) if nums[i]%2!=0]
        tmp=[-1]+tmp+[len(nums)]
        count=0
        for i in range(1,len(tmp)-k):
            count+=(tmp[i]-tmp[i-1])*(tmp[i+k]-tmp[i+k-1])
        return count
感想
  • 把列表边界处理下会快乐很多,就像之前那道题的哑结点。我怎么不长教训的(笑)

4.22

题目链接

199. 二叉树的右视图

很喜欢的解法(BFS)
class Solution:
    def rightSideView(self, root: TreeNode) -> List[int]:
        if not root:
            return []
        ans, nodes = [], [root]
        while nodes:
            ans.append(nodes[-1].val)
            nodes = [n for node in nodes for n in [node.left, node.right] if n]
        return ans
自己第一反应的解法
# 很憨憨的层序遍历
class Solution:
    def rightSideView(self, root: TreeNode) -> List[int]:
        if root==None:
            return []
        tmp,level=[root],[]
        result=[]
        nowlist=1
        nextlist=0
        while tmp:
            node=tmp.pop(0)
            nowlist-=1
            if node.left!=None:
                tmp+=[node.left]
                nextlist+=1
            if node.right!=None:
                tmp+=[node.right]
                nextlist+=1
            level.append(node.val)
            if nowlist==0:
                nowlist,nextlist=nextlist,0
                result.append(level[-1])
                level=[]
        return list(filter(None,result))
感想
  • 我会个p的bfs和dfs……dbq我又在拿python写c,我是憨憨,笨蛋是我我是笨蛋。
  • 既然有语法糖就去吃(。

4.25

题目链接

46. 全排列

很喜欢的解法

itertools — Functions creating iterators for efficient looping

def permute(self, nums: List[int]) -> List[List[int]]:
        return list(itertools.permutations(nums))
参考了题解的解法
#回溯算法
class Solution:
    def permute(self, nums: List[int]) -> List[List[int]]:
        result=[]
        def backtracks(nums,tmp):
            if not nums:
                result.append(tmp)
                return
            for i in range(len(nums)):
                backtracks(nums[:i]+nums[i+1:],tmp+[nums[i]])
        backtracks(nums,[])
        return result
感想
  • 值得参考的题解:
    从全排列问题开始理解「回溯」算法(深度优先遍历 + 状态重置 + 剪枝)
  • 多读文档多动脑,停止暴力(。
题目链接

6. Z 字形变换

很喜欢的解法
class Solution:
    def convert(self, s: str, numRows: int) -> str:
        tmp=['']*len(s)
        start,flag=0,-1
        for i in s:
            tmp[start]+=i
            if start==0 or start==numRows-1:flag=-flag
            start+=flag
        return ''.join(tmp)
自己第一反应的解法
class Solution:
    def convert(self, s: str, numRows: int) -> str:
        if numRows==1:
            return s
        s=list(s)
        jump=numRows*2-2
        tmp=s[::jump]
        for i in range(1,numRows-1):
            tmp+=[k for j in zip_longest(s[i::jump],s[jump-i::jump],fillvalue='') for k in j]
        tmp+=s[numRows-1::jump]
        return ''.join(tmp)
感想
  • 多动脑*2。天才 改索引方向 天才

4.28

题目链接

面试题56 - I. 数组中数字出现的次数

一个整型数组 nums 里除两个数字之外,其他数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。

很喜欢的解法(位运算)
class Solution:
    def singleNumbers(self, nums: List[int]) -> List[int]:
        tmp=reduce(lambda x,y:x^y,nums)
        lowbit=tmp&(-tmp)
        result=[0,0]
        for i in range(len(nums)):
            if nums[i]&lowbit==0:
                result[0]^=nums[i]
            else:
                result[1]^=nums[i]
        return result
解法说明
  • 参考题解:位运算三步走 详细解释lowbit原理
  • 因为“其他数字都出现了两次”,而相同值的异或结果为0,所以对所有数做异或的结果必定是“只出现一次的某两个数异或的结果”,暂称a和b。
    之后只要找到a和b(任意一个)不同的一位(即上一步的异或结果为1),就可以通过这一位把a和b区分开。为方便起见,解法里通过lowbit=tmp&-tmp获取最低位的1,并把这一位外的数都置0,作为掩码(mask)。
    这样一来,和mask做与运算的结果必定是0(在那一位上为0)或mask(在那一位上为1)。最后只需要挨个遍历,通过与运算区分开a和b以后再做异或就ok,出现两次的会自己消掉,所以剩下的就是所求的a和b。

4.29

题目链接

1095. 山脉数组中查找目标值

很喜欢的解法(二分查找)
def binary_search(mountain, target, l, r, key=lambda x: x):
    target = key(target)
    while l <= r:
        mid = (l + r) // 2
        cur = key(mountain.get(mid))
        if cur == target:
            return mid
        elif cur < target:
            l = mid + 1
        else:
            r = mid - 1
    return -1

class Solution:
    def findInMountainArray(self, target: int, mountain_arr: 'MountainArray') -> int:
        l, r = 0, mountain_arr.length() - 1
        while l < r:
            mid = (l + r) // 2
            if mountain_arr.get(mid) < mountain_arr.get(mid + 1):
                l = mid + 1
            else:
                r = mid
        peak = l
        index = binary_search(mountain_arr, target, 0, peak)
        if index != -1:
            return index
        index = binary_search(mountain_arr, target, peak + 1, mountain_arr.length() - 1, lambda x: -x)
        return index
感想
  • 参考题解:山脉数组中查找目标值
  • 这一手lambda用得好强,二分的泛用性也好强,学习了(。

4.30

题目链接

202. 快乐数

很喜欢的解法(快慢指针)

参考英文网站热评第一。这题可以用快慢指针的思想去做,有点类似于检测是否为环形链表那道题。
如果给定的数字最后会一直循环重复,那么快的指针(值)一定会追上慢的指针(值),也就是两者一定会相等。如果没有循环重复,那么最后快慢指针也会相等,且都等于1。

class Solution:
    def isHappy(self, n: int) -> bool:
        def calc(i):
            return sum(map(lambda x:int(x)**2,list(str(i))))
        slow=calc(n)
        fast=calc(calc(n))
        while slow!=fast and fast!=1:
            slow=calc(slow)
            fast=calc(calc(fast))
        return fast==1
看了题解的解法(HashSet)

我们使用 HashSet 而不是向量、列表或数组的原因是因为我们反复检查其中是否存在某数字。检查数字是否在哈希集中需要O(1)的时间,而对于其他数据结构,则需要O(n)的时间。选择正确的数据结构是解决这些问题的关键部分。

class Solution:
    def isHappy(self, n: int) -> bool:
        def calc(i):
            return sum(map(lambda x:int(x)**2,list(str(n))))
        tmp=set()
        while True:
            n=calc(n)
            print(n)
            if n==1:
                return True
            if n not in tmp:
                tmp.add(n)
            else:
                return False
感想
  • 摘录评论如下:
    此题不建议用集合记录每次的计算结果来判断是否进入循环,因为这个集合可能大到无法存储;另外,也不建议使用递归,同理,如果递归层次较深,会直接导致调用栈崩溃。不要因为这个题目给出的整数是int型而投机取巧。
  • 菜 我 菜。这道题最大也就243所以不会崩,但是其他场景下就不好说了,所以还是用快慢指针好一点。

你可能感兴趣的:(【4月】LeetCode:很缓慢地存些东西)