【Leetcode刷题笔记 持续更新】热题TOP100篇

3. 无重复字符的最长子串

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

思路:
最长,最大问题其实通常都会想到的是动态规划,而动态规划最开始都是由dp数组来实现的,但是通常在优化算法的时候dp算法都会被优化成几个变量,这其实也就可以看作是滑动窗口。
这个题是要求找出最长字串的长度,那么dp数组dp[i]表示的是截止到i处,最长字串的长度。那么此时dp[i]的值有以下几种情况:
1.在最长字串中没有出现过dp[i]这个字母,那么dp[i]=dp[i-1]+1,随之更新max。
2.在最长字串中已经有dp[i]这个字母,发生了重复,那么就要判断是两个重复子串之间的长度大,还是max大,两者取大者。
而通过分析发现,其实我们只用到了dp[i-1]和dp[i]两个,没有必要使用一个数组,所以我们只需要一个dp变量就可以了

还有一点就是向哈希表里添加元素的时候要在遍历的时候再加,如果提前初始化,会使得重复的字母覆盖下标,导致后面遍历出错。因此要在遍历的时候,一边取一边加,这样就能防止元素被覆盖

代码:

class Solution {
    public int lengthOfLongestSubstring(String s) {
        if(s.length()==0) return 0;
        Map<Character,Integer> map = new HashMap<>();
        int dp=0,max=0;
        for(int i=0;i<s.length();i++){
            //边取边加
            int index=map.getOrDefault(s.charAt(i),-1);
            map.put(s.charAt(i),i);
        
            if(i-index > dp){
                dp++;
            } else {
                dp=i-index;
            }
            max=Math.max(max,dp);
        }
        return max;
    }
}

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

给定两个大小分别为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。请你找出并返回这两个正序数组的 中位数
算法的时间复杂度应该为 O(log (m+n))

思路:
如果不要求复杂度的话这个题特别简单,不管是直接连接后sort还是遍历取中位数都能做出来。但是这个题要求了时间复杂度为log,并且还是两个正序数组。
刷了几天的题之后,现在看到正序数组就想到了二分法,并且二分法的时间复杂度也是log,基本确定这个题是二分解法。题目要求的是中位数,那么就可以先分析问题了。
当m+n为奇数时,那么中位数便是下标为(m+n)/2的那个数;当m+n为偶数时,那么中位数便是下标为(m+n)/2-1,(m+n)/2这两个数的平均数。众所周知中位数前后元素个数相同,两个数组都是正序,但是数字的大小不确定。那么我们其实可以用一条线将两个数组进行分割,前面一组元素的个数需要等于或大1比后面的那一组(大1是因为m+n为奇数的时候直接比较前面一组中两个数组的最后一个元素就可以,因此在确定长度的时候需要向上取整,向上取整之所以可用是因为对于偶数向上取整没有影响,还是之前的结果),并且前面一组的第一个数组最后一个值要小于后面一组第二个数组的第一个值,第二个数组最后一个值要小于后面一组第一个数组的第一个值。那么中位数就是前面一组中两个数组最后一个数的最大值和后面一组中两个数组第一个数的最小值的平均值。
那么问题来了,怎么确定线的位置呢,这就要用到二分法了,通过二分来判断线的位置是否满足预期的要求。

代码:

class Solution {
    public double findMedianSortedArrays(int[] nums1, int[] nums2) {
        int len1=nums1.length;
        int len2=nums2.length;
        if(len1>len2){
            return findMedianSortedArrays(nums2,nums1);
        }

        int leftlength = (len1+len2+1)/2;
        int left=0;
        int right=len1;
        while(left<right){
            int i = left+(right-left+1)/2;
            int j = leftlength-i;
            if(nums1[i-1]>nums2[j]){
                right=i-1;
            } else {
                left=i;
            }
        }
        int i=left;
        int j=leftlength-i;
        int nums1leftmax= i==0?Integer.MIN_VALUE:nums1[i-1];
        int nums1rightmin= i==len1?Integer.MAX_VALUE:nums1[i];
        int nums2leftmax= j==0?Integer.MIN_VALUE:nums2[j-1];
        int nums2rightmin= j==len2?Integer.MAX_VALUE:nums2[j];

        if((len1+len2)%2==1) return Math.max(nums1leftmax,nums2leftmax);
        else return (Math.max(nums1leftmax,nums2leftmax)+Math.min(nums1rightmin,nums2rightmin))/2.0;
    }
}

你可能感兴趣的:(刷题笔记,leetcode,算法,数据结构)