【精选】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;
    }

 

 

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

幽蓝丶流月

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值