Algorithm 将字符串中表示的大数字除以2,加1或减1

Algorithm 将字符串中表示的大数字除以2,加1或减1,algorithm,Algorithm,我现在正在进行一项代码挑战。我的解决方案得到“时间超过”,即使我优化了它。我正在寻求有关更有效解决方案或进一步优化我的解决方案的帮助 问题描述如下: 编写一个函数,该函数将正整数作为字符串,并返回将数字转换为1所需的最小操作数。数字的长度最多为309位,因此不会有太多的字符超出您在这么多数字中所能表达的范围。 转换过程仅限于三个操作: 1.加1 2.减去1 3.将数字除以2(此处仅允许偶数) 我的想法是使用DFS遍历所有可能的解决方案,并通过记忆来加速。但它确实超过了时间限制。这个问题不能使用d

我现在正在进行一项代码挑战。我的解决方案得到“时间超过”,即使我优化了它。我正在寻求有关更有效解决方案或进一步优化我的解决方案的帮助

问题描述如下: 编写一个函数,该函数将正整数作为字符串,并返回将数字转换为1所需的最小操作数。数字的长度最多为309位,因此不会有太多的字符超出您在这么多数字中所能表达的范围。 转换过程仅限于三个操作: 1.加1 2.减去1 3.将数字除以2(此处仅允许偶数)

我的想法是使用DFS遍历所有可能的解决方案,并通过记忆来加速。但它确实超过了时间限制。这个问题不能使用dp,因为dp需要一个非常大的数组来记忆。下面是我的代码:

private static int dfs(String num, int step,Map<String,Integer> memory){
        if(num.equals("1")){
            return step;
        }
        Integer size = memory.get(num);
        if(size != null && size < step){
            return Integer.MAX_VALUE;
        }
        memory.put(num, step);
        int min = Integer.MAX_VALUE;
        int lastDigit = num.charAt(num.length() - 1) - '0';
        if(lastDigit % 2 == 0){
            min = Math.min(min, dfs(divideBy2(num), step + 1, memory));
        }else{
            min = Math.min(min, dfs(divideBy2(num), step + 2, memory));
            min = Math.min(min, dfs(divideBy2(plusOne(num)), step + 2, memory));
        }
        return min;
    }
    private static String plusOne(String num){
        StringBuilder sb = new StringBuilder();
        int carry = 1;
        for(int i = num.length() - 1; i >=0; i--){
            int d = (carry + num.charAt(i) - '0') % 10;
            carry = (carry + num.charAt(i) - '0') / 10;
            sb.insert(0, d);
        }
        if(carry == 1){
            sb.insert(0, carry);
        }
        return sb.toString();
    }
    private static String divideBy2(String num){
        StringBuilder sb = new StringBuilder();
        int x = 0;
        for(int i = 0; i < num.length(); i++){
            int d = (x * 10 + num.charAt(i) - '0') / 2 ;
            x = (num.charAt(i) - '0') % 2 ;
            if( i > 0 || (i == 0 && d != 0))
                sb.append(d);
        }

        return sb.toString();
    }
私有静态int-dfs(字符串num、int-step、映射内存){
如果(num.equals(“1”)){
返回步骤;
}
整数大小=memory.get(num);
if(size!=null&&size=0;i--){
int d=(进位+num.charAt(i)-'0')%10;
进位=(进位+num.charAt(i)-'0')/10;
sb.插入(0,d);
}
如果(进位==1){
某人插入(0,进位);
}
使某人返回字符串();
}
私有静态字符串divideBy2(字符串编号){
StringBuilder sb=新的StringBuilder();
int x=0;
对于(int i=0;i0 | |(i==0&&d!=0))
某人(d);
}
使某人返回字符串();
}
注意:在测试了几个案例后:我有了一些感觉,但不能概括规则。 如果当前数字为奇数。我们有两个选择:加1或减1。操作后的数字可以再除以2次,步骤会更短

更新:嗨,伙计们,我工作了一整晚,找到了一个通过测试的解决方案。其思想是将问题分为两个子问题:1。如果数字是偶数,就把它除以二。2.如果数字为奇数,请选择让数字在其位表示中具有更多尾随零的方式。我将进一步解释奇数情况:如果数字是奇数,最后两位可以是“01”或“11”。当它为“01”时,将其减少1,使最后两位变为“00”。如果是“11”,则增加1,生成“00”。通过这样做,奇数生成的下一个偶数可以被多次除,这在实践中非常快。下面是我的代码,如果您对实现有任何疑问,请随时向我发送消息:

