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

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

        for i in range(len(nums)):
            for j in range(i+1,len(nums)):
                if nums[i]+nums[j] == target:
                    print (nums[i],nums[j])
                    return i,j
        return None

思路1:暴力遍历法,注意第二次循环要从i+1开始,注意range的用法。复杂度高。

 range(start, stop[, step])
        hashmap = {}
        for i,value in enumerate(nums):
            value_need =  target - value
            if value_need in hashmap:
                return [hashmap[value_need],i]
            hashmap[value] = i
        return None

思路2:哈希表法。

来源https://leetcode-cn.com/problems/two-sum/solution/jie-suan-fa-1-liang-shu-zhi-he-by-guanpengchn/

标签:哈希映射
这道题本身如果通过暴力遍历的话也是很容易解决的,时间复杂度在 O(n2)
由于哈希查找的时间复杂度为 O(1),所以可以利用哈希容器 map 降低时间复杂度
遍历数组 nums,i 为当前下标,每个值都判断map中是否存在 target-nums[i] 的 key 值
如果存在则找到了两个值,如果不存在则将当前的 (nums[i],i) 存入 map 中,继续遍历直到找到为止
如果最终都没有结果则抛出异常
时间复杂度:O(n)

2 给出两个 非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字。

如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。

您可以假设除了数字 0 之外,这两个数都不会以 0 开头。

输入:(2 -> 4 -> 3) + (5 -> 6 -> 4)
输出:7 -> 0 -> 8
原因:342 + 465 = 807

思路:先将两链表相加,之后再将其转换成新链表。注意逆序。

        p1 = l1
        p2 = l2
        ten = 1
        num1 = num2 = 0
        while p1:
            num1 = p1.val*ten+num1
            ten  = 10*ten
            p1 =p1.next
        ten = 1
        while p2:
            num2 = p2.val*ten+num2
            ten  = 10*ten
            p2 =p2.next
        result = num1+num2       #以上部分求出两个链表的和的值
        result = str(result)     #转换成字符串
        res = []
        for i in range(len(result)):
            res.append(result[i])
        res.reverse()            #转换成List并倒序
        node =  ListNode(int(res[0]))  #新建一个头节点,注意要把res中的元素变成int
        First = node             #头节点又名first
        for i in res[1:]:        #建立新链表
            node.next = ListNode(int(i))
            node =  node.next
        return First             #返回结果

思路2:一边计算和一边建新链表,注意的是进位与两数长度不同的情况。特殊情况:

        p1 = l1
        p2 = l2
        node = ListNode((p1.val + p2.val)%10)
        First = node
        if p1.val + p2.val>=10:
            carry = 1
        else:
            carry = 0
        while p1.next and p2.next:
            p1 = p1.next
            p2 = p2.next
            if p1.val + p2.val + carry < 10:
                add = p1.val + p2.val + carry
                node.next =  ListNode(add)
                node = node.next
                carry = 0
            else:
                add = (p1.val + p2.val + carry)%10
                node.next =  ListNode(add)
                node = node.next 
                carry  = 1
        while p1.next: #不是if,而是while
            p1 = p1.next
            if p1.val + carry < 10:
                add = p1.val + carry
                node.next =  ListNode(add)
                node = node.next
                carry = 0
            else:
                add = (p1.val + carry)%10
                node.next =  ListNode(add)
                node = node.next 
                carry  = 1
        while p2.next:
            p2 = p2.next
            if p2.val + carry < 10:
                add = p2.val + carry
                node.next =  ListNode(add)
                node = node.next
                carry = 0
            else:
                add = (p2.val + carry)%10
                node.next =  ListNode(add)
                node = node.next 
                carry  = 1
        if carry == 1: #双冒号
            node.next =  ListNode(carry)
            node = node.next 
        return First
执行用时 :
100 ms
, 在所有Python3提交中击败了
88.60%
的用户
内存消耗 :
13.2 MB
, 在所有Python3提交中击败了
52.23%
的用户

