有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java给定2个字符串,只删除一个数字,使1个字符串按字典顺序变小

我试图解决Java中字符串操作的编码问题。问题是

Given two strings S and T consisting of digits and lowercase letters, you are allowed to remove only one digit from either string, count how many ways of removal to make S lexicographically smaller than T.

我自己提出了这个测试用例。如果s='3ab'和t='cd',则返回1。如果s='123ab'和t='423cd',则返回6

我的想法是使用2作为循环,通过检查字符是否为数字来遍历每个字符串,将其删除并与另一个字符串进行比较

private static int numSmaller(String s, String t){
    int ways = 0;

    for(int i = 0; i < s.length(); i++){
        StringBuilder sbs = new StringBuilder(s);
        if(Character.isDigit(s.charAt(i))){
            sbs.deleteCharAt(i);
            String sub = sbs.toString();
            if(sub.compareTo(t) < 0) {
                ways++;
            }
        }
    }

    for(int i = 0; i < t.length(); i++){
        StringBuilder sbt = new StringBuilder(t);
        if(Character.isDigit(t.charAt(i))){
            sbt.deleteCharAt(i);
            String sub = sbt.toString();
            if(s.compareTo(sub) < 0){
                ways++;
            }
        }
    }
    return ways;
}

正如您所看到的,空间复杂度非常糟糕,而且代码似乎也是冗余的。有没有办法优化这段代码?有没有人发现了一种方法,可以避免每次使用字符串生成器或创建新字符串?欢迎您的任何意见


共 (5) 个答案

  1. # 1 楼答案

    我使用了streams并将其与您使用长度为10的随机字符串的方法进行了比较。我运行了这些字符串的1 million测试用例,这两种方法提供了相同的结果

    流部分相当简单。我使用IntStream索引到字符串中,根据数字位置构建substrings。然后,我根据传递的BiFunctionlambda进行过滤,该lambda充当双参数谓词。在此基础上,我计算成功的次数

    我做了两次,反转参数和谓词逻辑,并总结这两个计数

    long count = count(s1, t1, (a, b) -> a.compareTo(b) < 0);
    count += count(t1, s1, (a, b) -> b.compareTo(a) < 0);   
    
    public static long count(String s, String t, BiFunction<String, String, Boolean> comp) {
    
          return IntStream.range(0, s.length()).filter(
            i -> Character.isDigit(s.charAt(i))).mapToObj(
                  i -> s.substring(0, i) + s.substring(i + 1)).filter(
                        ss -> comp.apply(ss, t)).count();
    }
    
  2. # 2 楼答案

    仅依赖于检查第一个字符的O(n+m)解决方案对此输入失败

    s = "ab12c"
    t = "ab24z"
    

    只检查第一个字符仍然是一个很大的改进,但是必须处理边缘情况

  3. # 3 楼答案

    以下是具有O(n+m)时间复杂性的工作解决方案。只有第一个字符是重要的,我们可以根据它的数量来决定如何处理它

    public static int numSmaller(String s, String t) {
        return numSmaller(s,t,1);
    }
    public static int numSmaller(String s, String t,int n) {
        if(n==0){
            if(s.compareTo(t) < 0){
                return 1;
            }else{
                return 0;
            }
        }
        int output = 0;
        if(n==1){
            char sc = s.charAt(0);
            char tc = t.charAt(0);
            int sCount = digitCount(s);
            int tCount = digitCount(t);
            if(sc < tc){
                if(Character.isDigit(sc)){// s = '123ab' and t = 'c23cd',
                    output += ((sCount-1)+tCount);//we need to delete exactly one character
                    output+=numSmaller(s.substring(1),t,0);
                }else{
                    output += (sCount)+tCount;
                }
    
            }else{
                if(!Character.isDigit(sc) && !Character.isDigit(tc) ){
                    return 0;
                }
                if(Character.isDigit(sc)){
                    output +=numSmaller(s.substring(1),t,0);
                }
                if(Character.isDigit(tc)){
                    output +=numSmaller(s,t.substring(1),0);
                }
            }
        }
        return output;
    
    }
     private static int digitCount(String s){
        int count = 0;
        for(int i=0;i<s.length();i++){
            char c = s.charAt(i);
            if(Character.isDigit(c)){
                count++;
            }
        }
        return count;
    }
     /**
        String s="a123ab";
        String t ="b423cd";
        System.out.println( numSmaller(s,t));
        
         * a23ab,b423cd
         * a13ab,b423cd
         * a12ab,b423cd
         * a123ab,b23cd
         * a123ab,b43cd
         * a123ab,b42cd
         *
         */
    
  4. # 4 楼答案

    System.out.println(getcnt(s1, t1) + getcnt(t1, s1));
    
        public static int getcnt(String a, String b) {
        int ways = 0;
        for (int i = 0; i < a.length(); i++) {
    
            if (Character.isDigit(a.charAt(i))) {
    
                String s = a.substring(0, i) + a.substring(i + 1);
    
                if (s.compareTo(b) < 0 || b.compareTo(s) < 0)
                    ways++;
    
            }
        }
        return ways;
    }
    
  5. # 5 楼答案

    您可以将时间复杂度降低到O(m+n),其中m,n是S,T的长度 我写了C++代码,并测试了它的工作原理。p>

    其目的是比较S和T的第一个字符:

    First count how many digits S and T have, then compare their first characters
    
    if(S[0] < T[0])
        can remove any digits behind except for the first characters of S and T
        then check if you can remove S[0] or T[0] to make S<T
    else
        check if you can remove S[0] or  T[0] to make S<T if can not, return 0;