【精選】JAVA算法題(二十四)

一、子字符串出現的位置

題目:

/**
 * 給出 字符串 text 和 字符串列表 words, 返回所有的索引對 [i, j] 使得在索引對範圍內的子字符串
 * text[i]...text[j](包括 i 和 j)屬於字符串列表 words。
 *
 * 示例 1:
 * 輸入: text = "thestoryofleetcodeandme", words = ["story","fleet","leetcode"]
 * 輸出: [[3,7],[9,13],[10,17]]
 *
 * 示例 2:
 * 輸入: text = "ababa", words = ["aba","ab"]
 * 輸出: [[0,1],[0,2],[2,3],[2,4]]
 * 解釋:
 * 注意,返回的配對可以有交叉,比如,"aba" 既在 [0,2] 中也在 [2,4] 中
 *
 * 提示:
 *     所有字符串都只包含小寫字母。
 *     保證 words 中的字符串無重複。
 *     1 <= text.length <= 100
 *     1 <= words.length <= 20
 *     1 <= words[i].length <= 50
 *     按序返回索引對 [i,j](即,按照索引對的第一個索引進行排序,當第一個索引對相同時按照第二個索引對排序)。
 */

說到匹配,很容易就可以聯想到正則表達式,所以我就上手寫了段代碼

    public static int[][] method1(String text, String[] words) {
        List<List<Integer>> resultList =new ArrayList<>();
        List<Integer> integers=new ArrayList<>();
        for (String s:words){
            Matcher matcher = Pattern.compile(s).matcher(text);
            int needAdd=s.length()-1;
            while (matcher.find()){
                int start=matcher.start();
                integers=new ArrayList<>();
                integers.add(start);
                integers.add(start+needAdd);
                resultList.add(integers);
            }
        }
        int[][] result=new int[resultList.size()][2];
        int length=result.length;
        for (int i=0;i<length;i++){
            result[i]=new int[]{resultList.get(i).get(0),resultList.get(i).get(1)};
        }
        return result;
    }

運行結果一看,不行啊,正則表達式不會匹配已經匹配過的位置,只會往後走,但是題目要求交叉匹配啊,也不能不斷設置匹配起點吧,還不如自己寫for循環判斷呢。

我是按照一個一個子字符串去匹配字符串,得出出現位置再加上長度存到嵌套List裏面的,但這樣出來的結果都在數組裏,但是出現的順序和人家對不上,也給我判錯了,那我就再加一個sort()排個序吧,嗯?超時了?

    public static int[][] method2(String text, String[] words) {
        List<List<Integer>> resultList =new ArrayList<>();
        List<Integer> integers=new ArrayList<>();
        for (String s:words){
            int start=0;
            int length=s.length();
            while (start+length<text.length()){
                while (start+length<text.length()&&text.charAt(start)!=s.charAt(0)){
                    start++;
                    continue;
                }
                if (text.substring(start,start+length).equals(s)){
                    integers=new ArrayList<>();
                    integers.add(start);
                    integers.add(start+length-1);
                    resultList.add(integers);
                    start++;
                }
            }
        }
        resultList.sort(new Comparator<List<Integer>>() {
            @Override
            public int compare(List<Integer> o1, List<Integer> o2) {
                if (o1.get(0)==o2.get(0)){
                    if (o1.get(1)>o2.get(1)){
                        return 1;
                    }else if (o1.get(1)<o2.get(1)){
                        return -1;
                    }else {
                        return 0;
                    }
                }else if (o1.get(0)>o2.get(0)){
                    return 1;
                }else {
                    return -1;
                }
            }
        });
        int[][] result=new int[resultList.size()][2];
        int length=result.length;
        for (int i=0;i<length;i++){
            result[i]=new int[]{resultList.get(i).get(0),resultList.get(i).get(1)};
        }
        return result;
    }

