python练习(二)——失败的

来源:互联网 发布:数据共享的方式 编辑:程序博客网 时间:2024/06/07 05:37

  • 判断链表是否有环
    • 解答
  • 连续子数组求和
    • 暴力解法
    • 暴力解法X2
    • 失败的算法
    • 终于
    • 思路简介
    • 终版
    • 其它
  • 最大子数组 II
    • 思路

感谢这个网站lintcode
但是这个网站居然没有答案???
找不到答案我要死了

还是去leetcode.com吧

判断链表是否有环

给定一个链表,判断它是否有环

解答

def hasCycle(self, head):    # write your code here    if head == None:        return False    l =[head]    n = head.next    while n != None:        if n in l:            return True        else :            l.append(n)            n = n.next    return False    #总耗时: 1539 ms

本来代码没有测传入的链表是不是空的,导致一直报错
后来才意识到的,导致卡了许久

连续子数组求和

给定一个整数数组,请找出一个连续子数组,使得该子数组的和最大。输出答案时,请分别返回第一个数字和最后一个数字的下标。(如果两个相同的答案,请返回其中任意一个)

我写了半天才发现我连什么是连续子数组是什么都不知道!!!

暴力解法

只会暴力解法,写了半天由于各种手残,终于改完了,但是由于运行时间超了,想不出来其它方法,gg
复杂度On3

暴力解法X2

def continuousSubarraySum(self, A):    # Write your code here    l = [0,len(A)-1]    sum = 0    for n in A:        sum += n    s=0    for start in xrange(len(A)):        for n in A[start:]:            s += n        if s >sum:            l[0]= start            sum = s        s=0    for end in xrange(l[0], len(A)):        for n in A[l[0]:end+1]:            s += n        if s >sum:            l[1]= end            sum = s        s=0    return l

复杂度 O(n2)

失败的算法

def continuousSubarraySum(A):    # Write your code here    l = [0,len(A)-1]    sum = 0    for n in A:        sum += n    s=sum    for start in range(len(A)):        s -= A[start]        #if start > 8690 and start < 8720:        #    print s,sum,start,l[0]        if s > sum:            l[0] = start+1            sum = s    s=sum    for end in range(l[0], len(A))[::-1]:        s -= A[end]        if s >sum:            l[1]= end-1            sum = s    return l

本来想着这个算法可以把复杂度降到 O(n)了,可惜出现漏洞了,最开始写的时候感觉好像有些问题,但在运行的时候一直没出错,直到评测。。。。
大致就是[-1,1,-90,-90,-2]这样的序列稳稳会挂。

终于…

这代码后来发现还能够优化,下面有

    def continuousSubarraySum(self, A):        # Write your code here        if max(A)<=0:            return [A.index(max(A)),A.index(max(A))]        l = [0,len(A)-1]        ls = [0,0]        sum = 0        for n in A:            sum += n        s=sum        oldstart=0        ss=0        ssmax=A[0]        for start in range(len(A)):            s -= A[start]            #当当前数字大于等于0 且 过去数组的和小于0,取当前位置为新过去数组的开始            if A[start] >=0 and ss < 0 :                oldstart = start                ss=A[start]            else:#否则,继续累加                ss +=A[start]            #若过去数组的和大于历史过去数组的和的最大值,则刷新历史过去数组的最大值及片段            if ss > ssmax:                ls = [oldstart,start]                ssmax = ss            #若剩余数组的值的和大于历史剩余数组的和,则刷新历史剩余数组的最大值及片段            if s > sum:                l[0] = start+1                sum = s        if s <= ssmax:            return ls        else:            return l

O(n)
中途不知道犯了多少错
后来这变量名起得太随意了导致自己也不清楚什么是什么了,尴尬。然后加了注释就好多了。(暴力方法X2应该是错的)