小技巧:对于链表问题,返回结果为头结点时,通常需要先初始化一个预先指针 pre,该指针的下一个节点指向真正的头结点head。使用预先指针的目的在于链表初始化时无可用节点值,而且链表构造过程需要指针移动,进而会导致头指针丢失,无法返回结果。

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

        if not s:
            return 0
        nowmax = 1
        temp = []
        res = []
        for i in range(len(s)):
            nowmax = 1
            temp = [s[i]]
            while i+1<len(s) and s[i+1] not in temp: #and的前后顺序
                nowmax = nowmax+1
                i = i+1
                temp.append(s[i])
            res.append(nowmax)
        #print(res)
        return max(res)

思路1:暴力法,最后一个测试用例超出时间限制

        if not s:return 0
        left = 0
        lookup = []
        n = len(s)
        max_len = 0
        cur_len = 0
        for i in range(n):
            cur_len += 1
            while s[i] in lookup:  #如果出现在队列里,则一直右移,直到移除
                lookup.remove(s[left])
                left += 1
                cur_len -= 1
            if cur_len > max_len:max_len = cur_len
            lookup.append(s[i])
        return max_len

思路2:滑动窗口法,https://leetcode-cn.com/problems/longest-substring-without-repeating-characters/solution/hua-dong-chuang-kou-by-powcai/

这道题主要用到思路是:滑动窗口

什么是滑动窗口?

其实就是一个队列,比如例题中的 abcabcbb,进入这个队列(窗口)为 abc 满足题目要求,当再进入 a,队列变成了 abca,这时候不满足要求。所以,我们要移动这个队列!

如何移动?

我们只要把队列的左边的元素移出就行了,直到满足题目要求!

一直维持这样的队列,找出队列出现最长的长度时候,求出解!

时间复杂度:O(n)

4 给定两个大小为 m 和 n 的有序数组 nums1 和 nums2。请你找出这两个有序数组的中位数,并且要求算法的时间复杂度为 O(log(m + n))。你可以假设 nums1 和 nums2 不会同时为空。

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

思路:利用自带的sort函数,注意要int。

5 给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。

class Solution:
    def longestPalindrome(self, s):
        size = len(s)
        if size == 0:
            return ''

        # 至少是 1
        longest_palindrome = 1
        longest_palindrome_str = s[0]

        for i in range(size):
            palindrome_odd, odd_len = self.__center_spread(s, size, i, i)
            palindrome_even, even_len = self.__center_spread(s, size, i, i + 1)

            # 当前找到的最长回文子串
            cur_max_sub = palindrome_odd if odd_len >= even_len else palindrome_even
            if len(cur_max_sub) > longest_palindrome:
                longest_palindrome = len(cur_max_sub)
                longest_palindrome_str = cur_max_sub

        return longest_palindrome_str

    def __center_spread(self, s, size, left, right): #中心扩散算法
        """
        left = right 的时候,此时回文中心是一条线,回文串的长度是奇数
        right = left + 1 的时候,此时回文中心是任意一个字符,回文串的长度是偶数
        """
        l = left
        r = right

        while l >= 0 and r < size and s[l] == s[r]:
            l -= 1
            r += 1
        return s[l + 1:r], r - l - 1

中心扩散算法:https://leetcode-cn.com/problems/longest-palindromic-substring/solution/zhong-xin-kuo-san-dong-tai-gui-hua-by-liweiwei1419/

6 给你一个字符串 s 和一个字符规律 p,请你来实现一个支持 '.' 和 '*' 的正则表达式匹配。

'.' 匹配任意单个字符
'*' 匹配零个或多个前面的那一个元素
所谓匹配,是要涵盖 整个 字符串 s的,而不是部分字符串。

方法一:回溯法

class Solution(object):
    def isMatch(self, text, pattern):
        if not pattern:
            return not text  #如果text为空,则返回True

        first_match = bool(text) and pattern[0] in {text[0], '.'} #不考虑*的情况

        if len(pattern) >= 2 and pattern[1] == '*':
            return (self.isMatch(text, pattern[2:]) or
                    first_match and self.isMatch(text[1:], pattern))
