LeetCode Q1-Q5练习笔记 (Python3)

LeetCode Q1-Q5

  • Q1 两数之和 Two Sum
  • Q2 两数相加 Add Two Numbers(链表)
  • Q3 无重复字符的最长子串 Length of longest substrings
  • Q4 寻找两个正序数组的中位数 Find Median Sorted Arrays
  • Q5 最长回文子串 Longest Palindrome
  • Q1-5 一些笔记

Q1 两数之和 Two Sum

给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 的那 两个 整数,并返回它们的数组下标
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素不能使用两遍。
你可以按任意顺序返回答案。

我一开始的解答用了双循环,时间复杂度为O(n2),成功通过

def twoSum(nums,target):
    sol=[]
    if len(nums)<2:
        return sol
    for i in range(len(nums)):
        for j in range(i+1,len(nums)):
            if nums[i]+nums[j]==target:
                sol.append([i,j])
    return sol

之后看了别人的答案,他们用到了字典的方式,达到了O(n)的时间复杂度,dic[nums[i]]=i 这个不能写在下面的if条件之上,原因是每一次遍历不能因为target-nums[i]等于nums[i]而出现下标与自身相同的情况

def twoSum(nums,target):
	dic={
     }
    for i in range(len(nums)):
    
        #dic[nums[i]]=i 		# 这个不能写在下面的if条件之上,原因是每一次遍历不能因为
        						# target-nums[i]=nums[i]而出现下标与自身相同的情况
        				
        if target-nums[i] in dic:
            return [dic[target-nums[i]],i]
        dic[nums[i]]=i 			# 写在if下面才是对的

在之后自己的改进过程中,我给if语句加了一个判断,反而提高了运行的速率:

def twoSum(nums,target):
	dic={
     }
    for i in range(len(nums)):
            
	if target-nums[i] in dic and dic[target-nums[i]]!=i: 
		return [dic[target-nums[i]],i]
	dic[nums[i]]=i

Q2 两数相加 Add Two Numbers(链表)

给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。
请你将两个数相加,并以相同形式返回一个表示和的链表。
你可以假设除了数字 0 之外,这两个数都不会以 0 开头。
LeetCode Q1-Q5练习笔记 (Python3)_第1张图片

这个是我的错误答案,在最后的判断中,应该是判断当前的l1与l2是否为空值,因为就算next值为空,也可以指向next节点。同时在声明链表以后还需要声明一个指代这个链表的节点,我理解为c语言中的head

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode:
        c=0
        l=ListNode(0)
        l3=l 					# 很关键,声明链表以后还需要再声明一个指代这个链表头的节点
        while l1 or l2:

            a=l1.val if l1 else 0
            b=l2.val if l2 else 0

            val = a + b + c
            
            c=val//10

            l3.next=ListNode(val%10)
            l3=l3.next
            
            if l1.next: # 错误
                l1=l1.next
            if l2.next: # 错误
                l2=l2.next
        if c>1:
            l3.next=ListNode(1)
        
        return l.next

以下是需要修改的地方

            if l1: # 若当前值不为空,则去下一个节点
                l1=l1.next
            if l2:
                l2=l2.next

链表是个很基础的题型,以下是自己学习归纳的需要注意的地方:
1)先声明链表头节点
2)声明一个指针指向链表头节点
3)通过指针在while循环中每一次指向自己的next属性,来实现链表的遍历
4)当现在的指针不为空时,就可以指向下一个节点

Q3 无重复字符的最长子串 Length of longest substrings

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

这道题我曾经写出来过,但是用的方法是耗时70多ms,我觉得并不是最优解,这次再看别人的答案,比我的厉害特别多。我的思路是从字符串开头进行遍历,每次与之前的元素做对比,从而获得最优解的数组得出数组长度,但是这种思路非常有局限性,实现起来也很繁琐,如果字符串稍微复杂一点便难以实现。