public static int answer(String n) { 

        // Your code goes here.
        int count = 0;
        while(!n.equals("1")){
            if((n.charAt(n.length() - 1) - '0') % 2 == 0){
                n = divideBy2(n);
            }else if(n.equals("3") || lastTwoBit(n)){
                n = subtractOne(n);
            }else{
                n = plusOne(n);
            }
            count++;
        }
        return count;
    } 
      private static boolean lastTwoBit(String num){
          int n = -1;
          if(num.length() == 1){
              n = Integer.valueOf(num);
          }else{
              n = Integer.valueOf(num.substring(num.length() - 2, num.length()));
          }
          if(((n >>> 1) & 1) == 0){
            return true;
          }
          return false;
      }
      private static String subtractOne(String num){
         if(num.equals("1")){
            return "0";
         }
         StringBuilder sb = new StringBuilder();
         int carry = -1;
         for(int i = num.length() - 1; i >= 0; i--){
             int d = carry + num.charAt(i) - '0';
             if(d < 0){
                 carry = -1;
                 sb.insert(0, '9');
             }else if((d == 0 && i != 0) || d > 0){
                 carry = 0;
                 sb.insert(0, d );
             }
         }
         return sb.toString();
     }
    private static String plusOne(String num){
        StringBuilder sb = new StringBuilder();
        int carry = 1;
        int i = 0;
        for(i = num.length() - 1; i >=0; i--){
            if(carry == 0){
                break;
            }
            int d = (carry + num.charAt(i) - '0') % 10;
            carry = (carry + num.charAt(i) - '0') / 10;
            sb.insert(0, d);
        }
        if(carry ==0){
            sb.insert(0, num.substring(0, i + 1));
        }
        if(carry == 1){
            sb.insert(0, carry);
        }
        return sb.toString();
    }
    private static String divideBy2(String num){
        StringBuilder sb = new StringBuilder();
        int x = 0;
        for(int i = 0; i < num.length(); i++){
            int d = (x * 10 + num.charAt(i) - '0') / 2 ;
            x = (num.charAt(i) - '0') % 2 ;
            if( i > 0 || (i == 0 && d != 0))
                sb.append(d);
        }

        return sb.toString();
    }
公共静态int应答(字符串n){
//你的密码在这里。
整数计数=0;
而(!n.equals(“1”)){
如果((n.charAt(n.length()-1)-“0”)%2==0){
n=除以2(n);
}else如果(n等于(“3”)| |最后两位(n)){
n=减去一(n);
}否则{
n=冥王星(n);
}
计数++;
}
返回计数;
} 
私有静态布尔lastTwoBit(字符串num){
int n=-1;
如果(num.length()==1){
n=整数。值(num);
}否则{
n=整数.valueOf(num.substring(num.length()-2,num.length());
}
如果((n>>>1)&1)==0){
返回true;
}
返回false;
}
私有静态字符串减一(字符串数){
如果(num.equals(“1”)){
返回“0”;
}
StringBuilder sb=新的StringBuilder();
整数进位=-1;
对于(int i=num.length()-1;i>=0;i--){
int d=进位+num.charAt(i)-“0”;
if(d<0){
进位=-1;
sb.插入(0,'9');
}else如果((d==0&&i!=0)| | d>0){
进位=0;
sb.插入(0,d);
}
}
使某人返回字符串();
}
专用静态字符串plusOne(字符串编号){
StringBuilder sb=新的StringBuilder();
整数进位=1;
int i=0;
对于(i=num.length()-1;i>=0;i--){
如果(进位==0){
打破
}
int d=(进位+num.charAt(i)-'0')%10;
进位=(进位+num.charAt(i)-'0')/10;
sb.插入(0,d);
}
如果(进位==0){
sb.插入(0,num.substring(0,i+1));
}
如果(进位==1){
某人插入(0,进位);
}
使某人返回字符串();
}
私有静态字符串divideBy2(字符串编号){
StringBuilder sb=新的StringBuilder();
int x=0;
对于(int i=0;i0 | |(i==0&&d!=0))
某人(d);
}
使某人返回字符串();
}
而不是在1。。。 如果奇怪的话。。。减去1=>偶数 即使。。除以2

只要把老年退休金加起来就可以了

e、 g.5593
5593-1=5592/2=2796/2=1398/2=699-1=698/2=349-1
    public int make1(string s)
    {
        int n = 0;
        while(s != "1")
        {
            switch(s[s.Length-1])
            {
                case '0':
                case '2':
                case '4':
                case '6':
                case '8':
                    s = div2(s);
                    ++n;
                    break;
                case '1':
                case '3':
                case '5':
                case '7':
                case '9':
                    s = minus1(s);
                    s = div2(s);
                    n += 2;
            }
        }
        return n;
    }