leetcode刷題(持續(xù)更新)

  1. 從尾到頭打印鏈表

    輸入一個鏈表的頭節(jié)點,從尾到頭反過來返回每個節(jié)點的值(用數(shù)組返回)吉挣。

    示例 1:

    輸入:head = [1,3,2]
    輸出:[2,3,1]
    

    分析:可以首先遍歷一次鏈表崖蜜,獲得鏈表的長度,創(chuàng)建一個相同長度的數(shù)組,然后再從頭到尾遍歷一次苟鸯,從數(shù)組的尾部開始添加元素。

    /**
     * Definition for singly-linked list.
     * public class ListNode {
     *     int val;
     *     ListNode next;
     *     ListNode(int x) { val = x; }
     * }
     */
    class Solution {
        public int[] reversePrint(ListNode head) {
            //先獲取鏈表長度棚点,創(chuàng)建對應(yīng)長度數(shù)組
            ListNode currNode = head;
            int len = 0;
            while(currNode != null){
                len ++;
                currNode = currNode.next;
            }
            int[] result = new int[len];
            
            //再次遍歷鏈表早处,將值倒序填充至結(jié)果數(shù)組
            currNode = head;
            while(currNode != null){
                result[len - 1] = currNode.val;
                len --;
                currNode = currNode.next;
            }
            return result;
        }
    }
    
  2. 二維數(shù)組的查找

    在一個 n * m 的二維數(shù)組中,每一行都按照從左到右遞增的順序排序瘫析,每一列都按照從上到下遞增的順序排序砌梆。請完成一個函數(shù)默责,輸入這樣的一個二維數(shù)組和一個整數(shù),判斷數(shù)組中是否含有該整數(shù)咸包。

示例:

現(xiàn)有矩陣 matrix 如下:

[
  [1,   4,  7, 11, 15],
  [2,   5,  8, 12, 19],
  [3,   6,  9, 16, 22],
  [10, 13, 14, 17, 24],
  [18, 21, 23, 26, 30]
]

給定 target = 5桃序,返回 true。

給定 target = 20烂瘫,返回 false媒熊。

分析:這個二維數(shù)組有一個特點,右上角的元素是這行中最大的忱反,是這列中最小的泛释,這種類似二叉樹。

