Leetcode 前五题 python


最近开始刷题,在此记录一下。

1. Two number (Easy)

给定一个整数数组和一个目标值,该目标值是数组中两个数的和,输出这两个数的标号。注:每个数只能被用一次。

例如:

Given nums = [2, 7, 11, 15], target = 9,
Because nums[0] + nums[1] = 2 + 7 = 9,
return [0, 1].

最直观最暴力的解法就是两重循环,复杂度为 O ( n 2 ) O(n^2) O(n2)

class Solution(object):
    def twoSum(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: List[int]
        """
        n = len(nums)
        for i in range(n):
            dif = target - nums[i]
            for j in range(n):
                if dif == nums[j] and i != j:
                    return [i, j]

这种方法虽然思路简单,但是实在是很慢,leetcode里显示的运行时间是2872 ms,占的空间是11.5 MB。

有没有办法改进呢?答案是肯定的。 改进的方法有很多种,在此我贴出我写的一种:

class Solution(object):
    def twoSum(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: List[int]
        """
        d = {}
        for i, v in enumerate(nums):
            dif = target - v
            if dif in d:
                return ([d[dif], i])
            d[v] = i

可以看到该算法的复杂度为 O ( n ) O(n) O(n)。 leetcode中的运行时间为20 ms, 所占空间为11.8 MB。可以看到运行速度提高了非常非常多!

2. Add Two Numbers (Medium)

给定两个非负非空的链表, 反向遍历这两个链表并将其遍历结果作为两个数,以链表的形式输出这两个数的和。

例如:

Input: (2 -> 4 -> 3) + (5 -> 6 -> 4)
Output: 7 -> 0 -> 8
Explanation: 342 + 465 = 807.

要做这一题,首先得知道什么是链表。
顾名思义,链表其实就是有一条链条连起来的表,哈哈。具体来说,就是表中的数都有两个域,一个是数据域,用于储存具体的数值,还有另外一个指针域,用于指向该数的下一个值。
用这种方式存储的话,好处是很明显的,因为每个数都有其后继的信息,因此一个表中的数在内存中并不需要顺序存储。对内存空间的利用率高,不会造成内存空间碎片。当然,也消耗了更多的内存空间啦。

明白了概念的话,链表的定义实现其实蛮简单的。这一题中也用注释来给大家提示了。

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

运用该定义,一个链表就可以轻易的写出来啦。

l1 = ListNode(1)
l1.next = ListNode(2)
l1.next.next = ListNode(3)

遍历该链表结果如下:

while l1:
    print(l1.val)
    l1 = l1.next

# Result
1
2
3

回到该题,比较简单的思路就是将这两个链表转化成两个数先,算出这两个数的和,然后将结果转换成string, 然后反向,转换成链表就行。

python实现如下:

class Solution(object):
    def addTwoNumbers(self, l1, l2):
        """
        :type l1: ListNode
        :type l2: ListNode
        :rtype: ListNode
        """
        count, num1, num2 = 0, 0, 0
        while l1:
            num1 = num1 + l1.val * pow(10, count)
            count += 1
            l1 = l1.next
        count = 0
        while l2:
            num2 = num2 + l2.val * pow(10, count)
            count += 1
            l2 = l2.next
        sum = num1 + num2
        li = list(reversed(str(sum)))
        output = ListNode(li[0])
        temp = output
        for i in range(1, len(li)):
            temp.next = ListNode(li[i])
            temp = temp.next
        return output

该方法时间复杂度为 O ( n ) O(n) O(n)。 在leetcode中打败了86.11%的人,运行时间为68ms, 内存10.8MB。

当然,其实还有一种更简单的方法。通过观察可知,在不考虑满十进位的情况,其实最终的和就是每个数直接相加,不用倒置。加上进位的话,就只是把向前进位改成向后进位即可。

实现如下:

class Solution(object):
    def addTwoNumbers(self, l1, l2):
        """
        :type l1: ListNode
        :type l2: ListNode
        :rtype: ListNode
        """
        sum = 0
        temp = output = ListNode(0)
        while l1 or l2 or sum:
            if l1:
                sum += l1.val
                l1 = l1.next
            if l2:
                sum += l2.val
                l2 = l2.next
            temp.next = ListNode(sum%10)
            temp = temp.next
            sum = sum//10
        return output.next

可以看到,该实现更加简洁一点。不过时间复杂度,运行时间和所占空间跟上面的方法一样。

3. Longest Substring Without Repeating Characters (Medium)

给定一个字符串,找出其中最长的不重复的子串的长度。

Input: "abcabcbb"
Output: 3 

Input: "bbbbb"
Output: 1

Input: "pwwkew"
Output: 3

关于这一题,我的思路是,首先建一个空的字符串B 和 初始化为0的变量 length,遍历输入的字符串A,如果字符 i 不在B中,则加入B中;反之,则只保留B中从 i 开始往后的子串(包含i)。同时,每遍历一次,则计算一次B的长度,并与 length 对比,如果大于 length, 则将值赋给 length。

例如:

input: "pwwkew"
B = "pw", length = 2
-> w -> B = "w", length = 2
... B = "wke", length = 3
-> w -> B = "kew", length = 3
output: 3 

实现如下:

class Solution(object):
    def lengthOfLongestSubstring(self, s):
        """
        :type s: str
        :rtype: int
        """
        ns = ''
        length = 0
        for i in s:
            if i not in ns:
                ns += i
            else:
                ns = ns.split(i)[-1]
                ns += i
            if len(ns) > length:
                length = len(ns)
        return length        

该方法的时间复杂度为 O ( n ) O(n) O(n)。 在leetcode中打败了86.3%的提交方案,运行时间为48ms, 内存空间占用为11.1 MB。

该题我只提交了一种解决方案。当然,还有无数种方案等着大家挖掘。

4. Median of Two Sorted Arrays (Hard)

给定两个有序的数组,长度分别为 m 和 n, 找到这两个数组的中位数。
该算法的时间复杂度应该为 O ( m + n ) O(m + n) Om+n

这是我做的第一道困难模式的题,哈哈。我感觉其难点在于该题规定了时间复杂度。

如果不考虑时间复杂度的话,其实解决方案并不太难,直接将这两个数组合并,然后找出中位数就行了。最简单的合并方法,直接两重循环就成。但是这样的话时间复杂度并不符合要求。这时,考虑到两个数组是有序的,完全可以用归并排序的思想来做这一题。只取归并排序中的最后一步即可,时间复杂度也是符合要求的。

实现如下:

class Solution:
    def findMedianSortedArrays(self, nums1: 'List[int]', nums2: 'List[int]') -> 'float':
        list_o = []
        i, j = 0, 0
        if len(nums1) == 0:
            list_o = nums2
        elif len(nums2) == 0:
            list_o = nums1
        else:
            while i < len(nums1) and j < len(nums2):
                if nums1[i] < nums2[j]:
                    list_o.append(nums1[i])
                    i += 1
                else:
                    list_o.append(nums2[j])
                    j += 1
            list_o += nums1[i:]
            list_o += nums2[j:]
        r = len(list_o) % 2
        m = len(list_o) // 2
        if r == 1:
            med = list_o[m]
        else:
            med = (list_o[m-1] + list_o[m])/2
        return med

该方法打败了leetcode中69.09%的提交方案,运行时间为96ms,空间为 12.6 MB。

排名不高,所以显然还有更简单的方法。

其实有一种非常非常直观,但是容易被忽略的方法。就是直接合并这两个数组,然后调用 sort() 方法排序就行。我是在讨论区看到这个方法的,当时也是有点沮丧,这么简单的方法我当时居然么有想到!!

Anyway,贴代码吧。

class Solution:
    def findMedianSortedArrays(self, nums1: 'List[int]', nums2: 'List[int]') -> 'float':
        nums1.extend(nums2)
        nums1.sort()
        re = len(nums1) % 2
        m = len(nums1)//2
        if re == 1:
            return nums1[m]
        else:
            return (nums1[m-1]+nums1[m])/2

短短几行,妥妥的。打败了92.8%, 运行时间88ms, 占空间12.8 MB。

5. Longest Palindromic Substring (Medium)

在一个字符串中找最长的回文结构的子串。

这一题我虽然是中等难度的,可是我做了很久… 比上一题hard的还要久很多。中间一度很想看别人的答案。
算了,不多说了。

首先说啥叫回文结构话,白话一点,其实就是对称结构。

例如:

Input: "babad"
Output: "bab"

Input: "cbbd"
Output: "bb"

Input: “xabax”
Output:  “xabax”

那如何简单验证其是否为对称结构呢,就是将这个子串反向,它如果跟正向的一摸一样,就肯定是对称结构啦。

我首先实现了一个非常粗暴的方案:首先找出所有不重复的字符,然后找出每个不重复字符在字符串S中出现的位置 l, 比如 ‘abbba’, -> a: l = [0,4], b: l = [1,2,3] 。然后如果该字符正好出现了两次,则判断其两次之间的子串是否为对称结构。如果不是两次,则对 l 进行两重循环 i, j,判断 i,j之间的子串是否为对称结构。比如 ‘abbb’, -> a, b, bb, bbb.

实现如下:

class Solution:
    def longestPalindrome(self, s: 'str') -> 'str':
        if len(s) == 0:
            return s
        else:
            set_s = set(s)
            leng, pa_s = 0, ''
            for i in set_s:
                ind, l = 0, []
                for j, v in enumerate(s):
                    if i == v:
                        l.append(j)
                if len(l) == 2:
                    sub_s = s[l[ind]:l[ind+1]+1]
                    if sub_s == sub_s[::-1]:
                        if len(sub_s) > leng:
                            pa_s = sub_s
                            leng = len(sub_s)
                else:
                    for i in l:
                        for j in l:
                            sub_s = s[i:j+1]
                            if sub_s == sub_s[::-1]:
                                if len(sub_s) > leng:
                                    pa_s = sub_s
                                    leng = len(sub_s)
            return pa_s

当然,这个方法时间复杂度非常高,有 O ( n 3 ) O(n^3) O(n3)。 提交之后显示打败了打败了26.98%的方案,运行时间为 4084ms, 空间为 12.2 MB.

所以,有非常非常多简单的方法可以实现。

在此贴出一种,该方法非常巧妙,初始化 maxlen 为1,即对于一个字符串来说,至少有一个字符其本身为对称结构。然后从第一个字符开始,不断的验证从第一个字符开始,长度为maxlen的子串是否为对称结构。如果是则调整maxlen的长度。 同时大于一的最小对称结构其实只有两种,一种是 ‘aa’, 另外一种是 ‘aba’。 所以对于一个对称的子串来说,包含其的更大的对称子串只可能是 + 1 或者 + 2。

该代码实现如下:

class Solution:
    def longestPalindrome(self, s: 'str') -> 'str':
        if len(s) == 0:
            return s
        else:
            maxlen, start = 1, 0
            for i in range(len(s)):
                if (i - maxlen) >= 1 and s[(i-maxlen-1):i+1] == s[(i-maxlen-1):i+1][::-1]:
                    start = i-maxlen-1
                    maxlen += 2
                    print(maxlen)
                    continue

                if (i - maxlen) >= 0 and s[(i-maxlen):i+1] == s[(i-maxlen):i+1][::-1]:
                    start = i - maxlen
                    maxlen += 1
                    print(maxlen)
            return s[start:start+maxlen]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值