1. 程式人生 > >找出字串中的最長連續數字子串

找出字串中的最長連續數字子串

題目

給出一個字串作為輸入,找出其中最長的連續數字串並返回其長度和起始index。如果存在長度相同的連續數字串,返回最後一個連續數字串。如果沒有,返回0和0。

Analysis

對於這道題目,首先我們需要進一步縮小題目範圍。題目中並沒有給出字串中的數字都是什麼數字。比如是否包含負數,是否包含小數等。因此簡單起見,我們假設該輸入字串中只包含正整數。且假設輸入字串中沒有空格。

設輸入字串的長度為n

從Best Conceivable Time的角度考慮,這道題的時間複雜度至少為O(n)。也就是說,對於這道題而言,我們至少需要遍歷整個輸入的字串一次才能得出答案。因此在時間複雜度角度考慮,我們並沒有多少優化的空間。

從空間複雜度的角度考慮,brute-force解法比較直觀,就是遍歷一遍整個輸入字串,找出並記錄其中所有的連續數字子串。然後在所有被記錄的數字子串中找出最長的那個。因為題目要求有多個最長子串時返回最後一個,所以我們只需要返回最後一個被記錄的最長子串即可。這個方法最壞情況下需要記錄整個輸入字串。所以空間複雜度為O(n)

具體實現如下:

public class LongestNumberSubstring {
    public static int[] findLongestNumSubstring(String input) {
        // If the string is empty, return
[0, 0] directly. if (input == null || input.length() == 0) { return new int[]{0, 0}; } int index = 0; int[] ret = new int[]{0, 0}; //[start_index, length] while (index < input.length()) { StringBuilder sb = new StringBuilder(); while
(index < input.length() && Character.isDigit(input.charAt(index))) { sb.append(input.charAt(index)); index++; } // If current substring is not empty and is longer than or equal to the previously found substring // Put it in return values. if (sb.length() != 0 && ret[1] <= sb.length()) { ret[1] = sb.length(); ret[0] = index - sb.length(); } index++; } return ret; }

優化

但事實上,考慮到我們需要的只是子字串的起始index和長度,這道題可以用2 pointers的方法解決。並不需要記錄中間產生的任何子字串。這樣的話我們可以將演算法的空間複雜度降到O(1)

具體演算法為:從頭到尾遍歷字串,每當遇到數字連續數字子串時,記錄其長度。並與全域性記錄的最長長度相比較。如果更長的話,就記錄當前長度和開始index。

實現如下:

public class LongestNumberSubstring {
    public static int[] findLongestNumSubstring(String input) {
        // If the string is empty, return [0, 0] directly.
        if (input == null || input.length() == 0) {
            return new int[]{0, 0};
        }

        int index = 0;
        int[] ret = new int[]{0, 0}; //[start_index, length]
        int currLen = 0;
        while (index < input.length()) {
            currLen = 0;
            while (index < input.length() && Character.isDigit(input.charAt(index))) {
                currLen++;
                index++;
            }

            // If current substring is longer than or equal to the previously found substring
            // Put it in return values.
            if (currLen != 0 && ret[1] <= currLen) {
                ret[1] = currLen;
                ret[0] = index - currLen;
            }
            index++;
        }

        return ret;
    }
}