📌  相关文章
📜  以最少的步骤找到一个数字

📅  最后修改于: 2022-05-13 01:57:17.224000             🧑  作者: Mango

以最少的步骤找到一个数字

给定从 -INFINITY 到 +INFINITY 的无限数线,我们为零。我们可以在每第 n 次左右移动 n 步。

方法 1:使用树

1st time; we can move only 1 step to both ways, means -1 1;

2nd time we can move 2 steps  from -1 and 1;
-1 :  -3 (-1-2)  1(-1+2)
 1 :  -1 ( 1-2)  3(1+2)

3rd time we can move 3 steps either way from -3, 1, -1, 3 
-3:  -6(-3-3) 0(-3+3)
1:   -2(1-3)   4(1+3)
-1:  -4(-1-3)  2(-1+3)
3:     0(0-3)   6(3+3) 

Find the minimum number of steps to reach a given number n.

例子:

Input : n = 10
Output : 4
We can reach 10 in 4 steps,  1, 3, 6, 10 


Input : n = 13
Output : 5
We can reach 10 in 4 steps,  -1, 2, 5, 9, 14

这个问题可以建模为树。我们将初始点 0 放在 root 处,将 1 和 -1 作为 root 的孩子。下一级包含距离 2 处的值,依此类推。

0
            /   \
         -1       1  
        /  \     /  \
       1   -3   -1   3
     /  \  / \  / \  / \

现在的问题是找到值 n 的关闭节点到根。这个想法是对树进行级别顺序遍历以找到最近的节点。请注意,对最近的节点使用 DFS 绝不是一个好主意(我们最终可能会降低许多不必要的级别)。

下面是上述想法的 C++、 Python实现。

C++
// C++ program to find a number in minimum steps
#include 
using namespace std;
#define InF 99999
 
// To represent data of a node in tree
struct number {
    int no;
    int level;
 
public:
    number() {}
    number(int n, int l)
        : no(n), level(l)
    {
    }
};
 
// Prints level of node n
void findnthnumber(int n)
{
    // Create a queue and insert root
    queue q;
    struct number r(0, 1);
    q.push(r);
 
    // Do level order traversal
    while (!q.empty()) {
        // Remove a node from queue
        struct number temp = q.front();
        q.pop();
 
        // To avoid infinite loop
        if (temp.no >= InF || temp.no <= -InF)
            break;
 
        // Check if dequeued number is same as n
        if (temp.no == n) {
            cout << "Found number n at level "
                 << temp.level - 1;
            break;
        }
 
        // Insert children of dequeued node to queue
        q.push(number(temp.no + temp.level, temp.level + 1));
        q.push(number(temp.no - temp.level, temp.level + 1));
    }
}
 
// Driver code
int main()
{
    findnthnumber(13);
    return 0;
}


Java
// Java program to find a number in minimum steps
import java.util.*;
class GFG
{
  static final int InF = 99999;
 
  // To represent data of a node in tree
  static class number
  {
    int no;
    int level;
    number() {}
    number(int n, int l)
    {
      this.no = n;
      this.level = l;
    }
  };
 
  // Prints level of node n
  static void findnthnumber(int n)
  {
 
    // Create a queue and insert root
    Queue q = new LinkedList<>();
    number r = new number(0, 1);
    q.add(r);
 
    // Do level order traversal
    while (!q.isEmpty())
    {
 
      // Remove a node from queue
      number temp = q.peek();
      q.remove();
 
      // To astatic void infinite loop
      if (temp.no >= InF || temp.no <= -InF)
        break;
 
      // Check if dequeued number is same as n
      if (temp.no == n)
      {
        System.out.print("Found number n at level "
                         + (temp.level - 1));
        break;
      }
 
      // Insert children of dequeued node to queue
      q.add(new number(temp.no + temp.level, temp.level + 1));
      q.add(new number(temp.no - temp.level, temp.level + 1));
    }
  }
 
  // Driver code
  public static void main(String[] args)
  {
    findnthnumber(13);
  }
}
 
// This code is contributed by gauravrajput1


Python3
from collections import deque
 
# Python program to find a number in minimum steps
InF = 99999
 
# To represent data of a node in tree
class number:
    def __init__(self,n,l):
        self.no = n
        self.level = l
 