class Solution {
    public static boolean findNumberIn2DArray(int[][] matrix, int target) {
        if(matrix == null || matrix.length == 0 || matrix[0].length == 0){
            return false;
        }
        int rows = matrix.length;
        int columns = matrix[0].length;
        int row = 0;
        int column = columns - 1;
        if(target<matrix[0][0] || target > matrix[rows-1][column]){
            return false;
        }
        while (row<=rows-1 && column >=0){
            //如果相等温算,直接返回true
            if(target == matrix[row][column]){
                return true;
            }
            //如果小于當(dāng)前元素怜校,列數(shù)減一
            else if(target<matrix[row][column]){
                column--;
            }
            //如果大于當(dāng)前元素,行數(shù)加一
            else {
                row++;
            }
        }
        return false;

    }
}
  1. 重建二叉樹

    輸入某二叉樹的前序遍歷和中序遍歷的結(jié)果注竿,請重建該二叉樹茄茁。假設(shè)輸入的前序遍歷和中序遍歷的結(jié)果中都不含重復(fù)的數(shù)字。

    例如巩割,給出

    前序遍歷 preorder = [3,9,20,15,7]
    中序遍歷 inorder = [9,3,15,20,7]
    返回如下的二叉樹:

         3
        / \
      9  20
        /  \
       15   7
    

    分析:只要知道一個二叉樹的中序遍歷結(jié)果以及先序遍歷和后序遍歷中的一個裙顽,就能完整地構(gòu)建出這棵二叉樹。

    比如一棵二叉樹的先序遍歷結(jié)果為a b c d e f g h j i 宣谈,中序遍歷的結(jié)果為c b e d a h g i j f

    我們知道先序遍歷的第一個元素必定是根節(jié)點愈犹,所以根節(jié)點是a,從中序遍歷的結(jié)果中找到a闻丑,那么a之前的所有元素都是a的左子樹漩怎,有4個元素:c b e d,先序遍歷中選擇4個元素:b c d e嗦嗡。那么b是a的左子樹的根節(jié)點......在a之后的所有元素都是a的右子樹

    使用一個 Map 存儲中序遍歷的每個元素及其對應(yīng)的下標(biāo)勋锤,目的是為了快速獲得一個元素在中序遍歷中的位置。調(diào)用遞歸方法侥祭,對于前序遍歷和中序遍歷叁执,下標(biāo)范圍都是從 0 到 n-1,其中 n 是二叉樹節(jié)點個數(shù)矮冬。

    遞歸方法的基準(zhǔn)情形有兩個:判斷前序遍歷的下標(biāo)范圍的開始和結(jié)束谈宛,若開始大于結(jié)束,則當(dāng)前的二叉樹中沒有節(jié)點胎署,返回空值 null入挣。若開始等于結(jié)束,則當(dāng)前的二叉樹中恰好有一個節(jié)點硝拧,根據(jù)節(jié)點值創(chuàng)建該節(jié)點作為根節(jié)點并返回径筏。

    若開始小于結(jié)束葛假,則當(dāng)前的二叉樹中有多個節(jié)點。在中序遍歷中得到根節(jié)點的位置滋恬,從而得到左子樹和右子樹各自的下標(biāo)范圍和節(jié)點數(shù)量聊训,知道節(jié)點數(shù)量后,在前序遍歷中即可得到左子樹和右子樹各自的下標(biāo)范圍恢氯,然后遞歸重建左子樹和右子樹带斑,并將左右子樹的根節(jié)點分別作為當(dāng)前根節(jié)點的左右子節(jié)點。

    /**
     * Definition for a binary tree node.
     * public class TreeNode {
     *     int val;
     *     TreeNode left;
     *     TreeNode right;
     *     TreeNode(int x) { val = x; }
     * }
     */
     class Solution {
         //保存中序遍歷的結(jié)果集
         HashMap<Integer, Integer> dic = new HashMap<>();
         //保存先序遍歷數(shù)組
         int[] po;
         public TreeNode buildTree(int[] preorder, int[] inorder) {
             po = preorder;
             //遍歷中序結(jié)果集放進(jìn)HashMap中方便查詢獲得根節(jié)點
             for(int i = 0; i < inorder.length; i++) 
                 dic.put(inorder[i], i);
             return recur(0, 0, inorder.length - 1);
         }
         /**
         * pre_root是先序遍歷結(jié)果集中的根節(jié)點
         * in_left是中序遍歷的左邊界
         * in_right是中序遍歷的右邊界
         */
         TreeNode recur(int pre_root, int in_left, int in_right) {
             //如果左邊界大于右邊界勋拟,停止遞歸
             if(in_left > in_right) return null;
             //生成一個根節(jié)點
             TreeNode root = new TreeNode(po[pre_root]);
             //找到這個根節(jié)點在中序遍歷集中的位置
             int i = dic.get(po[pre_root]);
             //左子樹
             root.left = recur(pre_root + 1, in_left, i - 1);
             //右子樹勋磕,根節(jié)點索引+左子樹長度+1
             root.right = recur(pre_root + i - in_left + 1, i + 1, in_right);
             return root;
         }
     }
    
  2. 最長不含重復(fù)字符的子字符串

    請從字符串中找出一個最長的不包含重復(fù)字符的子字符串,計算該最長子字符串的長度敢靡。

    示例 1:

    輸入: "abcabcbb"
    輸出: 3
    解釋: 因為無重復(fù)字符的最長子串是 "abc"挂滓,所以其長度為 3。
    示例 2:

    輸入: "bbbbb"
    輸出: 1
    解釋: 因為無重復(fù)字符的最長子串是 "b"啸胧,所以其長度為 1赶站。
    示例 3:

    輸入: "pwwkew"
    輸出: 3
    解釋: 因為無重復(fù)字符的最長子串是 "wke",所以其長度為 3纺念。
    請注意贝椿,你的答案必須是 子串 的長度,"pwke" 是一個子序列陷谱,不是子串烙博。

