python leetcoe4

53. 最大子序和

'''
    第二次做这个题,我对这个题完全一点印象都没有,所以怎么办呢?
    当然是再想一遍白
'''

'''
    思路1:
        可以看到,找到具有最大和的连续子数组
        --也就是说如果你从右往左找最大的,那么一定是绕不过每一个数的(除非不选)
            如:[-2,1,-3,4,-1,2,1,-5,4]
            从右往左看:
                [2,4,3,6,2,3,1,-1,4]
            就是如果你想要过去这个位置,就一定要看一下后面能不能变大,就是说后面的该位置的最大值是不是正数是不是
            我能走下去的依据
'''
#这个代码的本质是动态规划
#还有一种分治的写法,不过感觉挺难,先放着
def fun1(nums):
    max=nums[len(nums)-1]
    for i in reversed(range(len(nums)-1)):
        if nums[i+1]>0:
            nums[i]=nums[i]+nums[i+1]
        if nums[i]>max:
            max=nums[i]
    return max
fun1([-2,1,-3,4,-1,2,1,-5,4])

====================================================================================================================================================================================================================================
198. 打家劫舍

'''
    首先我是一个专业的小偷,那我要怎么偷,才可以偷的最多?
        因为两间相邻的房屋,不能在一晚上同时被偷,所以我要好好指定策略

    --能偷的时候一定要偷(基本素养问题哈哈哈)
    --那么既然我见人就偷,不就只有两种情况了第一次偷,或者第一次不偷?

'''

'''
    方法一:
        既然见人就偷,才有美好明天(金额最大),那么
        只能分为两种情况,第一次偷和第一次不偷
        就直接一次遍历结束掉
        
    试了一下,有个问题,我没有考虑到,就是如果一群穷人中有一个富人,那么我见到穷人就偷,富人不就偷不到了?
    这样的话亏的反而更多
'''
def fun1(nums):
    s=0
    l=1
    sum_s=0
    sum_l=0
    while s<len(nums) or l<len(nums):
        if s<len(nums):
            sum_s+=nums[s]
        if l<len(nums):
            sum_l+=nums[l]
        s+=2
        l+=2
    return max(sum_s,sum_l)
print(fun1([2,1,1,2]))

'''
    像这种最优解问题,动态规划是非常有效的
    首先能偷就偷是一定的,在这个房子里面偷了,有赚的,不偷毛都没有
    max(f(i))=f(i)+max(f(i+2<i))
'''

def fun2(nums):
    if len(nums)==1:
        return nums[0]
    n=len(nums)
    ls=[0]*n
    ls[n-1]=nums[n-1]
    ls[n-2]=nums[n-2]
    max_=max(ls[n-1],ls[n-2])
    for i in reversed(range(len(nums)-2)):
        ls[i]=nums[i]+max(ls[i+2::])
        if max_<ls[i]:
            max_=ls[i]
    return max_
print(fun2([2,1,1,2]))

'''
    这里其实可以再化简一下,每次还额外的查找max(ls[i+2::])其实不需要,那个变量或者列表记录就好
'''

====================================================================================================================================================================================================================================
384. 打乱数组
这里有个名字听起来很高级的算法,但其实逻辑很简单
就是迭代的过程中,减少了列表的修改所需时间
就是无论如何,把剩下没有抽取的"签"放在一起,等我抽就行了,已经抽了的
签在也看不到就好了

'''
    这是是一类设计题目:
        我现在需要设计一个类:
            其中包含:
                --一个初始化函数
                --一个返回初始状态函数
                --一个返回随机打乱数组函数
'''

'''
    这类题目我做的并不多,所以可能会出现问题
        我就先试试random的随机打乱
    不用试了,他需要返回随机打乱所有的可能结果
    那么random本身属于伪随机,根本做不到
'''

