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

Java 给定2个字符串,只删除一个数字,使1个字符串按字典顺序变小,java,string,lexicographic-ordering,Java,String,Lexicographic Ordering,我试图解决Java中字符串操作的编码问题。问题是 给定两个由数字和小写字母组成的字符串S和T,您只允许从任一字符串中删除一个数字,请计算有多少种删除方法可以使S在字典上小于T 我自己提出了这个测试用例。如果s='3ab'和t='cd',则返回1。如果s='123ab'和t='423cd',则返回6 我的想法是使用2作为循环,通过检查字符是否为数字来遍历每个字符串,将其删除并与另一个字符串进行比较 private static int numSaller(字符串s,字符串t){ int-ways=

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

给定两个由数字和小写字母组成的字符串S和T,您只允许从任一字符串中删除一个数字,请计算有多少种删除方法可以使S在字典上小于T

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

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

private static int numSaller(字符串s,字符串t){
int-ways=0;
对于(int i=0;i

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

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

流部分相当简单。我使用
IntStream
索引到字符串中,根据数字位置构建
子字符串。然后我根据传递的
BiFunction
lambda进行过滤,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();
}
long count=count(s1,t1,(a,b)->a.compareTo(b)<0);
计数+=计数(t1,s1,(a,b)->b。与(a)<0相比;
公共静态长计数(字符串s、字符串t、双函数comp){
返回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();
}

您可以将时间复杂度降低到O(m+n),其中m,n是S,T的长度 我写了C++代码,并测试了它的工作原理。 其目的是比较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;
首先计算S和T的位数,然后比较它们的第一个字符
如果(S[0]System.out.println(getcnt(s1,t1)+getcnt(t1,s1));
公共静态int getcnt(字符串a、字符串b){
int-ways=0;
对于(int i=0;i
以下是时间复杂度为
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
     *
     */
public static int numSaller(字符串s,字符串t){
返回numSaller(s,t,1);
}
公共静态int numSaller(字符串s、字符串t、int n){
如果(n==0){
如果(s)与(t)<0相比{
返回1;
}否则{
返回0;
}
}
int输出=0;
如果(n==1){
char sc=s.charAt(0);
字符tc=t.charAt(0);
int SCONT=数字计数;
int t计数=数字计数(t);
如果(sc对于(int i=0;我能给你一个测试用例吗?@oleg.cherednik刚刚做了!对于
s='123ab'和t='423cd'
我用不同的方法计算了
9
[123a:423cb],[123b:423cb],[12ab:423cb],[13ab:423cb],[123ab:423cb],[123ab:423cb],[123ab:42cb],[123ab:43cb],[123ab:23cb]
@oleg.cherednik,因此您只能删除数字。改进代码的一种方法是在需要之前不要创建
StringBuilder
实例。例如,如果
t
s
不包含数字,则您永远不会测试它们。但是,您可以为每个迭代创建
StringBuilder
实例e循环。看起来这个解决方案不适用于s=“a1”,t=“a2”。当字母相等时,会增加复杂性。您处理过这个问题吗?
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
     *
     */