public static int lengthOfLongestSubstring(String s){
        //這里 是不包含start的
        //ans是最大子串的長度,初始為0烟逊,start是最大子串的開始的下標(biāo)的前一位渣窜,初始為-1
        int ans = 0, start = -1;
        //使用Map存儲字符及對應(yīng)的下標(biāo)
        Map<Character, Integer> map = new HashMap<>();
        //遍歷這個字符串
        for(int i = 0; i < s.length() ; i++){
             char k = s.charAt(i);
            if(map.containsKey(k)){
                // 如果遇到重復(fù)字符,就要更新了焙格!
                int index = map.get(k);
                //index是當(dāng)前重復(fù)字符對應(yīng)的下標(biāo),如果大于start
                if(index > start) {
                    start = index;
                }
            }
            map.put(k, i);
            //比較
            ans = Math.max(ans, i - start);
        }
        return ans;
    }
  1. 兩數(shù)之和

    給定一個整數(shù)數(shù)組 nums 和一個目標(biāo)值 target夷都,請你在該數(shù)組中找出和為目標(biāo)值的那 兩個 整數(shù)眷唉,并返回他們的數(shù)組下標(biāo)。

    你可以假設(shè)每種輸入只會對應(yīng)一個答案囤官。但是冬阳,數(shù)組中同一個元素不能使用兩遍。

    示例:

    給定 nums = [2, 7, 11, 15], target = 9

    因為 nums[0] + nums[1] = 2 + 7 = 9
    所以返回 [0, 1]

    解法一:暴力破解法

    class Solution {
        public int[] twoSum(int[] nums, int target) {
            for (int i = 0; i < nums.length; i++) {
                for (int j = i + 1; j < nums.length; j++) {
                    if (nums[j] == target - nums[i]) {
                        return new int[] { i, j };
                    }
                }
            }
            throw new IllegalArgumentException("No two sum solution");
        }
    }
    

    暴力破解法的時間復(fù)雜度是O(n^2)党饮,空間復(fù)雜度是O(1).

    解法二:哈希表的一次遍歷

    class Solution{
        public int[] twoSum(int[] nums, int target){
            Map<Integer,Integer> map = new HashMap<>();
            for(int i = 0;i<nums.length;i++){
                if(map.containsKey(target-nums[i])){
                    return new int[]{map.get(target-nums[i]),i};
                }
                map.put(nums[i],i);
            }
            throw new IllegalArgumentException("No two sum solution");
        }
    }
    

    這種方法的時間復(fù)雜度是O(n)肝陪,空間復(fù)雜度也是O(n)。

  2. 兩數(shù)相加

    給出兩個 非空 的鏈表用來表示兩個非負(fù)的整數(shù)刑顺。其中氯窍,它們各自的位數(shù)是按照 逆序 的方式存儲的饲常,并且它們的每個節(jié)點只能存儲 一位 數(shù)字。

    如果狼讨,我們將這兩個數(shù)相加起來贝淤,則會返回一個新的鏈表來表示它們的和。

    您可以假設(shè)除了數(shù)字 0 之外政供,這兩個數(shù)都不會以 0 開頭播聪。

    示例:

    輸入:(2 -> 4 -> 3) + (5 -> 6 -> 4)
    輸出:7 -> 0 -> 8
    原因:342 + 465 = 807

    分析:最開始想的是分別將這兩個鏈表轉(zhuǎn)換為int型的整數(shù),然后兩數(shù)相加得到一個int整數(shù)布隔,最后將這個整數(shù)轉(zhuǎn)成鏈表离陶。可惜這個想法太天真了衅檀,不僅時間復(fù)雜度很高招刨,而且還會出現(xiàn)int溢出的問題。最后看了答案:

    public static ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        ListNode dummyHead = new ListNode(0);
        ListNode p = l1,q = l2,curr = dummyHead;
        int carry = 0;
        while (p != null || q!= null){
            int x = (p != null) ? p.val : 0;
            int y = (q != null) ? q.val : 0;
            int sum = x + y + carry;
            carry = sum / 10;
            curr.next = new ListNode(sum%10);
            curr = curr.next;
            if(p != null){
                p = p.next;
            }
            if( q != null){
                q = q.next;
            }
        }
        if (carry > 0) {
            curr.next = new ListNode(carry);
        }
        return dummyHead.next;
    }
    

    使用了一個dummyHead作為頭節(jié)點之前的節(jié)點术吝。0-9之內(nèi)的數(shù)字相加有可能出現(xiàn)溢出的問題使用carry保存溢出的十位上的數(shù)字计济。最后還有可能出現(xiàn)進(jìn)位的問題,所以要對carry進(jìn)行判斷排苍。

  3. 尋找兩個正序數(shù)組的中位數(shù)(https://leetcode-cn.com/problems/median-of-two-sorted-arrays/solution/xun-zhao-liang-ge-you-xu-shu-zu-de-zhong-wei-s-114/)

    給定兩個大小為 m 和 n 的正序(從小到大)數(shù)組 nums1 和 nums2沦寂。

    請你找出這兩個正序數(shù)組的中位數(shù),并且要求算法的時間復(fù)雜度為 O(log(m + n))淘衙。

    你可以假設(shè) nums1 和 nums2 不會同時為空传藏。

    示例 1:

    nums1 = [1, 3]
    nums2 = [2]

    則中位數(shù)是 2.0

    示例 2:

    nums1 = [1, 2]
    nums2 = [3, 4]

    則中位數(shù)是 (2 + 3)/2 = 2.5

    分析:剛開始的時候我的思路是將這兩個數(shù)組合并為一個大數(shù)組,然后根據(jù)合并后數(shù)組的長度計算中位數(shù)彤守。但是這種算法的時間復(fù)雜度為O(m+n)毯侦,不能滿足題目的要求。無奈只能看參考答案:

    public static double findMedianSortedArrays(int[] nums1, int[] nums2) {
        int leftLength = nums1.length;
        int rightLength = nums2.length;
        // 為了保證第一個數(shù)組比第二個數(shù)組小(或者相等)
        if (leftLength > rightLength) {
            return findMedianSortedArrays(nums2, nums1);
        }
        // 分割線左邊的所有元素需要滿足的個數(shù) m + (n - m + 1) / 2;
        // 兩個數(shù)組長度之和為偶數(shù)時具垫,當(dāng)在長度之和上+1時侈离,由于整除是向下取整,所以不會改變結(jié)果
        // 兩個數(shù)組長度之和為奇數(shù)時筝蚕,按照分割線的左邊比右邊多一個元素的要求卦碾,此時在長度之和上+1,就會被2整除起宽,會在原來的數(shù)
        //的基礎(chǔ)上+1洲胖,于是多出來的那個1就是左邊比右邊多出來的一個元素
        int totalLeft = (leftLength + rightLength + 1) / 2;
        // 在 nums1 的區(qū)間 [0, leftLength] 里查找恰當(dāng)?shù)姆指罹€,
        // 使得 nums1[i - 1] <= nums2[j] && nums2[j - 1] <= nums1[i]
        int left = 0;
        int right = leftLength;
        // nums1[i - 1] <= nums2[j]
        //  此處要求第一個數(shù)組中分割線的左邊的值 不大于(小于等于) 第二個數(shù)組中分割線的右邊的值
        // nums2[j - 1] <= nums1[i]
        //  此處要求第二個數(shù)組中分割線的左邊的值 不大于(小于等于) 第一個數(shù)組中分割線的右邊的值
        // 循環(huán)條件結(jié)束的條件為指針重合坯沪,即分割線已找到
        while (left < right) {
            // 二分查找绿映,此處為取第一個數(shù)組中左右指針下標(biāo)的中位數(shù),決定起始位置
            // 此處+1首先是為了不出現(xiàn)死循環(huán),即left永遠(yuǎn)小于right的情況
            // left和right最小差距是1叉弦,此時下面的計算結(jié)果如果不加1會出現(xiàn)i一直=left的情況丐一,而+1之后i才會=right
            // 于是在left=i的時候可以破壞循環(huán)條件,其次下標(biāo)+1還會保證下標(biāo)不會越界卸奉,因為+1之后向上取整钝诚,保證了
            // i不會取到0值,即i-1不會小于0
            // 此時i也代表著在一個數(shù)組中左邊的元素的個數(shù)
            int i = left + (right - left + 1) / 2;
            // 第一個數(shù)組中左邊的元素個數(shù)確定后榄棵,用左邊元素的總和-第一個數(shù)組中元素的總和=第二個元素中左邊的元素的總和
            // 此時j就是第二個元素中左邊的元素的個數(shù)
            int j = totalLeft - i;
            // 此處用了nums1[i - 1] <= nums2[j]的取反凝颇,當(dāng)?shù)谝粋€數(shù)組中分割線的左邊的值大于第二個數(shù)組中分割線的右邊的值
            // 說明又指針應(yīng)該左移,即-1
            if (nums1[i - 1] > nums2[j]) {
                // 下一輪搜索的區(qū)間 [left, i - 1]
                right = i - 1;
                // 此時說明條件滿足疹鳄,應(yīng)當(dāng)將左指針右移到i的位置拧略,至于為什么是右移,請看i的定義
            } else {
                // 下一輪搜索的區(qū)間 [i, right]
                left = i;
            }
        }
        // 退出循環(huán)時left一定等于right瘪弓,所以此時等于left和right都可以
        // 為什么left一定不會大于right?因為left=i垫蛆。
        // 此時i代表分割線在第一個數(shù)組中所在的位置
        // nums1[i]為第一個數(shù)組中分割線右邊的第一個值
        // nums[i-1]即第一個數(shù)組中分割線左邊的第一個值
        int i = left;
        // 此時j代表分割線在第二個數(shù)組中的位置
        // nums2[j]為第一個數(shù)組中分割線右邊的第一個值
        // nums2[j-1]即第一個數(shù)組中分割線左邊的第一個值
        int j = totalLeft - i;
        // 當(dāng)i=0時,說明第一個數(shù)組分割線左邊沒有值腺怯,為了不影響
        // nums1[i - 1] <= nums2[j] 和 Math.max(nums1LeftMax, nums2LeftMax)
        // 的判斷袱饭,所以將它設(shè)置為int的最小值
        int nums1LeftMax = i == 0 ? Integer.MIN_VALUE : nums1[i - 1];
        // 等i=第一個數(shù)組的長度時,說明第一個數(shù)組分割線右邊沒有值呛占,為了不影響
        // nums2[j - 1] <= nums1[i] 和 Math.min(nums1RightMin, nums2RightMin)
        // 的判斷虑乖,所以將它設(shè)置為int的最大值
        int nums1RightMin = i == leftLength ? Integer.MAX_VALUE : nums1[i];
        // 當(dāng)j=0時,說明第二個數(shù)組分割線左邊沒有值晾虑,為了不影響
        // nums2[j - 1] <= nums1[i] 和 Math.max(nums1LeftMax, nums2LeftMax)
        // 的判斷疹味,所以將它設(shè)置為int的最小值
        int nums2LeftMax = j == 0 ? Integer.MIN_VALUE : nums2[j - 1];
        // 等j=第二個數(shù)組的長度時,說明第二個數(shù)組分割線右邊沒有值帜篇,為了不影響
        // nums1[i - 1] <= nums2[j] 和 Math.min(nums1RightMin, nums2RightMin)
        // 的判斷糙捺,所以將它設(shè)置為int的最大值
        int nums2RightMin = j == rightLength ? Integer.MAX_VALUE : nums2[j];
        // 如果兩個數(shù)組的長度之和為奇數(shù),直接返回兩個數(shù)組在分割線左邊的最大值即可
        if (((leftLength + rightLength) % 2) == 1) {
            return Math.max(nums1LeftMax, nums2LeftMax);
        } else {
            // 如果兩個數(shù)組的長度之和為偶數(shù)笙隙,返回的是兩個數(shù)組在左邊的最大值和兩個數(shù)組在右邊的最小值的和的二分之一
            // 此處不能被向下取整洪灯,所以要強制轉(zhuǎn)換為double類型
            return (double) ((Math.max(nums1LeftMax, nums2LeftMax) + Math.min(nums1RightMin, nums2RightMin))) / 2;
        }
    }
    

    這種方式基于一種分割線的思路來尋找中位數(shù)。第一個數(shù)組有一個分割線竟痰,第二個數(shù)組也有一個分割線签钩,分割線左側(cè)的所有元素要小于分割線右側(cè)的所有元素,也就意味著第一個數(shù)組的分割線左側(cè)的最后一個元素要小于第二個數(shù)組分割線右側(cè)的第一個元素凯亮,同理边臼,第二個數(shù)組的分割線左側(cè)的最后一個元素要小于第一個數(shù)組分割線右側(cè)的第一個元素哄尔。同時假消,上下兩個數(shù)組分割線左側(cè)的元素的數(shù)量是(上面數(shù)組的元素個數(shù)+下面數(shù)組的元素的個數(shù)+1)/2。當(dāng)總元素的個數(shù)是偶數(shù)的時候岭接,左側(cè)的元素的數(shù)量是總元素數(shù)量的一半富拗,當(dāng)是奇數(shù)的時候臼予,左側(cè)元素的數(shù)量是總元素的數(shù)量的一半再加一。這種思路相當(dāng)于只要找到上下兩個數(shù)組的分割線兩側(cè)的四個元素就可以計算出中位數(shù)了啃沪。

    需要注意的是有四種特殊情況:上面的數(shù)組分割線左邊沒有元素粘拾、右邊沒有元素,下面的數(shù)組分割線左邊沒有元素创千,右邊沒有元素缰雇。

  4. 最長回文子串

    給定一個字符串 s,找到 s 中最長的回文子串追驴。你可以假設(shè) s 的最大長度為 1000械哟。

    示例 1:

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

    示例 2:

    輸入: "cbbd"
    輸出: "bb"
    

? 解法一:中心擴展算法

? 對每一個字符殿雪,向兩邊擴展暇咆,可以分為兩種情況:奇數(shù)與偶數(shù),分別計算這兩種情況下最長回文子串的值并進(jìn)行比較丙曙。

/**
     * 中心擴散法尋找最長子串
     * @param s
     * @return
     */
    public String longestPalindrome(String s) {
        if (s == null || s.length() < 1){
            return "";
        }

        // 初始化最大回文子串的起點和終點
        int start = 0;
        int end   = 0;

        // 遍歷每個位置爸业,當(dāng)做中心位
        for (int i = 0; i < s.length(); i++) {
            // 分別拿到奇數(shù)偶數(shù)的回文子串長度
            int lenOdd = expandCenter(s,i,i);
            int lenEven = expandCenter(s,i,i + 1);
            // 對比最大的長度
            int len = Math.max(lenOdd,lenEven);
            // 計算對應(yīng)最大回文子串的起點和終點
            //與len>=end-start+1同樣的效果
            if (len > end - start){
                //len-1兼顧了偶數(shù)的情況
                start = i - (len - 1)/2;
                end = i + len/2;
            }
        }
        // 注意:這里的end+1是因為 java自帶的左閉右開的原因
        return s.substring(start,end + 1);
    }


    /**
     *
     * @param s             輸入的字符串
     * @param left          起始的左邊界
     * @param right         起始的右邊界
     * @return              回文串的長度
     */
    private int expandCenter(String s,int left,int right){
        // left = right 的時候,此時回文中心是一個字符亏镰,回文串的長度是奇數(shù)
        // right = left + 1 的時候扯旷,此時回文中心是一個空隙,回文串的長度是偶數(shù)
        // 跳出循環(huán)的時候恰好滿足 s.charAt(left) 拆挥!= s.charAt(right)
        while (left >= 0 && right < s.length() && s.charAt(left) == s.charAt(right)){
            left--;
            right++;
        }
        // 回文串的長度是right-left+1-2 = right - left - 1
        return right - left - 1;
    }

? 解法二:動態(tài)規(guī)劃

使用一個二維數(shù)組表示各個階段的狀態(tài)薄霜,這個二維數(shù)組的行是子串的起始位置,列是子串的結(jié)束位置纸兔。由于j>=i惰瓜,所以只需要考慮二維數(shù)組的主對角線的上半部分,對角線上的值永遠(yuǎn)是true汉矿。用true表示這個子串是回文串崎坊,false不是回文串。那么對于某個固定位置的數(shù)組元素來說洲拇,它的值依賴于左下角的元素的值奈揍。進(jìn)行填充的時候只能一列一列地進(jìn)行填充,同一列的元素從上到下依次填充赋续。

給定一個字符串s="abcba"

0 1 2 3 4
0 true false false false true
1 true false true false
2 true false false
3 true false
4 true
class Solution {
    public String longestPalindrome(String s) {
        int len = s.length();
        // 特判
        if (len < 2){
            return s;
        }
        //最大長度初始是1
        int maxLen = 1;
        int begin  = 0;

        // 1. 狀態(tài)定義
        // dp[i][j] 表示s[i...j] 是否是回文串


        // 2. 初始化
        boolean[][] dp = new boolean[len][len];
        for (int i = 0; i < len; i++) {
            dp[i][i] = true;
        }

        char[] chars = s.toCharArray();
        // 3. 狀態(tài)轉(zhuǎn)移
        // 注意:先填左下角
        // 填表規(guī)則:先一列一列的填寫男翰,再一行一行的填,保證左下方的單元格先進(jìn)行計算
        for (int j = 1;j < len;j++){
            for (int i = 0; i < j; i++) {
                // 頭尾字符不相等纽乱,不是回文串
                if (chars[i] != chars[j]){
                    dp[i][j] = false;
                }else {
                    // 相等的情況下
                    // 考慮頭尾去掉以后沒有字符剩余蛾绎,或者剩下一個字符的時候,肯定是回文串
                    if (j - i < 3){
                        dp[i][j] = true;
                    }
                    //否則,判斷其左下角的元素的狀態(tài)
                    else {
                        // 狀態(tài)轉(zhuǎn)移
                        dp[i][j] = dp[i + 1][j - 1];
                    }
                }

                // 只要dp[i][j] == true 成立租冠,表示s[i...j] 是否是回文串
                // 此時更新記錄回文長度和起始位置
                if (dp[i][j] && j - i + 1 > maxLen){
                    maxLen = j - i + 1;
                    begin = i;
                }
            }
        }
        // 4. 返回值
        return s.substring(begin,begin + maxLen);
    }
}
  1. Z字形變換

    將一個給定字符串根據(jù)給定的行數(shù)鹏倘,以從上往下、從左到右進(jìn)行 Z 字形排列顽爹。

    比如輸入字符串為 "LEETCODEISHIRING" 行數(shù)為 3 時纤泵,排列如下:

    L   C   I   R
    E T O E S I I G
    E   D   H   N
    

    之后,你的輸出需要從左往右逐行讀取镜粤,產(chǎn)生出一個新的字符串捏题,比如:"LCIRETOESIIGEDHN"。

    請你實現(xiàn)這個將字符串進(jìn)行指定行數(shù)變換的函數(shù):

    string convert(string s, int numRows);

    分析:最后需要按行讀取肉渴,所以可以考慮每一行使用一個字符串進(jìn)行保存涉馅。最后將字符串進(jìn)行拼接。最開始的想法是用一個變量記錄當(dāng)前所在的行黄虱,但是有一個問題稚矿,行數(shù)加一還是減一怎么判斷,苦思冥想不了了之捻浦,看了官方題解才恍然大悟晤揣,使用一個標(biāo)志位進(jìn)行標(biāo)記。根據(jù)這個標(biāo)志位的狀態(tài)進(jìn)行加一或是減一的操作朱灿。

    public static String convert(String s, int numRows){
        //如果行數(shù)為1或者字符串的長度小于等于行數(shù)昧识,就返回字符串本身,不需要轉(zhuǎn)換
        if(numRows == 1 || s.length()<=numRows){
            return s;
        }
        //同一行的字符保存在一個StringBuilder中盗扒,需要一個list來存放這些StringBuilder
        List<StringBuilder> list = new ArrayList<>();
        char[] chars = s.toCharArray();
    
        for (int i = 0; i < numRows; i++) {
            list.add(new StringBuilder());
        }
        //狀態(tài)位跪楞,根據(jù)這個變量判斷行數(shù)加一還是減一
        boolean goingDown = false;
        //初始當(dāng)前行為1
        int curRow = 1;
        //遍歷每個字符,追加到對應(yīng)的StringBuilder后面
        for (char aChar : chars) {
            //因為list的下標(biāo)從0開始侣灶,所以curRow需要減一
            list.get(curRow-1).append(aChar);
            //如果是第一行或者最后一行就需要對goingDown進(jìn)行取反操作
            if (curRow == 1 || curRow == numRows) {
                goingDown = !goingDown;
            }
            //根據(jù)goingDown的值進(jìn)行加一或者減一的操作
            curRow += goingDown ? 1 : -1;
        }
        StringBuilder sb = new StringBuilder();
        //合并list中的stringBuilder
        for (StringBuilder builder : list) {
            sb.append(builder);
        }
        return sb.toString();
    
    }
    
    1. 正則表達(dá)式匹配(難度:困難)

    給你一個字符串 s 和一個字符規(guī)律 p甸祭,請你來實現(xiàn)一個支持 '.' 和 '*' 的正則表達(dá)式匹配。

    '.' 匹配任意單個字符
    '*' 匹配零個或多個前面的那一個元素
    所謂匹配褥影,是要涵蓋 整個 字符串 s的池户,而不是部分字符串。

    說明:

    s 可能為空凡怎,且只包含從 a-z 的小寫字母校焦。
    p 可能為空寨典,且只包含從 a-z 的小寫字母,以及字符 . 和 *耸成。
    示例 1:

    輸入:
    s = "aa"
    p = "a"
    輸出: false
    解釋: "a" 無法匹配 "aa" 整個字符串注暗。

    示例 2:

    輸入:
    s = "aa"
    p = "a"
    輸出: true
    解釋: 因為 '
    ' 代表可以匹配零個或多個前面的那一個元素, 在這里前面的元素就是 'a'。因此墓猎,字符串 "aa" 可被視為 'a' 重復(fù)了一次。

    示例 3:

    輸入:
    s = "ab"
    p = "."
    輸出: true
    解釋: ".
    " 表示可匹配零個或多個('*')任意字符('.')赚楚。
    示例 4:

    輸入:
    s = "aab"
    p = "cab"
    輸出: true
    解釋: 因為 '*' 表示零個或多個毙沾,這里 'c' 為 0 個, 'a' 被重復(fù)一次。因此可以匹配字符串 "aab"宠页。
    示例 5:

    輸入:
    s = "mississippi"
    p = "misisp*."
    輸出: false

    
    
    
class Solution {
    public boolean isMatch(String s, String p) {
        int m = s.length();
        int n = p.length();    
        boolean[][] f = new boolean[m + 1][n + 1];
        f[0][0] = true;
        for (int i = 0; i <= m; ++i) {
            for (int j = 1; j <= n; ++j) {
                if (p.charAt(j - 1) == '*') {
                    f[i][j] = f[i][j - 2];
                    if (matches(s, p, i, j - 1)) {
                        f[i][j] = f[i][j] || f[i - 1][j];
                    }
                }
                else {
                    if (matches(s, p, i, j)) {
                        f[i][j] = f[i - 1][j - 1];
                    }
                }
            }
        }
        return f[m][n];
    }

    public boolean matches(String s, String p, int i, int j) {
        if (i == 0) {
            return false;
        }
        //.可以匹配任意字符左胞,所以返回true
        if (p.charAt(j - 1) == '.') {
            return true;
        }
        //i-1與j-1是否匹配
        return s.charAt(i - 1) == p.charAt(j - 1);
    }
  }
  1. 盛最多水的容器

    給你 n 個非負(fù)整數(shù) a1,a2举户,...烤宙,an,每個數(shù)代表坐標(biāo)中的一個點 (i, ai) 俭嘁。在坐標(biāo)內(nèi)畫 n 條垂直線躺枕,垂直線 i 的兩個端點分別為 (i, ai) 和 (i, 0)。找出其中的兩條線供填,使得它們與 x 軸共同構(gòu)成的容器可以容納最多的水拐云。

    說明:你不能傾斜容器,且 n 的值至少為 2近她。

    圖中垂直線代表輸入數(shù)組 [1,8,6,2,5,4,8,3,7]叉瘩。在此情況下,容器能夠容納水(表示為藍(lán)色部分)的最大值為 49粘捎。

示例:

輸入:[1,8,6,2,5,4,8,3,7]
輸出:49

> 分析:
>
> 這道一乍一看不就是一個雙重for循環(huán)嗎薇缅,很簡單的一道題,為什么還是中等難度攒磨。結(jié)果一提交運行速度只擊敗了14.7%的用戶泳桦。尋思這還有其他更快速的算法,苦思冥想有一個雙指針的方法娩缰,一個指針指向頭蓬痒,一個指針指向尾,循環(huán)的終止條件是指針重合漆羔。但是在判斷應(yīng)該移動哪個指針的問題上不知道怎么辦梧奢。果斷看了答案,原來只需要移動元素值較小的那個指針就行了演痒。原因就是如果說你移動元素值較大的那個指針亲轨,無論下一個元素的值大還是小鸟顺。面積一定小于之前的面積器虾。所以只能移動較小元素的那個指針兆沙,時間復(fù)雜度是O(n)葛圃。

```java
public static int maxArea(int[] height){
        int max  = 0;
        int length = height.length;
    //  雙重循環(huán)的方法
//        for (int i = 0; i < length-1; i++) {
//            for (int j = i+1; j < length; j++) {
//                int min = Math.min(height[i], height[j]);
//                int temp = min*(j-i);
//                if(temp>max){
//                    max = temp;
//                }
//            }
//        }
//        return max;
        int left = 0;
        int right = length-1;
        while (left<right){
            int min = Math.min(height[left],height[right]);
            int temp = min*(right-left);
            max = Math.max(temp, max);
            if(height[left]<=height[right]){
                left++;
            }
            else {
                right--;
            }
        }
        return max;
    }
```
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末库正,一起剝皮案震驚了整個濱河市褥符,隨后出現(xiàn)的幾起案子喷楣,更是在濱河造成了極大的恐慌抡蛙,老刑警劉巖粗截,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件熊昌,死亡現(xiàn)場離奇詭異婿屹,居然都是意外死亡昂利,警方通過查閱死者的電腦和手機蜂奸,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進(jìn)店門扩所,熙熙樓的掌柜王于貴愁眉苦臉地迎上來祖屏,“玉大人,你說我怎么就攤上這事雹食∪阂叮” “怎么了?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵化撕,是天一觀的道長植阴。 經(jīng)常有香客問我掠手,道長喷鸽,這世上最難降的妖魔是什么做祝? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任混槐,我火速辦了婚禮声登,結(jié)果婚禮上揣苏,老公的妹妹穿的比我還像新娘卸察。我一直安慰自己蛾派,他們只是感情好个少,可當(dāng)我...
    茶點故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著岂贩,像睡著了一般萎津。 火紅的嫁衣襯著肌膚如雪荤傲。 梳的紋絲不亂的頭發(fā)上颈渊,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天雾家,我揣著相機與錄音芯咧,去河邊找鬼唬党。 笑死驶拱,一個胖子當(dāng)著我的面吹牛蓝纲,可吹牛的內(nèi)容都是我干的税迷。 我是一名探鬼主播,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼毕泌,長吁一口氣:“原來是場噩夢啊……” “哼撼泛!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起损俭,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤杆兵,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后仔夺,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體琐脏,經(jīng)...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年囚灼,在試婚紗的時候發(fā)現(xiàn)自己被綠了骆膝。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片祭衩。...
    茶點故事閱讀 38,039評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡灶体,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出掐暮,到底是詐尸還是另有隱情蝎抽,我是刑警寧澤,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布灰羽,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏葛闷。R本人自食惡果不足惜蔓彩,卻給世界環(huán)境...
    茶點故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一等孵、第九天 我趴在偏房一處隱蔽的房頂上張望咐熙。 院中可真熱鬧锈玉,春花似錦椅棺、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工格带, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人嗽桩。 一個月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓拒逮,卻偏偏與公主長得像塔嬉,于是被迫代替她去往敵國和親佣赖。 傳聞我的和親對象是個殘疾皇子憎蛤,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,786評論 2 345