'''
    昨天,因为没有什么思路,看了一下答案的解析,发现了他是进行抽签
    抽签(无放回)中每一个签被抽到的概率是等可能的,1/n所以就可以
    把所有情况随机出来
'''
import random
class Solution:
    def __init__(self, nums):
        self.nums=nums
        self.arr=nums.copy()
    def reset(self):
        self.nums=self.arr.copy()
        return self.nums

    def shuffle(self):
        #返回打乱后的数组
        shuzhu=self.nums.copy()
        for i in range(len(self.nums)):#总共抽取的次数
            self.nums[i]=shuzhu.pop(random.randint(0,len(shuzhu)-1))
        return self.nums


nums=[[0,-12893,128384]]
ls=list(nums)
ls[0][1]=10
print(nums)


#Fisher-Yates 洗牌算法
#这种算法,是很像暴力枚举算法的,但是避免掉了每次迭代过程中,修改列表的时间
'''
    基本思想:
        --就像抽签一样,每次抽一个,已经被抽取过的不能抽了
        --那么我就需要对已经抽取过的进行删除
        --上面的删除是真删除,对列表进行了修改
        --但其实有更好的方法:
            假设有一数组:[0,-3,-4,9,5,1],当前位置为cur,抽取元素下标为:index,此时cur还没动等于0
            第一次(0,len):数组中每个元素都能取,假设取index=3,与当前位置交换变为:[9,-3,-4,0,5,1],cur+1
            第二次(1,len):....
            ...
            不断的迭代
            这就相当于不放回的抽取
'''

import random
class Solution1:
    def __init__(self, nums):
        self.nums=nums
        self.arr=nums.copy()
    def reset(self):
        self.nums=self.arr.copy()
        return self.nums

    def shuffle(self):
        le=len(self.nums)-1
        for i in range(len(self.nums)):#总共抽取的次数
            index=random.randint(i,le)
            self.nums[i],self.nums[index]=self.nums[index],self.nums[i]
        return self.nums

====================================================================================================================================================================================================================================
155. 最小栈

'''
    这个题目怎么说?
        刚学数据结构的应该就会写
    增长一下自信心
    最小栈:
        肯定也是一个栈,只不过会有一个返回最小元素的函数
'''

'''
    push(x) —— 将元素 x 推入栈中。
    pop()—— 删除栈顶的元素。
    top()—— 获取栈顶元素。
    getMin() —— 检索栈中的最小元素。
    
    如果在别的语言中写,你可能会遇见栈的空间不够用的情况
    这时候需要重新开空间
    但是在python中,他写的好,你不够用的时候会自动帮你开
'''
class MinStack:

    def __init__(self):
        self.min=float('inf')#设置成正无穷,这样一定会改变
        self.nums=[]
    def push(self, val: int) -> None:
        self.nums.append(val)
        if self.min>val:
            self.min=val
    def pop(self) -> None:
        val=self.nums.pop()#删除栈顶元素
        if val==self.min:
            #需要再次找到栈中的最小元素
            #self.min=min(self.nums),栈可能会空,需要判断一下
            if self.nums==[]:
                self.min=float('inf')
            else:
                self.min = min(self.nums)
    def top(self) -> int:
        return self.nums[len(self.nums)-1]
    def getMin(self) -> int:
        return self.min


'''
    上面的写法是取巧了,正常的方式应该是牺牲空间来
    达到记录最小元素的情况,这里不需要进行排序
    而是利用栈的性质:
        如果在元素a入栈时,b,c,d已经在栈中,那么可想而知,a不出栈,b,c,d也是不可能出栈的
        那么使用另外一个栈(辅助栈),每次入栈的都是最小值,每次主栈要出栈时,辅助栈也出
'''
class MinStack1:

    def __init__(self):
        self.stack=[float('inf')]
        self.nums=[]
    def push(self, val: int) -> None:
        self.nums.append(val)
        self.stack.append(min(val,self.stack[-1]))
    def pop(self) -> None:
        self.nums.pop()#删除栈顶元素
        self.stack.pop()
    def top(self) -> int:
        return self.nums[-1]
    def getMin(self) -> int:
        return self.stack[-1]

'''
    看到一个解放,不使用额外的空间,也没有用顺序查找
    采用了,栈中记录当前元素与最小值的差,并随时对最小值进行更改
'''

