【数据结构与算法】leetcode刷题记录(无重复最长字串+寻找正序数组的中位数)

无重复字符的最长子串

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

示例 1:

输入: "abcabcbb"
输出: 3 
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
示例 2:

输入: "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。
示例 3:

输入: "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
     请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。

python解决:

1.穷举法:

穷举除所有的字串,放到一个新的列表中,求出最长的连续字串

class Solution:
    def lengthOfLongestSubstring(self, s: str) -> int:
        if len(set(s)) == len(s):
            return len(s)
        list1 = []
        s1 = ""
        for i in range(0,len(s)):
            s1 += s[i]
            for j in s[i+1::1]:
                l2 = list(s1)
                if j not in l2:
                    s1 += j
                else:
                    break
            list1.append(s1)
            s1 = ""
        max = 0
        for k in list1:
            if max <= len(k):
                max = len(k)
        return max
    >>>时间复杂度0(n2)

2.哈希表

​ 1.python使用字典 模拟哈希表:

​ 2.遍历当前字符串: 使用方法 enumerate 方法, 把 i 和 遍历出的 item 组合成 一个字典

​ 3.如果这个 item 的值没有在字典中出现过,那么把这个值添加到字典中 : { item : i } 的格式 , 如果item在字典中,那么返回 当前长度 , 用maxnum 来承接 .

​ 4.下次遍历中比较maxnum 和之前maxnum的大小 , 返回最大值

class Solution:
    def lengthOfLongestSubstring(self, s: str) -> int:
        n = len(s)
        maxnum = 0
        index = -1
        dict1 = {}
        for i, c in enumerate(s):
            if c in dict1:
                index = max(index, dict1[c])
            maxnum = max(maxnum, i - index)
            dict1[c] = i
        return maxnum

java解决方案:

1.穷举: 略

2.哈希表:

​ 思路同python , 使用 Hashmap 对象 , Hashmap 对象使用 put()方法插入元素,使用get(key) = value 方法访问:

class Solution {
    public int lengthOfLongestSubstring(String s) {
        HashMap<Object, Object> dict1 = new HashMap<>();
        int n = s.length();
        int maxnum = 0;
        int index = -1;
        for(int i=0 ;i<s.length();i++){
            int key = s.charAt(i);
            if(dict1.containsKey(key)){
                index = Math.max(index, (Integer)dict1.get(key));
            }
            maxnum = Math.max(maxnum,i-index);
            dict1.put(key,i);
        }
        return maxnum;
    }
}

寻找两个正序数组的中位数

给定两个大小为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。请你找出并返回这两个正序数组的中位数。

进阶:你能设计一个时间复杂度为 O(log (m+n)) 的算法解决此问题吗?

示例 1:

输入:nums1 = [1,3], nums2 = [2]
输出:2.00000
解释:合并数组 = [1,2,3] ,中位数 2
示例 2:

输入:nums1 = [1,2], nums2 = [3,4]
输出:2.50000
解释:合并数组 = [1,2,3,4] ,中位数 (2 + 3) / 2 = 2.5
示例 3:

输入:nums1 = [0,0], nums2 = [0,0]
输出:0.00000
示例 4:

输入:nums1 = [], nums2 = [1]
输出:1.00000
示例 5:

输入:nums1 = [2], nums2 = []
输出:2.00000

python解决:

1.简单的分支:

​ 把列表1 append 到列表2 然后 对列表2 进行排序 , 然后通过列表的索引找到中位数

