leetcode实战

leetcode记录

两数之和

题目

给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。

你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。

示例:

给定 nums = [2, 7, 11, 15], target = 9

因为 nums[0] + nums[1] = 2 + 7 = 9
所以返回 [0, 1]

自己的解答

class Solution:
    def twoSum(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: List[int]
        """
        ## 保留数组备份,用于后面查找原始索引
        pre = nums.copy()
        ## 对数组进行排序,因为后面的查找过程是首位递进的,这是以数组元素有序为前提的
        nums.sort()
        ## 创建对称数组
        list = []
        for num in nums:
            list.append(target-num)
        ## 开始首位递进查找,复杂度为O(n)
        j = len(nums) - 1
        i = 0
        while i<j :
            if nums[i] < list[j]:
                i = i+1
            elif nums[i] > list[j]:
                j = j-1
            ## 查找成功,返回索引
            else:
                ## 找到第一个数的索引
                a = pre.index(nums[i])
                ## 为防止结果是一对重复值,调整数组中第一个数的大小,方便查找第二个数的索引(index方法只能查出第一个匹配的索引)
                pre[a] = nums[j] + 1
                b = pre.index(nums[j])
                return a,b

更优解

class Solution:
    def twoSum(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: List[int]
        """
        hashmap = {}
        for index, num in enumerate(nums):
            another_num = target - num
            if another_num in hashmap:
                return [hashmap[another_num], index]
            hashmap[num] = index
        return None

和至少为 K 的最短子数组

题目

返回 A 的最短的非空连续子数组的长度,该子数组的和至少为 K

如果没有和至少为 K 的非空子数组,返回 -1

示例 1:

输入:A = [1], K = 1
输出:1

示例 2:

输入:A = [1,2], K = 4
输出:-1

示例 3:

输入:A = [2,-1,2], K = 3
输出:3

提示:

  1. 1 <= A.length <= 50000
  2. -10 ^ 5 <= A[i] <= 10 ^ 5
  3. 1 <= K <= 10 ^ 9

自己的解答

算法初步思路

st=>start: 开始
e=>end: 结束
op1=>operation: ____sublist____
int head,tail,sum
op2=>operation: sum=0,i=-1
op3=>condition: i<len(A)-1?
op6=>operation: i++,sum=sum+A[i]
op4=>operation: tail=i,outlist.append([head,tail,sum])
sum=sum-A[head],head=head+1
cond1=>condition: A[i]<0?
cond2=>condition: sum>=K?
cond3=>condition: sum>0?
op5=>operation: head=i+1,sum=0
op7=>operation: 遍历outlist,输出

st->op1->op2->op3
op3(yes)->op6->cond1
op3(no)->op7
cond1(no)->cond2
cond2(yes)->op4->op3
cond2(no)->op3
cond1(yes)->cond3
cond3(yes)->op3
cond3(no)->op5->op3
op7->e

关键就在于累加时,如果当前数为正值,则有可能sum>k,此时,由于要找最短子数组,继续累加增长子数组的长度没有意义,所以要将子数组的头部右移一位以继续寻找。如果当前值为负值,那就要看sum加上这个负值的结果,如果不大于0,那么当前的子数组没希望了,首先加上这个负数前它也未能达到要求(达到要求就已经存下来了),其次如果我们将整个子数组丢弃,直接从下一个数重新累加显然要更机智。

算法优化

如果说A数组中负数是少数的,那么可否这么考虑:我们将连续为正或负的元素找出来,获取它的始末位置和和:[head,tail,sum],这个向量构成list。

首先遍历list的元素,如果有大于k的head和tail差值最小的,可以直接输出。这个结果一定最短。可以反向思考:除了这个结果,其他结果都是list中的基础元素相互伸展融合得在的,长度一定大于它。

之后遍历list进行处理,过程类似初始算法。

这里的优化体现在,如果存在连续为正的子数组,算法的执行速度会非常地快。

代码

初始版本,测试用例有十几万个,超出时间限制了

class Solution:
    def shortestSubarray(self, A, K):
        """
        :type A: List[int]
        :type K: int
        :rtype: int
        """
        outlist = []
        head = 0
        nsum = 0
        i = 0
        while i<len(A):
            nsum = nsum + A[i]
            if A[i] >= K:
                return 1
            if A[i] < 0:
                if nsum <= 0:
                    head = i+1
                    nsum = 0
            if (A[i] >0) and (nsum >= K):
                tail = i
                outlist.append(tail-head+1)
                nsum = 0
                head = head +1 
                i = head -1
            i = i+1          
        if outlist:
            outcome = 50000
            for num in outlist:
                if num < outcome:
                    outcome = num
            return outcome
        else:
            return -1

其他

廖雪峰:回数判断

题目

回数是指从左向右读和从右向左读都是一样的数,例如12321909。请编写函数,返回True或False。

自己的解答

def is_palindrome(n):
    n = str(n)
    for i in range(len(n)//2):
        if n[i] != n[len(n)-1-i]: return False
    return True

更优解

def is_palindrome(n):
    if str(n) == str(n)[::-1]:
        return n
posted @ 2019-03-08 19:37  eastzzp  阅读(184)  评论(0编辑  收藏  举报