# Prints level of node n
def findnthnumber(n):
    # Create a queue and insert root
    q = deque()
    r = number(0, 1)
    q.append(r)
 
    # Do level order traversal
    while (len(q) > 0):
        # Remove a node from queue
        temp = q.popleft()
        # q.pop()
 
        # To avoid infinite loop
        if (temp.no >= InF or temp.no <= -InF):
            break
 
        # Check if dequeued number is same as n
        if (temp.no == n):
            print("Found number n at level", temp.level - 1)
            break
 
        # Insert children of dequeued node to queue
        q.append(number(temp.no + temp.level, temp.level + 1))
        q.append(number(temp.no - temp.level, temp.level + 1))
 
# Driver code
if __name__ == '__main__':
    findnthnumber(13)
 
# This code is contributed by mohit kumar 29


C#
// C# program to find a number in minimum steps
using System;
using System.Collections.Generic;
public
class GFG
{
  static readonly int InF = 99999;
 
  // To represent data of a node in tree
  public
 class number
  {
    public
 int no;
    public
 int level;
    public
 number() {}
    public
 number(int n, int l)
    {
      this.no = n;
      this.level = l;
    }
  };
 
  // Prints level of node n
  static void findnthnumber(int n)
  {
 
    // Create a queue and insert root
    Queue q = new Queue();
    number r = new number(0, 1);
    q.Enqueue(r);
 
    // Do level order traversal
    while (q.Count != 0)
    {
 
      // Remove a node from queue
      number temp = q.Peek();
      q.Dequeue();
 
      // To astatic void infinite loop
      if (temp.no >= InF || temp.no <= -InF)
        break;
 
      // Check if dequeued number is same as n
      if (temp.no == n)
      {
        Console.Write("Found number n at level "
                         + (temp.level - 1));
        break;
      }
 
      // Insert children of dequeued node to queue
      q.Enqueue(new number(temp.no + temp.level, temp.level + 1));
      q.Enqueue(new number(temp.no - temp.level, temp.level + 1));
    }
  }
 
  // Driver code
  public static void Main(String[] args)
  {
    findnthnumber(13);
  }
}
 
// This code is contributed by gauravrajput1


Javascript


C++
// C++ program to Find a
// number in minimum steps
#include 
using namespace std;
 
vector find(int n)
{
    // Steps sequence
    vector ans;
 
    // Current sum
    int sum = 0;
    int i;
 
    // Sign of the number
    int sign = (n >= 0 ? 1 : -1);
    n = abs(n);
 
    // Basic steps required to get
    // sum >= required value.
    for (i = 1; sum < n; i++) {
        ans.push_back(sign * i);
        sum += i;
    }
 
    // If we have reached ahead to destination.
    if (sum > sign * n) {
        /*If the last step was an odd number,
         then it has following mechanism for
         negating a particular number and
         decreasing the sum to required number
         Also note that it may require
         1 more step in order to reach the sum. */
        if (i % 2) {
            sum -= n;
            if (sum % 2) {
                ans.push_back(sign * i);
                sum += i++;
            }
            ans[(sum / 2) - 1] *= -1;
        }
        else {
            /* If the current time instance is even
            and sum is odd than it takes
            2 more steps and few
            negations in previous elements
            to reach there. */
            sum -= n;
            if (sum % 2) {
                sum--;
                ans.push_back(sign * i);
                ans.push_back(sign * -1 * (i + 1));
            }
            ans[(sum / 2) - 1] *= -1;
        }
    }
    return ans;
}
 
// Driver Program
int main()
{
    int n = 20;
    if (n == 0)
        cout << "Minimum number of Steps: 0\nStep sequence:\n0";
    else {
        vector a = find(n);
        cout << "Minimum number of Steps: " << a.size() << "\nStep sequence:\n";
        for (int i : a)
            cout << i << " ";
    }
    return 0;
}


Java
// Java program to Find a
// number in minimum steps
import java.util.*;
class GFG
{
  static Vector find(int n)
  {
 
    // Steps sequence
    Vector ans = new Vector<>();
 
    // Current sum
    int sum = 0;
    int i = 1;
 
    // Sign of the number
    int sign = (n >= 0 ? 1 : -1);
    n = Math.abs(n);
 
    // Basic steps required to get
    // sum >= required value.
    for (; sum < n;)
    {
      ans.add(sign * i);
      sum += i;
      i++;
    }
 
    // If we have reached ahead to destination.
    if (sum > sign * n)
    {
 
      /*If the last step was an odd number,
         then it has following mechanism for
         negating a particular number and
         decreasing the sum to required number
         Also note that it may require
         1 more step in order to reach the sum. */
      if (i % 2 != 0)
      {
        sum -= n;
        if (sum % 2 != 0)
        {
          ans.add(sign * i);
          sum += i;
          i++;
        }
        int a = ans.get((sum / 2) - 1);
        ans.remove((sum / 2) - 1);
        ans.add(((sum / 2) - 1), a*(-1));
      }
      else
      {
 
        /* If the current time instance is even
            and sum is odd than it takes
            2 more steps and few
            negations in previous elements
            to reach there. */
        sum -= n;
        if (sum % 2 != 0)
        {
          sum--;
          ans.add(sign * i);
          ans.add(sign * -1 * (i + 1));
        }
        ans.add((sum / 2) - 1, ans.get((sum / 2) - 1) * -1);
      }
    }
    return ans;
  }
 