class MinStack2:

    def __init__(self):
        self.min=float('inf')
        self.nums=[]
    def push(self, val: int) -> None:
        diff=val-self.min#当前入栈元素,与最小值的差
        self.nums.append(diff)
        if diff<0:
            self.min=val

    def pop(self) -> None:
        diff=self.nums.pop()#删除栈顶元素
        #这里我需要判断一下,最小值是否发生改变
        if diff<0:
            top=self.min
            #说明刚才入栈的时候,他比最小值小,所以变成了最小值,所以需要对最小值进行更改
            self.min=self.min-diff
        else:
            top=self.min+diff
        return top
    def top(self) -> int:
        if self.nums[-1]<0:
            return self.min
        else:
            return self.min+self.nums[-1]
    def getMin(self) -> int:
        return self.min



====================================================================================================================================================================================================================================
412. Fizz Buzz

'''
    ?????
    这也太看不起我了,这题目
    ?????
    卧槽,我看了一下,这个题解下面的文章
    离谱?
    这个,写不出来,写出来要十几分钟?
    妈的
    没赶上好时代
'''

def fun1(n):
    s_ls=[]
    for i in range(1,n+1):
        if i%15==0:
            s_ls.append('FizzBuzz')
        elif i%3==0:
            s_ls.append('Fizz')
        elif i%5==0:
            s_ls.append('Buzz')
        else:
            s_ls.append(str(i))
    return s_ls

====================================================================================================================================================================================================================================
204. 计数质数
这里面有两种算法埃式筛和线性筛
都是很不错的寻找质数的算法,并且线性筛还可以用在别处

'''
    题目要求:
        统计所有小于非负整数 n 的质数的数量。
    质数:
        除了1和他本身外,不能被其他数整除
        1不是质数
'''

'''
    方法一:
        不管3,7二十一
        先暴力,看能不能把题解出来
'''
def fun1(n):
    su = 0  # 进行统计
    for i in range(2, n):
        for j in range(2, i):
            if i % j == 0:
                break
        else:
            su += 1
    return su
#哈哈哈,不出以外,超时了

'''
    现在我们来想一想,如何化简
        我的循环是从2开始,那么除2以外还有  偶数 可能是质数吗,不可能有吧?,那么可以省一半的循环
'''
def fun2(n):
    su = 0  # 进行统计
    if n >= 3:
        su += 1
    for i in range(2, n):
        if i % 2 != 0:
            for j in range(2, i):
                if i % j == 0:
                    break
            else:
                su += 1
    return su

'''超出时间限制'''
'''
    我们可以看到,如果一个数x是质数,那么他的2x,3x,4x......都不会是质数
    如果一个数x不是质数,那么它本身,他的2x,3x,4x....都不会是质数
    基本思路:
        我需要进行几个记录,不然后面的数还是要走一遍
        那么就需要开空间
'''

def fun3(n):
    su = 0  # 进行统计
    ls = [0] * n  # 开空间进行记录
    for i in range(2, n):
        if ls[i] == 0:  # i是当前数,i的整数被不可能为质数
            beishu = 2
            x = beishu * i
            while x < n:
                ls[x] = 1
                beishu += 1
                x = beishu * i

            for j in range(2, i):  # 判断当前数是不是质数
                if i % j == 0:
                    break
            else:

                su += 1
    return su


'''
    超出时间限制
'''


'''
    这里是还可以继续化简的:
        原因在于当前数的n倍可能已经被走过了
'''
def fun4(n):
    su = 0  # 进行统计
    ls = [0] * n  # 开空间进行记录
    for i in range(2, n):
        if ls[i] == 0:  # i是当前数,i的整数被不可能为质数
            x = i* i
            while x < n:
                ls[x] = 1
                x = x+i

            for j in range(2, i):  # 判断当前数是不是质数
                if i % j == 0:
                    break
            else:

                su += 1
    return su

