Bootstrap

LeetCode简单题合集 python

1672. 最富有客户的资产总量

tips: sum函数可以直接用~

class Solution:
    def maximumWealth(self, accounts: List[List[int]]) -> int:
        maxSum=0  #记录下最大值
        for a in accounts:  #遍历每个客户
            if sum(a)>maxSum:  #当前客户资产总和大于记录的最大值
                maxSum=sum(a)
        return maxSum

1920. 基于排列构建数组

class Solution:
    def buildArray(self, nums: List[int]) -> List[int]:
        return [nums[i] for i in nums]  # 这一句话解决问题

1. 两数之和

tips: 通过这个题可以 get 到字典的妙用,python中字典就是一种哈希结构,编程中用起来时间复杂度也比较低。

形象解释:(这个题就像是找老伴儿哈哈哈~~~)
   列表中的每个人心里都知道自己的老伴儿应该是谁(如果target=8,当前这个数是2,它知道自己需要找到的是6)。
  所以当遍历到这个人身上的时候,他就会去查一下字典,看看老伴儿在字典里吗,如果在,那这道题就结束了;
  如果不在,那他就先把自己放到字典中(他的值是字典中独一无二的key),乖乖等着他的老伴儿来找他。

class Solution:
    def twoSum(self, nums: List[int], target: int) -> List[int]:
        hashtable=dict()  # 创建一个字典
        for i,num in enumerate(nums): # 遍历数组nums,每当遇到一个数num时
            if target-num in hashtable: # 如果老伴儿(target-num)就在字典中 
                return [hashtable[target-num],i] # 问题结束,返回他俩各自的位置
            else:  # 老伴儿不在字典中
                hashtable[num]=i  # 那就把自己的信息以key(本身值大小)、value(下标位置)的形式存到字典中,等着他的老伴儿来找他
##### 二刷时的写法 #######
class Solution:
    def twoSum(self, nums: List[int], target: int) -> List[int]:
        # 字典能很好的直接访问到,哪个元素在,哪个元素不在,而且还能帮你存放一个附加的value值
        map_dict = {}  # 数值:下表
        for i, num in enumerate(nums):
            if target-num in map_dict:
                return [i, map_dict[target-num]]
            else:
                map_dict[num] = i

9. 回文数

class Solution:
    def isPalindrome(self, x: int) -> bool:
        x_str=str(x)  #把x转化成字符串
        x_ver_str=''.join(reversed(x_str))  #用''.join(reversed(str))这个方式求逆序字符串
        if x_str==x_ver_str:
            return True
        else:
            return False

13. 罗马数字转整数

