Minimum Steps to One

后端 未结 4 1240
庸人自扰
庸人自扰 2021-01-01 23:12

Problem statement :

On a positive integer, you can perform any one of the following 3 steps.

  1. Subtract 1 from it. ( n = n - 1 )
  2. If its divis
相关标签:
4条回答
  • 2021-01-01 23:56

    UPDATE: Here is updated code which I have actually tested somewhat and I believe comes to the same answers for n from 1 to 100000. I'm leaving the original answer below for reference. The flaw was the "clever" use of MAX_INT. I forgot that there would be some cases where I skipped the -1 possibility but the number would also not be divisible by 2 or 3. This solves that by returning null to mean "this path is pointless to explore further".

    public static int steps(int n) {
        return steps(n, 0);
    }
    private static Integer steps(int n, int consecutiveMinusOnes) {
        if (n <= 1) {
            return 0;
        }
        Integer minSteps = null;
        if (consecutiveMinusOnes < 2) {
            Integer subOne = steps(n - 1, consecutiveMinusOnes + 1);
            if (subOne != null) {
                minSteps = 1 + subOne;
            }
        }
        if (n % 2 == 0) {
            Integer div2 = steps(n / 2, 0);
            if (div2 != null) {
                if (minSteps == null) {
                    minSteps = div2 + 1;
                } else {
                    minSteps = Math.min(minSteps, 1 + div2);
                }
            }
        }
        if (n % 3 == 0) {
            Integer div3 = steps(n / 3, 0);
            if (div3 != null) {
                if (minSteps == null) {
                    minSteps = div3 + 1;
                } else {
                    minSteps = Math.min(minSteps, 1 + div3);
                }
            }
        }
        return minSteps;
    }
    

    I believe this may work, but I haven't proved it. This algorithm is based on the idea that the only reason to subtract by one is to get you closer to a number divisible by 2 or 3. For this reason, you never really need to apply the subtract-by-one step more than two times consecutively, because if k % 3 == 2, then k - 2 % 3 == 0 and you can divide by three. Subtracting by one more times will be a wast of effort (you'll have also passed by at least one even number, so the best divide by two step opportunity will come up). This means a top down, recursive approach, and you can mix in some memoization if you want to:

    public static int steps(n) {
        return steps(n, 0);
    }
    private static int steps(int n, int consecutiveMinusOnes) {
        if (n <= 1) {
            return 0;
        }
        int minSteps = Integer.MAX_VALUE;
        if (consecutiveMinusOnes < 2) {
            minSteps = 1 + steps(n - 1, consecutiveMinusOnes + 1);
        }
        if (n % 2 == 0) {
            minSteps = Math.min(minSteps, 1 + steps(n / 2, 0));
        }
        if (n % 3 == 0) {
            minSteps = Math.min(minSteps, 1 + steps(n / 3, 0));
        }
        return minSteps;
    }
    

    DISCLAIMER: As I said above, I haven't proved this method works. I also haven't tested this particular implementation. I also haven't done the memoization stuff just because I'm lazy. Anyway, I hope that even if this doesn't quite work it gives you some ideas on how to modify your approach.

    0 讨论(0)
  • 2021-01-01 23:58

    Recursive Solution For this problem

    
    public static int countMinStepsTo1(int n){
    
          if(n==1)
          {
              return 0;
          } 
          int count1,count2=Integer.MAX_VALUE,count3=Integer.MAX_VALUE;
    
          count1 = countMinStepsTo1(n-1);
    
           if((n%2)==0)
           {
               count2=countMinStepsTo1(n/2);
           }
            if((n%3)==0)
            {
                count3=countMinStepsTo1(n/3);
            }
    
            return 1+Math.min(count1,Math.min(count2,count3));
        }
    

    DP Approch For this problem

    public static int countstepsDP(int n)
        {
            int storage[] = new int[n+1];
            storage[1]=0;
    
            for(int i=2; i<=n;i++)
            {
                int min=storage[i-1];
                if(i%3==0)
                {
                    if(min>storage[i/3])
                    {
                        min=storage[i/3];
                    }
                }
                if(i%2==0)
                {
                    if(min>storage[i/2])
                    {
                        min=storage[i/2];
                    }
                }
                storage[i]=1+min;
            }
    
            return storage[n];
    
        } 
    
    0 讨论(0)
  • 2021-01-02 00:01

    This works :)

    import java.util.Scanner;
    public class MinimumStepToOne {
    
     public static void main(String[] args){
        Scanner sscan = new Scanner(System.in);
        System.out.print("Give a no:" + " ");
    
        int n = sscan.nextInt();
        int count = 0;
        for(int i = 0; n > 1; i++){
    
            if(n%2 == 0){n /= 2; count++;}
            else if(n%3 == 0){ n /= 3; count++;}
            else { n -= 1; count++;}
    
        }
        System.out.println("your no is minimized to: " + n);
        System.out.println("The min no of steps: " + count);    
     }
    }
    
    0 讨论(0)
  • 2021-01-02 00:06

    One idea is that at any iteration you need the values only for r/3 to r. So you can keep discarding 1/3rd of the array.

    I'm not familiar with Java, but with C++ you can use a double ended queue (deque):

    You keep adding to the deque from the back.
    When i = 6, you do not need bu[0] and bu[1]. So you pop out two elements from the front of the queue.

    Random access [ ] is supported with deque container.

    EDIT: Also as suggested in the comments, you should change your datatype to a smaller sized one since the maximum number of steps shall be of the order of ( (log N) to base 2)

    EDIT2: As Dukeling pointed out, it seems that in Java there is no ready-made well-suited implementation for deque that would not compromise on time complexity. You can think of implementing it in your own way as C++ does (I heard it is implemented as a vector of vectors with the size of inner vectors being small as compared to the total number of elements).

    0 讨论(0)
提交回复
热议问题