  // Driver Program
  public static void main(String[] args)
  {
    int n = 20;
    if (n == 0)
      System.out.print("Minimum number of Steps: 0\nStep sequence:\n0");
    else
    {
      Vector a = find(n);
      System.out.print("Minimum number of Steps: " + 
                       a.size()+ "\nStep sequence:\n");
      for (int i : a)
        System.out.print(i + " ");
    }
  }
}
 
// This code is contributed by aashish1995


Python3
# Python3 program to Find a
# number in minimum steps
def find(n):
     
    # Steps sequence
    ans = []
     
    # Current sum
    Sum = 0
    i = 0
     
    # Sign of the number
    sign = 0
     
    if (n >= 0):
        sign = 1
    else:
        sign = -1
 
    n = abs(n)
    i = 1
     
    # Basic steps required to get
    # sum >= required value.
    while (Sum < n):
        ans.append(sign * i)
        Sum += i
        i += 1
 
    # If we have reached ahead to destination.
    if (Sum > sign * n):
         
        # If the last step was an odd number,
        # then it has following mechanism for
        # negating a particular number and
        # decreasing the sum to required number
        # Also note that it may require
        # 1 more step in order to reach the sum.
        if (i % 2!=0):
            Sum -= n
             
            if (Sum % 2 != 0):
                ans.append(sign * i)
                Sum += i
                i += 1
                 
            ans[int(Sum / 2) - 1] *= -1
        else:
             
            # If the current time instance is even
            # and sum is odd than it takes
            # 2 more steps and few
            # negations in previous elements
            # to reach there.
            Sum -= n
             
            if (Sum % 2 != 0):
                Sum -= 1
                ans.append(sign * i)
                ans.append(sign * -1 * (i + 1))
                 
            ans[int((sum / 2)) - 1] *= -1
     
    return ans
 
# Driver code
n = 20
 
if (n == 0):
    print("Minimum number of Steps: 0\nStep sequence:\n0")
else:
    a = find(n)
    print("Minimum number of Steps:", len(a))
    print("Step sequence:")
    print(*a, sep = " ")
 
# This code is contributed by rag2127


C#
// C# program to Find a
// number in minimum steps
using System;
using System.Collections.Generic;
public class GFG
{
  static List find(int n)
  {
 
    // Steps sequence
    List ans = new List();
 
    // Current sum
    int sum = 0;
    int i = 1;
 
    // Sign of the number
    int sign = (n >= 0 ? 1 : -1);
    n = Math.Abs(n);
 
    // Basic steps required to get
    // sum >= required value.
    for (; sum < n;)
    {
      ans.Add(sign * i);
      sum += i;
      i++;
    }
 
    // If we have reached ahead to destination.
    if (sum > sign * n)
    {
 
      /*If the last step was an odd number,
         then it has following mechanism for
         negating a particular number and
         decreasing the sum to required number
         Also note that it may require
         1 more step in order to reach the sum. */
      if (i % 2 != 0)
      {
        sum -= n;
        if (sum % 2 != 0)
        {
          ans.Add(sign * i);
          sum += i;
          i++;
        }
        int a = ans[((sum / 2) - 1)];
        ans.RemoveAt((sum / 2) - 1);
        ans.Insert(((sum / 2) - 1), a*(-1));
      }
      else
      {
 
        /* If the current time instance is even
            and sum is odd than it takes
            2 more steps and few
            negations in previous elements
            to reach there. */
        sum -= n;
        if (sum % 2 != 0)
        {
          sum--;
          ans.Add(sign * i);
          ans.Add(sign * -1 * (i + 1));
        }
        ans.Insert((sum / 2) - 1, ans[(sum / 2) - 1] * -1);
      }
    }
    return ans;
  }
 
