我现在正致力于代码挑战。我的解决方案得到了“时间超过”,即使我已经优化了它。我正在寻求更有效的解决方案的帮助或更多地优化我的解决方案。
问题的描述是: 编写一个函数,它将一个正整数作为一个字符串,并返回将数字转换为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();
}
注意:经过几个案例的测试:我有一些意义,但不能概括规则。 如果当前的数字是奇数。我们在这里有两个选择:加1或减1.操作后的数字可以再划分2次,步骤会更短。
更新:嗨,伙计们,我整晚都在工作,并找到通过测试的解决方案。这个想法是将问题分成两个子问题:1。如果数字是偶数,则将其除以2。 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();
}
答案 0 :(得分:-2)
虽然不是1 ... 如果奇数...减去1 =&gt;甚至 如果偶数......除以2。
只需对操作进行求和并返回。
e.g。 5593
5593 -1 = 5592 /2 = 2796 /2 = 1398 /2 = 699 -1 = 698 /2 = 349 -1 = 348 /2 = 174 /2 = 87 -1 = 86 /2 = 43 -1 = 42 /2 = 21 -1 = 20 /2 = 10 /2 = 5 -1 = 4 /2 = 2 /2 = 1
19 Operations -///-/-//-/-/-//-//
编辑:时间复杂度为O(logN)
,我们将数字除以2 /减去然后除。
和空格为O(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;
}