'''
    我看了下答案,发现他直接没有通过循环判断是不是质数
    而是列表对应数等于0时直接加
    为什么?
'''
'''
    吐了,提交通过了,我们来想一下为什么
    埃氏筛
'''
import time
start=time.time()
def fun5(n):
    su = 0  # 进行统计
    ls = [0] * n  # 开空间进行记录
    for i in range(2, n):
        if ls[i] == 0:  # i是当前数,i的整数被不可能为质数
            su+=1       #我觉得这是看规律可以得到的,未排除的数就是可以直接加的
                        #当然,更数学的是这个样子
                        #当前数(i)列表的下标对应元素为0,也就是说,i不是2~~i-1中任意一个的倍数
                        #即i无法整除2~~i-1中的任意一个,所以i是质数
                        #对就是这样

            x = i* i    #这样可以避免重复记录
                        #为什么?
                        #当前数为2,会把所有2的倍数筛选出来
                        #当前数为3,会把所有3的倍数筛选出来
                        #....
                        #这样基本不会出现重复问题
                        #而如果采用倍数问题2*i,3*i,4*i....
                        #每一次都会经过2的倍数,3的倍数,4的倍数...
                        #这样的话,会有大量重复记录
            while x < n:
                ls[x] = 1
                x = x+i
    return su


'''
    线性筛:
        优化方向:每个合数只被标记一次
            因为,前面的
            
    基本思路:
        --标记过程不再仅当x为质数时才进行,而是对每个整数x,都进行
        --对于整数x,不再标记其所有的倍数 x*x, x*(x+1) .....
            而是只标记,质数集合中的数,与x相乘的数
            即:x*质数1,x*质数2,x*质数3......
            并且在x%质数i==0时停止
            *****因为这里的x不一定为质数
                如果是质数,会在超出范围后停止
    核心点:
        如果x%质数i==0,那么对于合数y=x*质数i+1他一定会在遍历到(x//质数i)*质数i+1这个数时被标记
            这里x是可以整除质数i,所以(x//质数i)*质数i+1最后一定会乘以质数i的可以得到y
            保证每一个合数,只能被其最小质因数得到
    
    个人理解:
        合数会有多个质因子
'''

def fun6(n):
    ls=[0]*n
    zhishu=[]
    for i in range(2,n):
        if ls[i]==0:#这个和前面是一样的,i位置的2--i-1都不能整除他
            zhishu.append(i)
        for j in zhishu:#代码在leetcode里面运行不通过,我发现是因为,她会每次执行这个循环
                        #然后会导致,多次循环,但什么都不干
            if i*j<n:
                ls[i*j]=1

            if i%j==0:#结束掉循环,因为y=i*j+1(这个是指位置+1),而这在后面一定会遇到(y),所以不会重复
                break
    return len(zhishu)


def fun7(n):
    ls=[0]*n
    zhishu=[]
    for i in range(2,n):
        if ls[i]==0:#这个和前面是一样的,i位置的2--i-1都不能整除他
            zhishu.append(i)
        for j in zhishu:
            if i*j<n:
                ls[i*j]=1
            else:
                break
            if i%j==0:#结束掉循环,因为y=i*j+1(这个是指位置+1),而这在后面一定会遇到(y),所以不会重复
                break
    return len(zhishu)


print(fun6(10))
print(time.time()-start)

====================================================================================================================================================================================================================================
326. 3的幂

'''
    这种题目,或者说数学问题,基本上都是先暴力,然后再看可不可以优化思路
    基本不存在数学公式解决问题,哈哈哈如果能解决,一般也不会让你写代码
'''


'''
    方法一:
        直接暴力,先剔除小于等于0的数
'''

def fun1(n):
    if n<=0:
        return False
    while n>=3:
        if n%3!=0:
            return False
        n=n//3
    if n==1:
        return True
    else:
        return False

====================================================================================================================================================================================================================================
13. 罗马数字转整数

'''
    这个题目我做过,s中仅仅包含字符(I,V,X,L,C,D,M)
        I可以放在V和X,来表示4和9
        X可以放在L和C,来表示40和90
        C可以放在D和M,来表示400和900
    然后这个题目说,s 是一个有效的罗马数字,所以不会出现I在L的左边的情况
'''