用两个字符组合代表数字的就那6个特例('IV,‘IX’,‘XL’,‘XC’,‘CD’,‘CM’),字符串中的每个字符要么就是跟后边字符形成特例,不然的话那就是单独自己代表一个数字。(所以只需要走一遍字符串,看看每个字符跟后边是否能组合,不能组合就单独累加)

class Solution:
    def romanToInt(self, s: str) -> int:
        mapDict={
            'I':1,'V':5,'X':10,'L':50,'C':100,'D':500,'M':1000,
            'IV':4,'IX':9,'XL':40,'XC':90,'CD':400,'CM':900
        }
        countSum=0
        i=0
        while i<=len(s)-1: # 直到最后一位
            if i+1<=len(s)-1: # 如果后边有数
            # 取出这两个字母,看看是不是特例里中的
                if s[i:i+2] not in mapDict.keys(): # 两位组合的不在,那只能单独成数
                    countSum+=mapDict[s[i]] #直接由s[i]这个字符在字典中定位到其值
                    i+=1 #指针后移一位
                else:
                    countSum+=mapDict[s[i:i+2]] #s[i:i+2]两个字符形成的字符串也是在字典中直接定位到其值
                    i+=2 #指针后移两位
            else: # 后边没数,那它就是最后一位了
                countSum+=mapDict[s[i]] #直接加
                i+=1 #指针后移一位

        return countSum

14. 最长公共前缀

方法1:可以拓展成一种思想,要找出一堆东西中的共同基础部分,我们就按照规则让它们依次排队,排到最后会越来越严格,如果留到最后的那个都能和第一个有相同之处,那中间的肯定也没啥问题~

class Solution:
    def longestCommonPrefix(self, strs: List[str]) -> str:
        if len(strs)==0:  #空字符数组
            return ""
        minStr=min(strs) #找到排序之后最小的字符串
        maxStr=max(strs) #找到排序之后最大的字符串

        ## 遍历最小的字符串,依次检查里边每个字符是否在最大的字符串中
        for i,v in enumerate(minStr):
            ## 又小又短的会默认排在前边,所以不用担心maxStr[i]超出索引下标的问题
            if v!=maxStr[i]: #找到首个不一样的字符位置
                return maxStr[:i] #直接返回前边这些相同的字符串
        ## 如果一直没有返回,那最大的字符串就已经把最小的全包含了,直接返回最小的
        return minStr

方法2:通过这个题正好学习一下zip的用法

class Solution:
    def longestCommonPrefix(self, strs: List[str]) -> str:
        if len(strs)==0:  #空字符数组
            return ""
        strSum=""
        for i in zip(*strs): #每个i是一个元组(),大家把第几位都放到一起,例如('f','f','f')
            if len(set(i))==1: #转化成集合(自动去重),长度不为1那就是有不一样的
                strSum+=i[0]
            else:
                break
        return strSum

20. 有效的括号

还记得 1.两数之和 那个题我们用到了老伴儿思想嘛!这个题我们继续沿用情侣的思想,oh no这就是爱情的力量嘛?!(单身狗表示不懂了)
【用 ‘[’ ‘(’ ‘{’ 表示女生,等着男生 ‘]’ ‘)’ ‘}’ 来带走她,切记男生只去牵离他最近的那个女生 , 例如字符串 “( [ ) ]” ,前两个女生都在等着被牵手,第三个男生 ‘)’ 只尝试去牵第二个女生 ‘[’ ,发现不配对,就直接牵手失败喽~ 】

class Solution:
    def isValid(self, s: str) -> bool:
   		#键:男方,值:要找的女方
        partnerMap_Dict={ 
            ')':'(',']':'[','}':'{'
        }
        waitList=[] #存放等待被牵的女方
        #遍历字符串
        for i in s:
            if i not in partnerMap_Dict.keys(): #这是个女方,等着被牵
                waitList.append(i) #进去等着吧
            elif (len(waitList)!=0 and waitList[-1]!=partnerMap_Dict[i]) or len(waitList)==0: #这是个男方,有女方在等,但最近的那个女方和他并不配对;或者里边压根没人
                return False
            elif len(waitList)!=0 and waitList[-1]==partnerMap_Dict[i]: #这是个男方,且最后那个女生在等他,这一对儿就成了,把最近那个女方牵走吧
                waitList.pop()
        
        if len(waitList)==0: #最后wait列表空了,全部配对成功
            return True
        else:
            return False

LCP 33. 蓄水

浅试一下简单题中通过率最低的题目,结果直接让我怀疑人生~~
虽然我的解题逻辑有误,但是通过做这道题让我学会了python中很多的骚操作,也算是有很大的收获啦~~
收获如下:

1. 如何删除列表中值为0的元素
2. np.delete() 执行完后返回的是 ndarray,不是 list 了,转化回列表用 .tolist()
3. 对浮点数 x 向上取整用 math.ceil (x) ,记得要 import math
4. 找出列表 a 中最小值 b 所在的位置,用 a.index(b) 来获取
5. np.sum返回的是 float 类型,千万要注意这个坑
6. 遍历列表 a 时想跳过某个位置 i , 可以用 index =
list(range(0,i))+list(range(i+1,len(a))) 来重新组建下标索引,这样就避免了遍历时一直要 if 判断是不是我们不想要的那个位置

下边的错误代码也放上来做个纪念,目的是大家可以看一下上边的收获代码都是怎么实现的【正解在后边】:

import numpy as np
import math
class Solution:
    def storeWater(self, bucket: List[int], vat: List[int]) -> int:

        operationNums=0 #操作总次数

        ## 设置一个列表,存放每个水缸需要倒水的次数
        ## 当我们升级了水桶时,需要倒水的次数肯定也会随之变化,所以这个列表也是在动态改变的
        needToPushWaterNums=[0]*len(vat)

        # 0.对于水缸压根不要水的,我们就直接删掉就好啦
        flag=0
        for i in range(len(vat)-1,-1,-1):
            if vat[i]==0: #这个水缸压根不需要水
                #直接删掉这组就可以了
                vat=np.delete(vat,i)
                bucket=np.delete(bucket,i)
                needToPushWaterNums=np.delete(needToPushWaterNums,i)
                flag=1

        ## 注意:np.delete()执行完后返回的是ndarray,不是list了,这里需要转化一下
        ## 如果不转化的话,下边的.index就用不了了,运行会报错
        if flag==1:
            needToPushWaterNums=needToPushWaterNums.tolist()
        
        if len(needToPushWaterNums)!=0: #如果还有水缸需要倒水
            # 1.遍历每个水缸和对应的水桶,计算初始的需要倒水次数
            for i in range(len(bucket)):
                if bucket[i]==0:
                    needToPushWaterNums[i]=100000 #用100000代表一个很大的数
                else:
                    needToPushWaterNums[i]=math.ceil(vat[i]/bucket[i])  

            # 2.找出倒水次数最少的那组,用G表示
            minPushNums=min(needToPushWaterNums)
            minIndex=needToPushWaterNums.index(minPushNums) 
            if minPushNums==100000: #特殊情况,所有的桶容量一开始都是0
                operationNums+=int(np.sum(vat)) #这种情况下就是把所有的桶容量先升级起来
                operationNums+=1 #最后再执行一次蓄水
                return operationNums
            else: #正常情况
                operationNums+=minPushNums
             

            # 3.对于其他那些组,以G的倒数次数为baseline,那看一下它们的桶至少变为多大才可以
            otherIndex=list(range(0,minIndex))+list(range(minIndex+1,len(needToPushWaterNums))) 
            #### (这样遍历时就可以跳过某个位置,不需要在遍历时一直加上if来判断)
            for oI in otherIndex:
                bucketNeedSize=vat[oI]/minPushNums #水桶至少需要达到这么大
                operationNums+=math.ceil(bucketNeedSize-bucket[oI]) #升级这个水桶需要的次数
        return operationNums

正解: 参考b站视频
【我之前的想法是考虑不周全的,想法比较狭隘。我是用初始蓄水次数最少的那个水桶和水缸对儿来作为baseline,但其实这个最小的蓄水次数值并不一定是好的,可能我再加一次蓄水操作,效果就直接等同于三次升级水桶的操作】

import math
import numpy as np
class Solution:
    def storeWater(self, bucket: List[int], vat: List[int]) -> int:
        # 蓄水次数是一个没法一下就算出来最优值的变量,所以我们可以去遍历尝试它的值
        # 对于设置的当前蓄水次数i,我们看一下每个水桶首先要升级多少次才能用这个蓄水次数i来灌满水缸
        # 各个水桶的升级次数再加上蓄水次数i,那就是需要的操作数
        # 对比设置的所有蓄水次数i中,操作数最少的那个,就是最优的

        ## 如果所有的水缸蓄水量都是0,那就不需要任何操作,直接返回0(不需要改动minOperationNumber的值)
        if np.sum(vat)==0:
            return 0

        minOperationNumber=10005 # 存储最小的操作数值
        ## 遍历所有的蓄水次数值,1~10000
        for storeWaterNumber in range(1,10001): 
            operationSum=storeWaterNumber #先累加上蓄水操作的次数 
            for i in range(len(bucket)): #对于每一个水桶水缸对儿,看一下这个水桶需要升级多少次
                bucketSize=bucket[i]
                vatSize=vat[i]
                needBucketSize=math.ceil(vatSize/storeWaterNumber) #当蓄水次数一定时,水桶容量需要达到多大
                updateBucketNumber=needBucketSize-bucketSize #需要升级的次数
                if updateBucketNumber>0:
                    operationSum+=updateBucketNumber #再累加上每个水桶的升级次数
            
            if operationSum<minOperationNumber: #更新minOperationNumber
                minOperationNumber=operationSum
        
        return minOperationNumber

70. 爬楼梯

当前台阶的答案和前两个台阶有关,弄个dp数组保存一下结果

class Solution:
    def climbStairs(self, n: int) -> int:

        # 方法1:设置dp数组,推荐这个
        dp = [0,1,2]
        for i in range(3, n+1):
            dp.append(dp[i-1]+dp[i-2])
        
        return dp[n]


        # 方法2:省去dp数组,直接用两个变量来记录
        # 不过这种占的内存反倒更高,可能是因为变量太多了
        if n==1:
            return 1
        elif n==2:
            return 2
        else:
            pre1, pre2 = 1, 2
            cur = 0 
            for i in range(3, n+1):
                cur = pre1 + pre2
                # 更新pre1和pre2的值,为下个人做准备
                pre1 = pre2
                pre2 = cur
            return cur

83. 删除排序链表中的重复元素

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def deleteDuplicates(self, head: Optional[ListNode]) -> Optional[ListNode]:
        p = head
        while p and p.next: #这里要确保一下p.next是存在的
        #这里用到了p.next它的val值,那就一定要确保p.next是存在的,不然就会报错
            if p.next.val==p.val:  
                p.next=p.next.next
            else:
                p=p.next
        
        return head  #注意这里返回的是head,不是p哈

141. 环形链表

设置快慢指针,一个每次走两步,一个每次走一步

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

class Solution:
    def hasCycle(self, head: Optional[ListNode]) -> bool:
        fast = head
        slow = head

        # 快指针每次移动两步,慢指针每次移动一步
        # 如果他俩能相遇,说明有环,返回true
        while fast and fast.next:  #while循环一直next走就行,
        #如果是直链,while最终会退出去的,而且快慢指针绝对碰不上
            fast = fast.next.next
            slow = slow.next
            if fast == slow:
                return True

        return False

704. 二分查找

解法一:基础的二分查找代码

class Solution:
    def search(self, nums: List[int], target: int) -> int:
        n=len(nums)
        left,right=0,n-1
      
        while left<=right: #要考虑清楚这里是小于等于哦
            mid=int((left+right)/2) 
            if nums[mid]==target:
                return mid
            elif target>nums[mid]: #找右边
                left=mid+1
            else: #找左边
                right=mid-1
        
        return -1

解法二:利用python中列表自带的函数,直接返回索引位置

class Solution:
    def search(self, nums: List[int], target: int) -> int:
        if target in nums:
            return nums.index(target)
        else:
            return -1

27. 移除元素

思路:数组前边都是弄好的数,以end来标记,每次有新数就挨着往后放

class Solution:
    def removeElement(self, nums: List[int], val: int) -> int:
        # 【关键】把要留下的数,全都放到数组的最前边
        # 根据返回的数值,就去取数组的最前边这几个数

        end=-1
        for i in range(len(nums)): #遍历数组
            if nums[i]!=val: #这个数是要留下的
                nums[end+1]=nums[i]
                end+=1 #把这个棋子插在它身上
        
        return end+1  #数组长度的话是最后一个下标加1

977. 有序数组的平方

直接借助python自带的一些函数,“对列表求平方和”、“对列表排序”

# 时间:76ms
class Solution:
    def pow2(self,arg): #类内定义的函数记得要加self哈
        return arg**2
    def sortedSquares(self, nums: List[int]) -> List[int]:
        return sorted(list(map(self.pow2,nums)))  #类中方法相互调用,self.方法名 
# 时间:60ms
class Solution:
    def sortedSquares(self, nums: List[int]) -> List[int]:
        return sorted(list(map(lambda x:x*x, nums))) #使用lambda匿名函数也行
# 时间:68ms
class Solution:
    def sortedSquares(self, nums: List[int]) -> List[int]:
        return sorted([x**2 for x in nums]) #列表的推导式

203. 移除链表元素

  • 需要注意和83.删除排序链表中的重复元素区分开。
  • 这个题需要在链表最前边自己定义一个空head,因为链表第一个元素也是有可能要被删掉的,所以p要从前边的空head开始。
  • 而83题链表第一个元素是不会被删除的,所以p从它开始是没有问题的。
  • 链表的题目,如果某个节点存在要被删除的可能,此时一定确保要有个指针指向着它前边的元素。
  • 返回的时候是剩余链表的第一个元素,所以是newHead.next哦。
# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def removeElements(self, head: Optional[ListNode], val: int) -> Optional[ListNode]:
    
        newHead = ListNode(0,head)
        p = newHead #用p来进行遍历
        while p and p.next:
            if p.next.val == val: #下一个数是要被删掉的
                p.next = p.next.next
            else:
                p = p.next
        
        return newHead.next #返回链表第一个数的节点

206. 反转链表

虽说是双指针题目,其实是涉及到三个指针,其中有一个是临时指针temp

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]:
        cur = head  #用cur主指针来遍历,遍历到的这个元素是需要被调整next指向的
        pre = None ## 当涉及到删除或调整指针时,都要有一个指向前一个节点的从指针

        while cur: # 主指针一个一个节点遍历
            # 1、先把下一个节点记录下来,不然一会调整next指向就找不到它了
            temp =  cur.next 
            # 2、next指针调方向【核心语句】
            cur.next = pre 
            # 3、两个指针后移
            pre = cur
            cur = temp
        
        return pre #最后返回的谁不要搞错了

