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