Leetcode题解 0002期

0003题 无重复字符的最长子串【Longest Substring Without Repeating Characters】

题目:
给定一个字符串,找出不含有重复字符的最长子串的长度。
示例:

给定 "abcabcbb" ,没有重复字符的最长子串是 "abc" ,那么长度就是3。
给定 "bbbbb" ,最长的子串就是 "b" ,长度是1。
给定 "pwwkew" ,最长子串是 "wke" ,长度是3。

请注意答案必须是一个子串,"pwke" 是 子序列  而不是子串。

题目不严谨之处:
1. 没有给出数据范围,存在空字符串作为输入的可能性

需要注意:
1. 优化算法
2. 下标处理

解题思路:
1. 纯暴力搜索, O ( n 3 ) O ( n 2 )
2. 伪DP思路优化, O ( n )

这道题一眼望去,第一感觉暴力破解,第二感觉是线性结构上的动态规划,联想题目:最大连续和(给出一个长度为n的序列,求一个连续子序列使得元素总和最大),列出状态转移方程:
子串需要更新的
根据状态转移方程,可以意识到需要优化查询功能,那同0001题一样,使用hashtable(python语言可使用dictionary)来储存对应字符和其下标。由于需要更新substring的内容,所以这样简单的优化只可以使复杂度降至 O ( k n ) ,其中k是一个常数。

这里放上此处代码:

def lengthOfLongestSubstring(s):
       if len(s) == 0: return 0
       d = []
       substr = dict()
       for i in range(len(s)):
           if substr.get(s[i]):
               idx = substr.get(s[i])
               substr=dict()
               for j in range(idx+1, i):
                   substr[s[j]] = j
               substr[s[i]] = i
               d.append(max(1,d[i-1]))
           else:
               substr[s[i]] = i
               if i == 0: 
                   d.append(1)
               else:
                   d.append(max(d[i-1], len(substr)))

       return d[len(s)-1]

现在的挑战是如何使此题复杂度降至 O ( n )
根据子串连续的性质可以得知,我们需要寻找的是一段连续的空间,同时我们不能浪费时间在更新子串上,所以这个地方可以进一步优化。扫描整个字符串,在hashtable中储存对应字符其下标+1(这种存储方式很重要,调试多次才发现应该这样存,其原因应该是如果该字符重复出现,那么新子串起始counting位置应为该字符+1);同时额外添加变量用于储存子串左端下标,若某字符第k次出现(k>1),则判断是否需要更新子串左端下标(考虑发生在”pwwkewp”的三种情况,最末尾的p和中间重复出现的两次w)。这样我们在不更新子串的情况下,通过“跳跃”移动子串左端下标达到间接更新的作用,最后只要实时让ans保持当下子串最长长度,则可以省略d数组的参与,达到空间复杂度为 O ( 1 ) 的优化。

放上最终代码:

def lengthOfLongestSubstring(s):
    if len(s) == 0: return 0
    substr = dict()
    idx = 0
    n = len(s)
    ans = 0
    for i in range(n):
        if s[i] in substr:
            idx = max(idx, substr.get(s[i]))
        substr[s[i]] = i+1
        ans = max(ans, i-idx+1)
    return ans

总而言之,这道题目相对难一些,在优化层面上需要多加考虑,另外包括下标的储存方式。
有待提高!


0004题 两个排序数组的中位数【Median of Two Sorted Arrays】

题目:
给定两个大小为 m 和 n 的有序数组 nums1 和 nums2 。
请找出这两个有序数组的中位数。要求算法的时间复杂度为 O(log (m+n)) 。
示例:

nums1 = [1, 3]
nums2 = [2]
中位数是 2.0

nums1 = [1, 2]
nums2 = [3, 4]
中位数是 (2 + 3)/2 = 2.5

题目不严谨之处:
1. 说明不得当,并不是寻找nums1的中位数和nums2的中位数,而其实是寻找这两个数组合并之后的大数组的中位数。

解题思路:
根据题目要求的时间复杂度,可以得知这是一道明显使用归并思想的二分查找寻找两个有序数列中第k大(小)数的经典题目,在这道题中k就应该是(m+n)/2,如果是偶数的话就是两个最后除以2,复杂度没有变化。
二分思想寻找第k大数的核心就是两个字:舍弃。

a[k/2-1] < b[k/2-1],则a[0] - a[k/2-1]的值必定在合并后的前k个元素中,换言之合并后的中位数第k个元素不可能出现在a[0] - a[k/2-1]这个区间。所以可将a[0] - a[k/2-1]范围的元素抛弃,并将要寻找的第k大数减去抛弃元素的个数。

其他情况相对而言非常容易考虑。这里附上python的代码:

def findKthmax(a, b, i, j, m, n, k):
    if m > n:
        return findKthmax(b, a, j, i, n, m, k)

    if m == 0: return b[j+k-1]
    if k == 1: return min(a[i], b[j])
    x = min(k//2, m)
    y = k - x
    if a[i+x-1] < b[j+y-1]:
        return findKthmax(a, b, i+x, j, m-x, n, k-x)
    else:
        if a[i+x-1] > b[j+y-1]:
            return findKthmax(a, b, i, j+y, m, n-y, k-y)
        else:
            return a[i+x-1]

def findMedianSortedArrays(nums1, nums2):
    m = nums1.__len__()
    n = nums2.__len__()
    tot = m + n
    if tot%2 != 0:
        return findKthmax(nums1, nums2, 0, 0, m, n, tot//2+1)
    else:
        return (findKthmax(nums1, nums2, 0, 0, m, n, tot//2)+findKthmax(nums1, nums2, 0, 0, m, n, tot//2+1))/2

(Python用该方法跑出来的结果都没有直接sort速度快


0005题 最长回文子串【Longest Palindromic Substring】

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

输入: "babad"
输出: "bab"
注意: "aba"也是一个有效答案。

输入: "cbbd"
输出: "bb"

题目相对严谨

经典题目无需注意太多

解题思路:
1. 标准动态规划, O ( n 2 )
2. 经典算法Manacher, O ( n )

经典题目,无需post代码,自行完成。

猜你喜欢

转载自blog.csdn.net/bright_silmarillion/article/details/80520611