class Solution:
    def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float:
        for i in nums1:
            nums2.append(i)
        nums2.sort()
        if len(nums2) % 2 == 0:
            mid = (nums2[len(nums2)//2-1] + nums2[len(nums2)//2])/2
        else:
            mid = nums2[len(nums2)//2 ]
        return mid
  1. 动用二分查找解决( 转载自jimimmy00745 发布于 2020-01-21 二分搜索Python3)

    思路
    看到了O(log(m+n))和有序数列,不难想到使用「二分查找」来解决此题。
    可是这道题有两个数列,给找中位数带来了不小的困难,「二分查找」的细节更是举步维艰。
    别怕,可以使用@liweiwei1419大佬总结的「二分查找模板」来快速解决细节问题。
    这个题解可以看作是官方题解的使用「二分查找模板」的改写。
    代码
    交换顺序
    为了减少思考,我们先假定一个序列的长度总不大于第二个。
    如果大于了,那么就交换一下。
    这样子做的原因
    一开始如果不交换 nums1 和 nums2 ,mid2 = half_len - mid1 可能会是负数。

    if len(nums1) > len(nums2):
        nums1, nums2 = nums2, nums1
    

    记录两个序列的长度

    len1, len2 = len(nums1), len(nums2)
    

    记录二分查找的信息
    怎么二分查找呢?
    假设两个序列按顺序合并了,那么中间点的位置就在(len1 + len2 + 1) // 2
    假定这个理想中位数为x
    考虑一般情况下,第一个序列存在一个数,其左边都是小于x,右边都大于。
    对第二个序列也是一样。
    我们对这两个数在各自序列的位置分别称作mid1和mid2。
    所以我们首先先对第一个序列二分查找。
    记录左边界,右边界为第一个序列的左右边界。
    而查找的中间就是左右边界的中间点。
    对于mid2,便是(len1 + len2 + 1) // 2减去mid1

    left, right, half_len = 0, len1, (len1 + len2 + 1) // 2
    mid1 = (left + right) // 2
    mid2 = half_len - mid1
    

    更新二分查找的条件
    上面分析的看起来不错
    可是没有触及怎么更新二分查找的条件
    如何来更新呢?
    不妨这样想,最理想的情况下,两个序列的mid1和mid2应该是一样的。
    这时候mid1左侧和mid2左侧的数都应该比mid1和mid2对应的数小。
    所以可以肯定,如果mid2左侧的数比mid1对应的数都大,那么第一行的中间太靠左了。
    可以这么想,如果mid2左侧的数比mid1对应的都大,那不如第二行的数选小一点而第一行的数选大一点,这样两个数会更接近。
    要把第一行的中间往右,即二分查找的更新left。
    反之更新right。套用模板。
    记得mid1不要越过上限!

    while left < right:
        if mid1 < len1 and nums2[mid2-1] > nums1[mid1]:
            left = mid1 + 1
        else:
            right = mid1
        mid1 = (left + right) // 2
        mid2 = half_len - mid1
    

    返回情况判断
    这道题还困难在它的判断条件上
    完成了这样的二分查找,我们找到了第一行的中间数和第二行的中间数
    我们要返回哪个?还是返回它们的一半?
    如果两个序列的长度和是奇数的话,那么就有一个唯一的中间的数
    而是偶数的话,就是两个中间值平均数
    我们假想两个序列合并并排序,那么就有这个中位数分成左右两块
    我们需要一个左边的最大值和一个右边的最小值
    如何找到左边的最大值呢?
    通常情况下,我们已经找到了mid1和mid2,对比这两个数。
    小的那个就是右边的最小值。
    而对比mid1和mid2左边的数,大的那个就是左边的最大值。
    为什么是这个逻辑呢?为什么左侧两个数的是左边的最大值,而本身就是右边的最小值呢?为什么不是它们本身两者分高低呢?(有点绕,体会一下)
    这样想,因为我们从0到(m + n) // 2总共共有(m + n) // 2 + 1个数(因为下标0也是一个数),这是大于半数的。而减去这俩中位数后,剩下的就正好是一半的数量。这即左半部分。所以我们找的mid其本身应该划分到右边部分。这里可以多找几个测试样例测试几次。
    对了,还有一些特殊情况没考虑,就是比如第一行特别小的情况下,那么左大就是二行的mid2偏左,而右小就是二行的mid2。
    如果总数是奇数,那么输出左大,如果是偶数,输出左大和右小的平均数。

    if mid1 == 0: 
        max_of_left = nums2[mid2-1]
    elif mid2 == 0: 
        max_of_left = nums1[mid1-1]
    else: 
        max_of_left = max(nums1[mid1-1], nums2[mid2-1])
    
    if (len1 + len2) % 2 == 1:
        return max_of_left
    
    if mid1 == len1: 
        min_of_right = nums2[mid2]
    elif mid2 == len2: 
        min_of_right = nums1[mid1]
    else: 
        min_of_right = min(nums1[mid1], nums2[mid2])
    
    return (max_of_left + min_of_right) / 2
    

    完整代码

    class Solution:
        def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float:
            if len(nums1) > len(nums2):
                nums1, nums2 = nums2, nums1
            len1, len2 = len(nums1), len(nums2)
    
            left, right, half_len = 0, len1, (len1 + len2 + 1) // 2
            mid1 = (left + right) // 2
            mid2 = half_len - mid1
    
            while left < right:
                if mid1 < len1 and nums2[mid2-1] > nums1[mid1]:
                    left = mid1 + 1
                else:
                    right = mid1
                mid1 = (left + right) // 2
                mid2 = half_len - mid1
    
            if mid1 == 0: 
                max_of_left = nums2[mid2-1]
            elif mid2 == 0: 
                max_of_left = nums1[mid1-1]
            else: 
                max_of_left = max(nums1[mid1-1], nums2[mid2-1])
    
            if (len1 + len2) % 2 == 1:
                return max_of_left
    
            if mid1 == len1: 
                min_of_right = nums2[mid2]
            elif mid2 == len2: 
                min_of_right = nums1[mid1]
            else: 
                min_of_right = min(nums1[mid1], nums2[mid2])
    
            return (max_of_left + min_of_right) / 2
    

    作者:qsctech-sange
    链接:https://leetcode-cn.com/problems/median-of-two-sorted-arrays/solution/dong-yong-er-fen-cha-zhao-mo-ban-lai-qiao-miao-jie/

java解决

1.分支:

​ 建立一个新数组,把两个数组遍历一遍添加进来,然后排序,然后查找:

class Solution {
    public double findMedianSortedArrays(int[] nums1, int[] nums2) {
        int [] midarr = new int[nums1.length+ nums2.length];
        int i = 0;
        double mid;
        for(int item : nums1){
            midarr[i] = item;
            i++;
        }
        for(int item : nums2){
            midarr[i] = item;
            i++;
        }
        Arrays.sort(midarr);
        if (midarr.length%2==0){
            int index = midarr.length/2 ;
            mid =   (double) (midarr[index-1]+midarr[index])/2;
        }else{
            int index = midarr.length/2 ;
            mid = midarr[index];
        }
        return mid;
    }
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值