  // Driver Program
  public static void Main(String[] args)
  {
    int n = 20;
    if (n == 0)
      Console.Write("Minimum number of Steps: 0\nStep sequence:\n0");
    else
    {
      List a = find(n);
      Console.Write("Minimum number of Steps: " + 
                    a.Count+ "\nStep sequence:\n");
      foreach (int i in a)
        Console.Write(i + " ");
    }
  }
}
 
// This code is contributed by Rajput-Ji


Javascript


输出:

Found number n at level 5

以上解决方案由Mu Ven提供。

方法 2:使用向量

上述解决方案使用二叉树作为第 n 个时间实例,即 -n 和 n。但是随着树的级别增加,这变得低效。对于类似 abs(200) 或以上程序的值,程序会给出分段错误。
以下解决方案不会生成树,并且复杂度等于所需的确切步骤数。所需的步骤也打印在数组中,该数组等于所需的确切总和。

大意:

  • +n 和 -n 之间的距离为 2*n。因此,如果您从 +ve 到 -ve 取反一个数字,它将与之前的总和产生 2*n 的差异。
  • 如果对于任何 n,一个数介于 n(n+1)/2 和 (n+1)(n+2)/2 之间,那么我们转到步骤 (n+1)(n+2)/2 并尝试减少使用上面讨论的想法的差异总和。
  • 如果我们去 n(n+1)/2 然后尝试增加比它最终会引导你到相同数量的步骤。
    而且由于您不能从 n(n+1)/2 中否定任何数字(因为总和已经小于所需的总和),这证明它需要最少的步数。

C++

// C++ program to Find a
// number in minimum steps
#include 
using namespace std;
 
vector find(int n)
{
    // Steps sequence
    vector ans;
 
    // Current sum
    int sum = 0;
    int i;
 
    // Sign of the number
    int sign = (n >= 0 ? 1 : -1);
    n = abs(n);
 
    // Basic steps required to get
    // sum >= required value.
    for (i = 1; sum < n; i++) {
        ans.push_back(sign * i);
        sum += i;
    }
 
    // If we have reached ahead to destination.
    if (sum > sign * n) {
        /*If the last step was an odd number,
         then it has following mechanism for
         negating a particular number and
         decreasing the sum to required number
         Also note that it may require
         1 more step in order to reach the sum. */
        if (i % 2) {
            sum -= n;
            if (sum % 2) {
                ans.push_back(sign * i);
                sum += i++;
            }
            ans[(sum / 2) - 1] *= -1;
        }
        else {
            /* If the current time instance is even
            and sum is odd than it takes
            2 more steps and few
            negations in previous elements
            to reach there. */
            sum -= n;
            if (sum % 2) {
                sum--;
                ans.push_back(sign * i);
                ans.push_back(sign * -1 * (i + 1));
            }
            ans[(sum / 2) - 1] *= -1;
        }
    }
    return ans;
}
 
// Driver Program
int main()
{
    int n = 20;
    if (n == 0)
        cout << "Minimum number of Steps: 0\nStep sequence:\n0";
    else {
        vector a = find(n);
        cout << "Minimum number of Steps: " << a.size() << "\nStep sequence:\n";
        for (int i : a)
            cout << i << " ";
    }
    return 0;
}

Java

// Java program to Find a
// number in minimum steps
import java.util.*;
class GFG
{
  static Vector find(int n)
  {
 
    // Steps sequence
    Vector ans = new Vector<>();
 
    // Current sum
    int sum = 0;
    int i = 1;
 
    // Sign of the number
    int sign = (n >= 0 ? 1 : -1);
    n = Math.abs(n);
 
    // Basic steps required to get
    // sum >= required value.
    for (; sum < n;)
    {
      ans.add(sign * i);
      sum += i;
      i++;
    }
 
    // If we have reached ahead to destination.
    if (sum > sign * n)
    {
 
      /*If the last step was an odd number,
         then it has following mechanism for
         negating a particular number and
         decreasing the sum to required number
         Also note that it may require
         1 more step in order to reach the sum. */
      if (i % 2 != 0)
      {
        sum -= n;
        if (sum % 2 != 0)
        {
          ans.add(sign * i);
          sum += i;
          i++;
        }
        int a = ans.get((sum / 2) - 1);
        ans.remove((sum / 2) - 1);
        ans.add(((sum / 2) - 1), a*(-1));
      }
      else
      {
 
        /* If the current time instance is even
            and sum is odd than it takes
            2 more steps and few
            negations in previous elements
            to reach there. */
        sum -= n;
        if (sum % 2 != 0)
        {
          sum--;
          ans.add(sign * i);
          ans.add(sign * -1 * (i + 1));
        }
        ans.add((sum / 2) - 1, ans.get((sum / 2) - 1) * -1);
      }
    }
    return ans;
  }
 