哦,懂了題目的意思了,我要去遍歷字符串,對每個位置進行子字符串的匹配,匹配不成功就下一個,這樣效率更高一些,但是最後還是需要一個排序。我不知道這是不是最佳解法,這是一道比賽的題,沒有答案,只能看到提交通過沒通過。如果你有更好的解決方式歡迎和我討論。

    public static int[][] method3(String text, String[] words) {
        List<List<Integer>> resultList =new ArrayList<>();
        List<Integer> integers=new ArrayList<>();
        int start=0;
        while (start<text.length()){
            for (String s:words){
                int length=s.length();
                if (start+length>text.length()){
                    continue;
                }
                int i=0;
                for (;i<length;i++){
                    if (text.charAt(start+i)!=s.charAt(i)){
                        break;
                    }
                }
                if (i==length){
                    integers=new ArrayList<>();
                    integers.add(start);
                    integers.add(start+length-1);
                    resultList.add(integers);
                }
            }
            start++;
        }
        resultList.sort(new Comparator<List<Integer>>() {
            @Override
            public int compare(List<Integer> o1, List<Integer> o2) {
                if (o1.get(0)==o2.get(0)){
                    if (o1.get(1)>o2.get(1)){
                        return 1;
                    }else if (o1.get(1)<o2.get(1)){
                        return -1;
                    }else {
                        return 0;
                    }
                }else if (o1.get(0)>o2.get(0)){
                    return 1;
                }else {
                    return -1;
                }
            }
        });
        int[][] result=new int[resultList.size()][2];
        int length=result.length;
        for (int i=0;i<length;i++){
            result[i]=new int[]{resultList.get(i).get(0),resultList.get(i).get(1)};
        }
        return result;
    }

二、最長公共字符串

題目:

/**
 * 對於字符串 S 和 T,只有在 S = T + ... + T(T 與自身連接 1 次或多次)時,我們才認定 “T 能除盡 S”。
 * 返回字符串 X,要求滿足 X 能除盡 str1 且 X 能除盡 str2。
 *
 * 示例 1:
 * 輸入:str1 = "ABCABC", str2 = "ABC"
 * 輸出:"ABC"
 *
 * 示例 2:
 * 輸入:str1 = "ABABAB", str2 = "ABAB"
 * 輸出:"AB"
 *
 * 示例 3:
 * 輸入:str1 = "LEET", str2 = "CODE"
 * 輸出:""
 *
 * 提示:
 *     1 <= str1.length <= 1000
 *     1 <= str2.length <= 1000
 *     str1[i] 和 str2[i] 爲大寫英文字母
 */

找兩個字符串的最長公共子串,如果你去一個字符一個字符增加,這樣去挨個匹配的話肯定是不行的,因爲字符串有可能很長。你可以從子字符串構成入手,加入set,看看組成最小的子字符串需要多少個字符,這樣截取出來子字符串去匹配,如果可以匹配就加長一倍再進行匹配,如此往復,直到最後無法匹配,得出最長的公共字符串。

還要一種思路就是從字符串長度入手,因爲要求最長公共子字符串,所以長度肯定也是兩個字符串的公因子,求出兩個字符的最大公因子,首先按照最短的字符串來匹配,不斷地去減去最大公因子的長度,如果能匹配到就返回當前的長度。

匹配可以使用String.split()函數,該函數返回按照傳入分割符分割後組成的數組,如果該字符創都是由分隔符組成的,那麼返回的數組應該爲0

我用的是第二種思路,比賽的時候寫的比較急。

    public static String gcdOfStrings(String str1, String str2) {
        if (str2.length()>str1.length()){
            String temp=str1;
            str1=str2;
            str2=temp;
        }
        int step=GCD(str1.length(),str2.length());
        int end=str2.length();
        while (end>0){
            String fenge=str2.substring(0,end);
            if (str1.split(fenge).length==0&&str2.split(fenge).length==0){
                return fenge;
            }
            end-=step;
        }
        return "";
    }

    public static int GCD(int a,int b) {
        if(b==0)
            return a;
        else
            return GCD(b,a%b);
    }

三、翻轉矩陣

題目:

/**
 * 給定由若干 0 和 1 組成的矩陣 matrix,從中選出任意數量的列並翻轉其上的 每個 單元格。
 * 翻轉後,單元格的值從 0 變成 1,或者從 1 變爲 0 。
 * 返回經過一些翻轉後,行上所有值都相等的最大行數。
 *
 * 示例 1:
 * 輸入:[[0,1],[1,1]]
 * 輸出:1
 * 解釋:不進行翻轉,有 1 行所有值都相等。
 *
 * 示例 2:
 * 輸入:[[0,1],[1,0]]
 * 輸出:2
 * 解釋:翻轉第一列的值之後,這兩行都由相等的值組成。
 *
 * 示例 3:
 * 輸入:[[0,0,0],[0,0,1],[1,1,0]]
 * 輸出:2
 * 解釋:翻轉前兩列的值之後,後兩行由相等的值組成。
 *
 * 提示:
 *     1 <= matrix.length <= 300
 *     1 <= matrix[i].length <= 300
 *     所有 matrix[i].length 都相等
 *     matrix[i][j] 爲 0 或 1
 */