#忽略这一部分,或者删除匹配串的第一个字符,若其能匹配当前位置字符
# 解释:如果发现有字符和 '*' 结合,
    # 或者匹配该字符 0 次,然后跳过该字符和 '*'
    # 或者当 pattern[0] 和 text[0] 匹配后,移动 text

        else:
            return first_match and self.isMatch(text[1:], pattern[1:])

方法二:动态规划

https://leetcode-cn.com/problems/regular-expression-matching/solution/ji-yu-guan-fang-ti-jie-gen-xiang-xi-de-jiang-jie-b/

使用「备忘录」递归的方法来降低复杂度。有了暴力解法,优化的过程及其简单,就是使用两个变量 i, j 记录当前匹配到的位置,从而避免使用子字符串切片,并且将 i, j 存入备忘录,避免重复计算即可。

我将暴力解法和优化解法放在一起,方便你对比,你可以发现优化解法无非就是把暴力解法「翻译」了一遍,加了个 memo 作为备忘录,仅此而已。

# 带备忘录的递归
def isMatch(text, pattern) -> bool:
    memo = dict() # 备忘录
    def dp(i, j):
        if (i, j) in memo: return memo[(i, j)]
        if j == len(pattern): return i == len(text)

        first = i < len(text) and pattern[j] in {text[i], '.'}
        
        if j <= len(pattern) - 2 and pattern[j + 1] == '*':
            ans = dp(i, j + 2) or \
                    first and dp(i + 1, j)
        else:
            ans = first and dp(i + 1, j + 1)
            
        memo[(i, j)] = ans
        return ans
    
    return dp(0, 0)

# 暴力递归
def isMatch(text, pattern) -> bool:
    if not pattern: return not text

    first = bool(text) and pattern[0] in {text[0], '.'}

    if len(pattern) >= 2 and pattern[1] == '*':
        return isMatch(text, pattern[2:]) or \
                first and isMatch(text[1:], pattern)
    else:
        return first and isMatch(text[1:], pattern[1:])

作者:labuladong
链接:https://leetcode-cn.com/problems/two-sum/solution/ji-yu-guan-fang-ti-jie-gen-xiang-xi-de-jiang-jie-b/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

 

9 给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。

示例:

输入:"23"
输出:["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"].

分析:https://leetcode-cn.com/problems/letter-combinations-of-a-phone-number/solution/dian-hua-hao-ma-de-zi-mu-zu-he-by-leetcode/

回溯法:是一种通过穷举所有可能情况来找到所有解的算法。如果一个候选解最后被发现并不是可行解,回溯算法会舍弃它,并在前面的一些步骤做出一些修改,并重新尝试找到可行解。(其实本题就是深度优先搜索)

#官方题解
class Solution:
    def letterCombinations(self, digits):
        """
        :type digits: str
        :rtype: List[str]
        """
        phone = {'2': ['a', 'b', 'c'],
                 '3': ['d', 'e', 'f'],
                 '4': ['g', 'h', 'i'],
                 '5': ['j', 'k', 'l'],
                 '6': ['m', 'n', 'o'],
                 '7': ['p', 'q', 'r', 's'],
                 '8': ['t', 'u', 'v'],
                 '9': ['w', 'x', 'y', 'z']}  #定义一个数字与字母对应的字典,大括号
                
        def backtrack(combination, next_digits): #回溯函数
            # if there is no more digits to check
            if len(next_digits) == 0:   #如果没有数字(最后一位)
                # the combination is done
                output.append(combination)  #添加结果,字符串
            # if there are still digits to check
            else:
                # iterate over all letters which map 
                # the next available digit
                for letter in phone[next_digits[0]]:   #对于第一位对应的每一个字母
                    # append the current letter to the combination
                    # and proceed to the next digits
                    backtrack(combination + letter, next_digits[1:]) #将这个字母与之前字符串相加,将数字后移
                    
        output = []
        if digits:
            backtrack("", digits)
        return output