  // Driver Program
  public static void main(String[] args)
  {
    int n = 20;
    if (n == 0)
      System.out.print("Minimum number of Steps: 0\nStep sequence:\n0");
    else
    {
      Vector a = find(n);
      System.out.print("Minimum number of Steps: " + 
                       a.size()+ "\nStep sequence:\n");
      for (int i : a)
        System.out.print(i + " ");
    }
  }
}
 
// This code is contributed by aashish1995

Python3

# Python3 program to Find a
# number in minimum steps
def find(n):
     
    # Steps sequence
    ans = []
     
    # Current sum
    Sum = 0
    i = 0
     
    # Sign of the number
    sign = 0
     
    if (n >= 0):
        sign = 1
    else:
        sign = -1
 
    n = abs(n)
    i = 1
     
    # Basic steps required to get
    # sum >= required value.
    while (Sum < n):
        ans.append(sign * i)
        Sum += i
        i += 1
 
    # If we have reached ahead to destination.
    if (Sum > sign * n):
         
        # If the last step was an odd number,
        # then it has following mechanism for
        # negating a particular number and
        # decreasing the sum to required number
        # Also note that it may require
        # 1 more step in order to reach the sum.
        if (i % 2!=0):
            Sum -= n
             
            if (Sum % 2 != 0):
                ans.append(sign * i)
                Sum += i
                i += 1
                 
            ans[int(Sum / 2) - 1] *= -1
        else:
             
            # If the current time instance is even
            # and sum is odd than it takes
            # 2 more steps and few
            # negations in previous elements
            # to reach there.
            Sum -= n
             
            if (Sum % 2 != 0):
                Sum -= 1
                ans.append(sign * i)
                ans.append(sign * -1 * (i + 1))
                 
            ans[int((sum / 2)) - 1] *= -1
     
    return ans
 
# Driver code
n = 20
 
if (n == 0):
    print("Minimum number of Steps: 0\nStep sequence:\n0")
else:
    a = find(n)
    print("Minimum number of Steps:", len(a))
    print("Step sequence:")
    print(*a, sep = " ")
 
# This code is contributed by rag2127

C#

// C# program to Find a
// number in minimum steps
using System;
using System.Collections.Generic;
public class GFG
{
  static List find(int n)
  {
 
    // Steps sequence
    List ans = new List();
 
    // Current sum
    int sum = 0;
    int i = 1;
 
    // Sign of the number
    int sign = (n >= 0 ? 1 : -1);
    n = Math.Abs(n);
 
    // Basic steps required to get
    // sum >= required value.
    for (; sum < n;)
    {
      ans.Add(sign * i);
      sum += i;
      i++;
    }
 
    // If we have reached ahead to destination.
    if (sum > sign * n)
    {
 
      /*If the last step was an odd number,
         then it has following mechanism for
         negating a particular number and
         decreasing the sum to required number
         Also note that it may require
         1 more step in order to reach the sum. */
      if (i % 2 != 0)
      {
        sum -= n;
        if (sum % 2 != 0)
        {
          ans.Add(sign * i);
          sum += i;
          i++;
        }
        int a = ans[((sum / 2) - 1)];
        ans.RemoveAt((sum / 2) - 1);
        ans.Insert(((sum / 2) - 1), a*(-1));
      }
      else
      {
 
        /* If the current time instance is even
            and sum is odd than it takes
            2 more steps and few
            negations in previous elements
            to reach there. */
        sum -= n;
        if (sum % 2 != 0)
        {
          sum--;
          ans.Add(sign * i);
          ans.Add(sign * -1 * (i + 1));
        }
        ans.Insert((sum / 2) - 1, ans[(sum / 2) - 1] * -1);
      }
    }
    return ans;
  }
 
  // Driver Program
  public static void Main(String[] args)
  {
    int n = 20;
    if (n == 0)
      Console.Write("Minimum number of Steps: 0\nStep sequence:\n0");
    else
    {
      List a = find(n);
      Console.Write("Minimum number of Steps: " + 
                    a.Count+ "\nStep sequence:\n");
      foreach (int i in a)
        Console.Write(i + " ");
    }
  }
}
 
// This code is contributed by Rajput-Ji

Javascript


输出 :

Minimum number of Steps: 7
Step sequence:
1 2 3 -4 5 6 7