思路简介

  1. 本来想进行两边遍历,一遍从前往后,一遍从后往前,由此确定子数组的两个边界。
  2. 如何确定呢?先对列表求和,然后逐项减去,如果和变大了,便记录当前位置。从前往后一遍,从后往前一遍,确定起始和结束位置。这算是暴力方法X2的简化版,但由于我在暴力方法X2时便已经错了,所以改版自然也是错的。
  3. 经过测试我发现在某些情况下由于数字顺序的独特性,导致整个子数组都被减掉了。
  4. 我本以为是因为数字中带有负数的原因,尝试将所有数字加上一个足够大的值,由此可以避免这个问题。后来发现数组内所有数字加上一个数之后和原数组完全不是一个东西了,逐放弃
  5. 由于发现正确的子数组有可能被整个删掉,便设想通过监控被删掉的数字进行监控
  6. 在编写代码的时候由于思路并不清晰,导致走了不少弯路。具体思想为
    1. 将数组分为过去数组和剩余数组两部分,由(start)作为分界线,A[start]之前的为过去数组(包括A[start]),之后的为剩余数组(不包括A[start])
    2. 剩余数组的处理(不要看这段的扯淡了,我后来发现这东西的功能让下边的覆盖了,直接删掉都不报错):剩余数组处理和之前相同,当start变化时,若剩余数组的数字之和(s)比之前记录的剩余数组的数字之和最大值(sum)大,则刷新sum,重新记录位置,(l[0]=start+1)**(注意由于程序的编写顺序,此时A[start]已经被从s中删除,所以是start + 1),最终确定剩余数组的数字之和的最大值(sum)及位置 (l)
    3. 过去数组的处理:过去数组的尾部是确定的(start),但是头部是没有确定的(我最初没有意识到这点,吃了不少亏,最初设想为上次存储sum时的start(所以起名为oldstart),但是后来在测试时发现在某些情况下会出错),最终通过不断的修改,确定头部为,当前A[start]的值为零或正整数 且 当前的过去数组的数字之和为负数的时候,重新定位此时为头部(既然过去数组的数字之和是负数,且当前值不为负,之前的还留着作甚),否则正常累加
      当过去数组的数字之和(ss)大于历史过去数组数字之和最大值(ssmax)的时候,刷新ssmax及ls,直到start走到最后这个地方我写着写着,突然发现剩余数组好像没什么用吗,于是我就给删掉了,没报错!!!!!!!!!!!!!
    4. 再后来测试时发现没有考虑列表里全是负数的情况,这个就简单了,判断最大值是不是0或负数,是的话直接返回位置就可以了,其它都不需要了

终版

    def continuousSubarraySum(A):        # Write your code here        if max(A)<=0:            return [A.index(max(A)),A.index(max(A))]        ls = [0,0]        oldstart=0        ss=0        ssmax=A[0]        for start in range(len(A)):            #当当前数字大于等于0 且 过去数组的和小于0,取当前位置为新过去数组的开始            if A[start] >=0 and ss < 0 :                oldstart = start                ss=A[start]            else:#否则,继续累加                ss +=A[start]            #若过去数组的和大于历史过去数组的和的最大值,则刷新历史过去数组的最大值及片段            if ss > ssmax:                ls = [oldstart,start]                ssmax = ss        return ls

就这么几行我写了多久啊啊啊啊啊啊啊啊(不算注释16行),怪不得只是一个中等难度的,心塞QAQ
网上给的分治法不太懂,好像是二分法,使用递归,感觉也不好写啊。

其它

我把这个代码改改贴到其它题下一起完成了
最大子数组
最小子数组

最大子数组 II

给定一个整数数组,找出两个 不重叠 子数组使得它们的和最大。
每个子数组的数字在数组中的位置应该是连续的。
返回最大的和。

兴致勃勃的改了一会代码后,发现
和上边的不一样!!!
本以为是找一个最大子数组之后再找一个,发现不一样!!!

擦,还有这样的数组[-1,-1]

思路

本来想在原有程序的基础上将数组分为最多3段
1. 先进行连续子数组求和,获取最大子数组之和ssmax,以及起始位置,结束位置
2. 然后将数组分为起始位置之前那截(可能没有),最大子数组,结束位置之后那截(可能没有)
3. 判断第一段是否存在
1. 若不存在,l1=0,flag1=0
2. 若存在且最大值为负,l1=最大值,flag1=1
3. l1=最大值, flag1=4
4. 判断第三段是否存在
1. 若不存在,l2=0,flag2=0
2. 若存在且最大值为负,l2=最大值, flag2=1
3. l2=最大值, flag2=4
5. 判断flag1与flag2
1. 当flag1+flag2>=4时,比较l1与l2大小,返回最大值+ssmax
2. 当小于4时,判断第二段长度
1. 若长度大于2,判断最小值
1. 若最小值为正或0,返回ssmax
2. 若最小值为负,获取第二段最小子数组ssmin,返回ssmax-ssmin
2. 若长度等于2 返回ssmax
3. 若长度小于2,返回ssmax+min(l1,l2)

写那么多感觉自己石乐志

然后在62%稳定卡住,还是在一个1000输入的时候…..

不太清楚问题处在哪,估计是算法有漏洞,不想调试了QAQ,上网搜索方法也没有和我一样的,算了,去用另一个网站吧

原创粉丝点击