def fun1(s):
    #可以用双指针,i和i+1比较,
    #如果[i]小于[i+1]可以用[i+1]-[i]然后加上去
    #如果[i]大一些就不需要了
    dic={
        'I':1,
        'V':5,
        'X':10,
        'L':50,
        'C':100,
        'D':500,
        'M':1000
    }
    su=0
    i=0
    while i<len(s)-1:
        z=dic[s[i]]
        z1=dic[s[i+1]]
        if z<z1:
            su=su-z
            i+=1
        else:
            su+=z
            i+=1
    su+=dic[s[-1]]
    return su

print(fun1('IV'))


====================================================================================================================================================================================================================================
191. 位1的个数
没写出来,现在也不想看了

'''
    位1的个数:
        这个题目给我的第一感觉,是依靠补码,反码,等来计算
        第二感觉是转化成字符串的循环
'''

'''
    方法一:
        直接暴力,转化成字符串循环就好,反正常数级别
'''
def fun1(n):
    su=0
    n=str(n)
    for i in n:
        su+=eval(i)
    return su
print(fun1(0b00000000000000000000000000001011))

====================================================================================================================================================================================================================================
876. 链表的中间结点

'''
    这个题目就是直接快慢指针写就好了
'''

class ListNode:
    def __init__(self, val=0, next=None):
        self.val = val
        self.next = next
def fun1(head):
    #从head的下一个,第二个节点开始
    if head==None or head.next==None:
        return head#直接返回了
    s=head.next
    q=head.next
    while q.next and q.next.next:
        s=s.next
        q=q.next.next
    return s

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

'''
    这个题目的要求是,你不能只换值,你要换的是链表(如果真的在笔试,就直接换值就好了)
    但现在,我需要学习所以,就改变列表的结构
'''


'''
    这种链表题目,没别的,就是修改指针,就好了
    对于s处于头部时
        s.next=q.next
        q.next=s
    对于s不处于头部是
        s.next=q.next
        q.next=s
        pre.next=q#这里pre是s的上一位,如果不走这一步,那么q.next是s,pre.next也是s
        
'''
def fun1(head):#已通过
    if head==None or head.next==None:
        return head
    #这是第一次转换,因为与其他不一样就单独拿出来了
    s=head
    q=head.next
    s.next=q.next
    q.next=s

    head=q
    while s.next.next and s.next:
        q = s.next.next
        s = s.next
        s.next=q.next
        q.next=s
        pre.next=q
        pre=s
    return head

====================================================================================================================================================================================================================================
725. 分隔链表

'''

    分隔链表:
        --这个题目要求分隔中的每一部分都是连续的片段,不然可以直接一次循环,直接结束
        --所以可以第一次先遍历一遍链表,并进行计数得到n
        --n//k得链表被分成了多少份
        --n%k得余数,这个余数会分配给第一个链表分段到后面得,直到没有
'''


def fun1(head,k):
    ls = []
    pre = head
    jishu = 0
    while pre:
        jishu += 1
        pre = pre.next
    zhengshu = jishu // k
    yushu = jishu % k
    for i in range(k):  # 分k段
        cur = head
        shuzhi = 0
        if (yushu > 0):
            while shuzhi < zhengshu:
                cur = cur.next
                shuzhi += 1
            yushu -= 1
            ls.append(head)
            head = cur.next
            cur.next = None
        else:
            if head == None:
                ls.append(None)
            else:
                while shuzhi < zhengshu - 1:
                    cur = cur.next
                    shuzhi += 1
                ls.append(head)
                head = cur.next
                cur.next = None
    return ls



====================================================================================================================================================================================================================================

'''
    哈哈哈,啥东西都喜欢搞个回文
'''

'''
    这个题目的思路很简单:
        循环+栈
        第一遍的时候循环记录
        第二遍的时候开始比对
        没办法,只有头节点
'''

def fun1(head):
    stack=[]
    node=head
    while node:
        stack.append(node.val)#这里保存值就行了,因为最后比的就是这个
        node=node.next
    #这里不想再出栈了,直接双指针(左右指针)
    left=0
    right=len(stack)-1
    while left<right:
        if stack[left]!=stack[right]:
            #左右不相等
            return False
        left+=1
        right-=1
    return True