題目需要好好讀一讀,知道是怎麼翻轉的。因爲翻轉是按照列進行翻轉的,結果是看行數字是否都一樣,所以說翻轉一列所有行都會受到影響,就不存在複雜的行與行配合的情況,核心就在兩種情況上,一種就是原本就是全1或者全0的行,另一種就是兩行正好互補的情況,你0我1,你1我0,這樣翻轉之後纔可以變成全0或者全1。

明確了核心這題就很好解了,因爲給的矩陣順序是亂的,所以你要先對其進行排序,排序很簡單就不說了。然後先把全0和全1的行的數量統計出來,然後因爲矩陣已經排好序了,所以你就可以用頭尾指針不斷比較是否可以匹配

如果兩行加和數字中存在2,那就說明有兩個相同的位置上都是1,說明尾指針大了,尾指針前移;

如果兩行加和的數字存在0,那就說明有兩個相同的位置上都是0,說明頭指針小了,頭指針前移;

我在其中加入了startnum和endnum,是因爲有可能幾行的數字都是完全一樣的,沒必要重複判斷,減少判斷次數。

在定義List的時候我還加入了一個0,是因爲可能沒有一行可以變成全1或全0的,防止報錯。

    public static int maxEqualRowsAfterFlips(int[][] matrix) {
        sort(matrix,0,matrix.length-1);
        List<Integer> integerList=new ArrayList<>();
        integerList.add(0);
        int start=0,end=matrix.length-1,startnum=0,endnum=0;
        if (matrix[start]==matrix[end]){
            return matrix.length;
        }
        while (true){
            int i=0;
            for (;i<matrix[start].length;i++){
                if (matrix[start][i]!=0){
                    break;
                }
            }
            if (i==matrix[start].length){
                start++;
                startnum++;
            }else {
                break;
            }
        }
        integerList.add(startnum);
        while (true){
            int i=0;
            for (;i<matrix[end].length;i++){
                if (matrix[end][i]!=1){
                    break;
                }
            }
            if (i==matrix[end].length){
                end--;
                endnum++;
            }else {
                break;
            }
        }
        integerList.add(endnum);

        while (start<=end){
            startnum=1;
            endnum=1;
            while (start<end&&matrix[start]==matrix[start+1]){
                startnum++;
                start++;
            }
            while (start<end&&matrix[end]==matrix[end-1]){
                endnum++;
                end--;
            }
            int i=0;
            for (;i<matrix[start].length;i++){
                if (matrix[start][i]+matrix[end][i]!=1){
                    break;
                }
            }
            if (i==matrix[start].length){
                integerList.add(startnum+endnum);
                start++;
                end--;
            }else {
                if (matrix[start][i]+matrix[end][i]==2){
                    end--;
                }else {
                    start++;
                }
            }
        }
        integerList.sort(new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o1==o2?0:o1>o2?-1:1;
            }
        });
        return integerList.get(0);
    }

    public static void sort(int[][] array,int left,int right){
        if (left < right) {
            int i = left, j = right;
            int[] pivot = array[left];

            while (i < j) {
                while (i < j && compare(array[j],pivot)>=0) {
                    j--;
                }
                if (i < j) {
                    array[i] = array[j];
                    i++;
                }
                while (i < j && compare(array[j],pivot)==-1) {
                    i++;
                }
                if (i < j) {
                    array[j] = array[i];
                    j--;
                }
            }
            array[i] = pivot;
            sort(array, left, i - 1);
            sort(array, i + 1, right);
        }
    }

    public static int compare(int[] A,int[] B){
        int length=A.length;
        for (int i=0;i<length;i++){
            if (A[i]>B[i]){
                return 1;
            }else if (A[i]<B[i]){
                return -1;
            }
        }
        return 0;
    }

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章