面试题 02.07. 链表相交

在这里插入图片描述

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

class Solution:
    def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:

        # 这两个链表的公共尾部,在内存中的地址是一样的
        # 因此我们不需要时刻盯着长度,当地址相等时自然就该停了
        
        # 所以我们的目标是:
        # 如何用双指针分别在这两个链表上做遍历,使得在某一个时刻上的这俩指针指向的地址相等
        # 要有发散思维,只是局限地在一个链表身上遍历,是没有办法重合的,两个链表长度都不同
        # 完全可以跳转到对方链表身上去做遍历

        A, B = headA, headB

        while A!=B: # 只要地址还不相同,两个指针就继续沿着设定的路线走

            # A的路线
            if A: # A链表长度还够
                A = A.next # 继续沿A走
            else: # A链表走完了
                A = headB # 跳转到B身上

            # B的路线
            if B: # B
                B = B.next
            else:
                B = headA

        return A

242. 有效的字母异位词

class Solution:
    def isAnagram(self, s: str, t: str) -> bool:

        ds,dt = {},{}
       
        for i in s:
            if i not in ds.keys():
                ds[i] = 1
            else:
                ds[i] += 1
        
        for j in t:
            if j not in dt.keys():
                dt[j] = 1
            else:
                dt[j] += 1 
        
        if ds==dt:
            return True
        else:
            return False

349. 两个数组的交集

class Solution:
    def intersection(self, nums1: List[int], nums2: List[int]) -> List[int]:
        return list(set(nums1) & set(nums2))    

后续题目在新的博客

【1】Leetcode简单题合集 python

;