'''
    哈哈哈,题目问我能不能用o(n)的时间复杂度和o(1)的空间复杂度
    我写上一个写法的时候突然想到,转换
        --第一次的循环是不可避免的,这是由于链表的性质导致
        --那么想一下我第一次的循环干什么?
            记录呗,一定是需要记录的,没毛病吧?
                那么用栈可以记录用字符串是不是也可以?
                    那么字符串是不是可以转整数(他只有数字)?
        --字符串记录,转整数
        --然后变成了判断该数是不是回文数的问题
            没毛病吧,常数级别的空间吧?
'''

def fun2(head):
    st=''
    while head:
        st+=str(head.str)
        head=head.next
    #我可以转换成数字,然后开始判断是不是回文数,但是偷个懒吧
    shuzhi=eval(st)
    left=0
    right=len(st)-1
    while left<right:
        if st[left] != st[right]:
            # 左右不相等
            return False
        left += 1
        right -= 1
    return True


'''
    果然这种操作还有经典的快慢指针
    quick=quick.next.next
    slow=slow.next
    一个一次走两个,一个一次走一个,那么可以看到quick到了尾部,slow刚好到达中部
    这样将slow和quick之间的链表进行链表反转,继续比较,这样什么空间都没有开
    哈哈哈,流弊(因为上面其实有部分空间开了,只不过数据后面不用了,一切都只是假象哈哈哈)
'''

====================================================================================================================================================================================================================================

'''
    方法一:
        直接暴力
    cur为当前数
    然后不断从右向左遍历,找到[i]==[cur]
    然后开始同时动,不满足回退
    直到cur==i时结束,cur+1
'''

def fun1(s):#提交通过,离谱
    len_=len(s)
    if len_==1:
        return s

    #s中至少有两个元素
    begin=0
    max_=1
    for cur in range(len_):#注意是否存在溢出情况
        for j in range(cur+1,len_):#注意是否存在溢出情况
            if j-cur+1>max_ and huiwen(cur,j,s):
                max_=j-cur+1
                begin=cur
    print(s[begin:begin+max_:])

def huiwen(left,right,s):
    while left<right:
        if s[left]!=s[right]:
            return False
        left+=1
        right-=1
    return True




def fun2(s):#运行超时,最后一个测试用例没通过
    len_=len(s)
    max_=''
    for cur in range(len_):
        i=len_-1
        chongx=cur
        huitui=i
        while cur<i:
            if s[cur]!=s[i]:
                i=huitui-1
                huitui=i
                cur=chongx
            else:
                i-=1
                cur+=1
        if len(max_)<=len(s[chongx:huitui+1:]):
            max_=s[chongx:huitui+1:]
    print(max_)



def fun3(s):#中心扩散方法,一共有n个中心,每个中心o(n)的时间复杂度
    len_ = len(s)
    # 不知道有没有边界条件
    if len_ == 1:
        return s
    begin = 0
    max_ = 1
    for i in range(0, len_ - 1):
        jhw_begin, jhw_max = jhw(i, s)
        ohw_begin, ohw_max = ohw(i, i + 1, s)
        cur_max = max(ohw_max, jhw_max)
        if jhw_max < ohw_max:
            if max_ < ohw_max:
                begin = ohw_begin
                max_ = ohw_max
        else:
            if max_ < jhw_max:
                begin = jhw_begin
                max_ = jhw_max
    return s[begin:begin + max_:]

def jhw(zhongxing,s):
    len_=len(s)
    left=zhongxing-1
    right=zhongxing+1
    while left>=0 and right<len_:
        if s[left]!=s[right]:
            return left+1,right-left-1#因为这里[left]!=[right]所以left和right是不可取的
        left-=1
        right+=1
    return left+1,right-left-1

def ohw(left,right,s):
    len_=len(s)
    while left>=0 and right<=len_:
        if s[left]!=s[right]:
            return left+1,right-left-1
        left-=1
        right+=1
    return left+1,right-left-1


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值