LeetCode热题100道-Day02

11,765 阅读2分钟

LeetCode热题100道-Day02

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

  • 算法的时间复杂度应该为 O(log (m+n)),所以这里应使用二分法。定义sum为nuns1和nums2的长度和,如果sum为奇数,则找sum/2+1小的元素即为中位数,为偶数,则找sum/2,sum/2+1这两个元素。分析三种边界情况,如果index1等于len1,即越界,则返回nums2的第k小元素,index2越界,返回nums1的第k小元素,k等于1时,返回nums1第一个元素和nums2第一个元素中较小数。比较nums1[k/2-1]和nums2[k/2-1]如果nums1的小,则nums1[0]至nums1[k/2-1]这些元素都不可能是第k小元素,删除掉这些元素,再修改k,k要减去之前删除的那些元素,index1也要修改,待下轮使用。nums2小的话同理。
class Solution {
    public double findMedianSortedArrays(int[] nums1, int[] nums2) {
        int len1 = nums1.length;
        int len2 = nums2.length;
        int sum = len1 + len2;

        if (sum % 2 != 0) {
            int midIndex = sum / 2 + 1;
            return getKthElement(nums1, nums2, midIndex);
        } else {
            int midIndex_1 = sum / 2;
            int midIndex_2 = sum / 2 + 1;
            double a = getKthElement(nums1, nums2, midIndex_1);
            double b = getKthElement(nums1, nums2, midIndex_2);
            return (a + b) / 2.0;
        }
    }

    private int getKthElement(int[] nums1, int[] nums2, int k) {
        int len1 = nums1.length;
        int len2 = nums2.length;
        int index1 = 0;
        int index2 = 0;
        while (true) {
            if(index1 == len1) {
                return nums2[index2 + k - 1];
            }
            if(index2 == len2) {
                return nums1[index1 + k - 1];
            }
            if(k == 1) {
                return Math.min(nums1[index1], nums2[index2]);
            }
            int half = k / 2;
            int newIndex1 = Math.min(index1 + half, len1) - 1;
            int newIndex2 = Math.min(index2 + half, len2) - 1;
            int pivot1 = nums1[newIndex1];
            int pivot2 = nums2[newIndex2];
            if(pivot1 <= pivot2) {
                k -= (newIndex1 - index1 + 1);
                index1 = newIndex1 + 1;
            } else {
                k -= (newIndex2 - index2 + 1);
                index2 = newIndex2 + 1;
            }
        }
    }
}

5. 最长回文子串

  • 此题可以使用动态规划的方法来解决,确定状态转移方程:dp[i][j] = dp[i + 1][j - 1]。定义dp数组,dp[i][j] 数组的含义: 下标 i 到 j 的字串是不是回文串(i < j),初始化dp数组,max为最大回文串的长度,start最大回文串的起始位置。进行遍历,如果字串的首位不相等,那么一定不是回文串,如果首位字符相等,处理边界条件,只要 dp[i][j] == true 成立,就表示子串 s[i..j] 是回文,此时记录回文长度max和起始位置start。
class Solution {
    public String longestPalindrome(String s) {
        int len = s.length();
        
        boolean[][] dp = new boolean[len][len];
        for (int i = 0; i < len; i++) {
            dp[i][i] = true;
        }

        char[] arr = s.toCharArray();
        int max = 1, start = 0;

        for (int j = 1; j < len; j++) {
            for (int i = 0; i < len - 1 && i < j; i++) {

                if (arr[i] != arr[j]) {
                    dp[i][j] = false;
                } else {
                    if (j - i <= 2) {
                        dp[i][j] = true;
                    } else {
                        dp[i][j] = dp[i + 1][j - 1];
                    }
                }

                if (dp[i][j] && j - i + 1 > max) {
                    max = j - i + 1;
                    start = i;
                }
            }
        }
        return s.substring(start, start + max);
    }
}

10. 正则表达式匹配

  • 此题使用动态规划解决,按照动态规划步骤来
class Solution {
    public boolean isMatch(String s, String p) {
        //加1是为处理空字符串的情况,比如说p为空,s为空时什么情况
        int m = s.length() + 1;
        int n = p.length() + 1;
        //动态数组里面加了一列和一行空字符串的匹配情况
        boolean[][] dp = new boolean[m][n];
        dp[0][0] = true;
        
        for (int j = 2; j < n; j++) {
            if (p.charAt(j - 1) == '*') {
                dp[0][j] = dp[0][j - 2];
            }
        }

         for (int r = 1; r < m; r++) {
            //r为dp里面的行,c为dp里面的列
            int i = r - 1;
            //
            for (int c = 1; c < n; c++) {
                int j = c - 1;
                //当 s[i] = p[j] || p[j] == '.'
                if (s.charAt(i) == p.charAt(j) || p.charAt(j) == '.') {
                    //动态转移方程为dp[r][c] = dp[r - 1][c - 1]
                    dp[r][c] = dp[r - 1][c - 1];
                } else if (p.charAt(j) == '*') {
                    //p[j-1] == s[i] || p[j-1] == '.', 如果是 * 的前一个字符为 . 那我们只需要看 . 的前面字符匹配情况
                   
                    if (p.charAt(j - 1) == s.charAt(i) || p.charAt(j - 1) == '.') {
                        dp[r][c] = dp[r - 1][c] || dp[r][c - 2];
                    //其他情况:p[j-1] 不是s[i]或者
                    } else {
                        dp[r][c] = dp[r][c - 2];
                    }
                } else {
                    dp[r][c] = false;
                }

            }
        }
        return dp[m - 1][n - 1];
    }
}