这位大神的答案十分的言简意赅,他通过字典的方式存储所有字符,直到找到下一个相同的字符,用最后字符的位置加1减去前一个字符的位置取得该不重复字符的长度(因为得包含相同字符中的一个所以要加1),但还是有些没弄懂,得再吸收一下。

class Solution:
    def lengthOfLongestSubstring(self, s):
        """
        :type s: str
        :rtype: int
        """
        st = {
     }
        i, ans = 0, 0
        for j in range(len(s)):
            if s[j] in st:
                i = max(st[s[j]], i)
            ans = max(ans, j - i + 1)
            st[s[j]] = j + 1
        return ans;

Q4 寻找两个正序数组的中位数 Find Median Sorted Arrays

这道题如果想直接实现的话其实并不难,但作为一道Hard难度的题目,他将答案的时间复杂度限制在O(log(m+n))。

我之后再来填补这道题吧,现在确实看着有些繁琐。

Q5 最长回文子串 Longest Palindrome

给你一个字符串 s,找到 s 中最长的回文子串。

被整吐了,先是自己尝试用暴力破解法失败了,看了官方解释的中心扩散法也失败了,最后还是看着答案搞完的,自己归纳了几个需要注意的点:

  1. 我在这个方法中本来用了一个标志位judge来判断长度的奇偶性从而进行分类讨论,但是我对于回文序列的思路想错了,不论是奇数字符串还是偶数字符串是都有可能有奇偶回文序列的。这个标志位应该是针对回文序列而不是针对原字符串,这也导致了我的写法无法得到正确的解
  2. 其次,我的想法是将leftright变量变成与索引i相减和相加得到回文序列的起点和终点,虽然这样可行,但是对于边界的处理会很复杂,不如直接如答案中将leftright直接设置为起点和终点
  3. 这个答案中的一个比较精妙的点是findCenter(s,left,right)这个函数的设计,因为并不知道这个字符串中回文序列的奇偶性,当调用这个函数时,不仅可以让奇偶同时被讨论,而且对于答案互不影响。
class Solution:
    def longestPalindrome(self, s: str) -> str:
        def findCenter(s,left,right):#放上面
            while left>=0 and right<len(s) and s[left]==s[right]:
                left-=1
                right+=1
            return left+1,right-1

        if len(s)<2:
            return s

        judge=0 if len(s)%2==0 else 1 #本来是用来判断长度的奇偶性从而分类讨论


        start,end=0,0
        maxLen=0
        lst=[]
        for i in range(len(s)):
            #if judge ==1:
            left1,right1= findCenter(s,i,i)
            if right1-left1>end-start:
                start,end=left1,right1
                # if right-left>maxLen:
                #     maxLen=right-left
                #     lst=[left,right]

            #else:
            left2,right2=findCenter(s,i,i+1)
            if right2-left2>end-start:
                start,end=left2,right2
                # if abs(right-left)>maxLen:
                #     maxLen=abs(right-left)
                #     lst=[left,right]


        sol=s[start:end+1]



        return sol

Q1-5 一些笔记

  1. python中对列表进行赋值时,不能直接让list1=list2,这只会让他们地址相同而一起发生改变,要使用切片:list1[:]=list2[:]
  2. 列表的索引只能是整数,若在其中用到了除法表达式也需要是整除//
  3. 字串(Substring) 是原始字符串的一个连续子集。
    子序列(Subsequence)是原始字符串的一个子集。
  4. 希望自己可以养成调用函数的习惯,事先将一些实现重复功能的函数单独写出来,可以使代码易于修改并看上去更加美观。之前在练习java的时候总是将不同功能分为不同的类,这种习惯反而在python中坚持的少了
  5. 字典在python中用于查找列表与字符串中的特定位置元素还是很好用的,多换换思维方式,不要总想着暴力地遍历所有值。字典适用于单一的元素查找,适合找特定开头和结尾的字符串,如Q1和Q3,但如果是对于Q5这道回文序列就显得不太实用了。

你可能感兴趣的:(python,算法,数据结构)