leetcode刷题记录 | 青训营

30 阅读2分钟

在做项目的同时别忘了刷力扣嗷^^

一、圆和矩形是否有重叠

1、问题

image.png

2、解答

可以用求圆心到矩形区域的最短距离判断圆形和矩形是否相交。

在求圆与直线的位置关系时,常常会计算圆心到直线的垂直线段的距离。这条垂直线段的距离小于半径的时候,说明两者相交。进一步考虑是因为这条垂直线段的长度已经是圆心到直线上任意点中最小的了,若最小的线段长度比圆半径小,说明存在点在圆内。

因此,可以分解成两个问题,即圆心到区域x1≤x≤x2的最小值xmin和圆心到区域y1≤y≤y2的最小值ymin:

image.png

圆心到矩阵区域的最小距离就是

image.png

因此,代码如下:

class Solution {
    public boolean checkOverlap(int radius, int xCenter, int yCenter, int x1, int y1, int x2, int y2) {
        double dist = 0;
        if(xCenter < x1 || xCenter > x2)
        dist += Math.min(Math.pow(x1 - xCenter,2),Math.pow(x2 - xCenter,2));
        if(yCenter < y1 || yCenter > y2)
        dist += Math.min(Math.pow(y1 - yCenter,2),Math.pow(y2 - yCenter,2));
        return dist <= radius * radius;
    }
}

二、无重复字符的最长字串

虽然做过很多遍了,但是隔了段时间总要忘,特此记录一下。

1、问题

image.png

2、解答

滑动窗口!滑动窗口!滑动窗口! 如何移动?只需要把队列的左边元素移出即可!!

class Solution {
    public int lengthOfLongestSubstring(String s) {
        if(s.length() == 0) return 0;
        int max = 0;
        int left = 0;
        HashMap<Character,Integer> map = new HashMap<>();
        for(int i = 0;i < s.length();i++){
            if(map.containsKey(s.charAt(i))){
                left = Math.max(left,map.get(s.charAt(i)) + 1);
            }
            map.put(s.charAt(i),i);
            max = Math.max(max,i - left + 1);
        }
        return max;
    }
}

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

1、问题

image.png

2、解答

这道题如果用暴力解法会非常简单,但是无法满足时间复杂度为O(log(m+n)),因此必须换个思路。

为了达到log级的时间复杂度,我们只有用到二分的方法才能达到。题目是求中位数,其实就是求第k个小数的一种特殊情况。

由于数列是有序的,我们可以一半一半地排除。假设我们要找第k个小数,那么我们可以每次循环排除掉k/2个数。

假设我们要找第7小的数字。

image.png

比较两个数组的第k/2个数字,也就是7/2=3个数字,上边数组中的4和下边数组中的3,如果哪个小,就表明该数组的前k/2个数字不是第k小数字,所以可以排除。即1,2,3这三个数字不可能是第7小的数字,我们可以将它们排除掉。将1349和45678910两个数组作为新的数组进行比较。

由于我们已经排除掉了3个数字,也就是说这3个数字一定在最前边,因此在两个新数组中,我们只要找第7-3=4小的数字即可,也就是k=4。此时k/2=2,因此比较第2个数字,3<5,所以我们可以把第一个数组中的1,3排除掉。

image.png

我们又排除掉了2个数字,因此现在要找第4-2=2小的数字即可。此时比较两个数组中的第k/2=1个数,4==4怎么办呢?由于两个数相等,因此我们无论去掉哪个数组中的都行,因此假设将下面数组的4去掉。

image.png

由于又去掉了1个数字,因此我们要找第2-1=1小的数字,所以只需判断两个数组中第一个数字哪个小即可,也就是4。

因此第7小数字是4。

class Solution {
    public double findMedianSortedArrays(int[] nums1, int[] nums2) {
        int n = nums1.length;
        int m = nums2.length;
        //因为数组是从索引0开始的,因此必须+1,即索引(k + 1)的数,才是第k个数。
        int left = (n + m + 1) / 2;
        int right = (n + m + 2) / 2;
        return(getKth(nums1,0,n - 1,nums2,0,m - 1,left) + getKth(nums1,0,n - 1,nums2,0,m - 1,right)) * 0.5;
    }

    private int getKth(int[] nums1,int start1,int end1,int[] nums2,int start2,int end2,int k){
        int len1 = end1 - start1 + 1;
        int len2 = end2 - start2 + 1;
        if(len1 > len2) return getKth(nums2,start2,end2,nums1,start1,end1,k);
        if(len1 == 0) return nums2[start2 + k - 1];
        if(k == 1) return Math.min(nums1[start1],nums2[start2]);

        int i = start1 + Math.min(len1,k / 2) - 1;
        int j = start2 + Math.min(len2,k / 2) - 1;

        if(nums1[i] > nums2[j]) return getKth(nums1,start1,end1,nums2,j + 1,end2,k - (j - start2 + 1));
        else return getKth(nums1,i + 1,end1,nums2,start2,end2,k - (i - start1 +1));

    }
}

四、最大回文子串

1、问题

image.png

2、解答

使用动态规划。对于一个字串而言,若它是回文串且长度大于2,那么将它首尾的两个字母去除后,它仍然是一个回文串。

用P(i,j)表示字符串s的第i到第j个字母组成的串是否为回文串:

image.png

这里的其他情况包含两种可能性:

image.png

那么就可以写出动态规划的状态转移方程:

image.png

即只有s[i + 1,j - 1]是回文串,并且s的第i个字母和第j个字母相同时,s[i,j]才会是回文串。 上文所有讨论是建立在字串长度大于2的前提上的,还需要考虑动态规划的边界条件,即子串的长度为1或是2.对于长度为1的字串,显然它就是个回文串;对于长度为2的字串,只要它的两个祖母相同,它就是回文串。因此我们可以写出动态规划的边界条件:

image.png


class Solution {
    public String longestPalindrome(String s) {
        int len = s.length();
        int maxLen = 1;
        int begin = 0;
        if(len < 2) return s;
        boolean[][] dp = new boolean[len][len];
        char[] ch = s.toCharArray();
        for(int i = 0;i < len;i++){
            dp[i][i] = true;
        }

        for(int L = 2;L <= len;L++){
            for(int i = 0;i < len;i++){
                int j = L + i - 1;
                if(j >= len) break;
                if(ch[i] != ch[j]) dp[i][j] = false;
                else{
                    if(j - i  < 3) dp[i][j] = true;
                    else dp[i][j] = dp[i + 1][j - 1];
                }
                if(dp[i][j] && j - i + 1 > maxLen){
                    maxLen = j - i + 1;
                    begin = i;
                }
            }
        }
        return s.substring(begin,begin + maxLen);
    }
}