📌  相关文章
📜  最小N位数,其位数的总和是一个完美平方

📅  最后修改于: 2021-04-22 09:23:35             🧑  作者: Mango

给定整数N,请找到最小的N位数字,以使该数字的平方和(以十进制表示)也是一个理想的平方。如果不存在这样的数字,则打印-1。
例子:

方法1:
为了解决上述问题,我们可以使用Backtracking 。由于我们要查找满足给定条件的最小N位数字,因此答案中的数字将以非降序排列。因此,我们在每个递归步骤中递归生成可能的数字,并跟踪以下内容:

  • position:递归步骤的当前位置,即放置哪个位置数字。
  • prev:上一个数字,因为当前数字必须大于等于prev。
  • sum:到目前为止放置的数字的平方和。放置数字时,这将用于检查所放置的所有数字的平方和是否为理想平方。
  • 一个向量,用于存储所有数字到此位置为止的内容。

如果将数字放置在某个位置并移至下一个递归步骤会导致可能的解决方案,则返回1,否则返回。
下面是上述方法的实现:

C++
// C++ implementation to find Smallest N
// digit number whose sum of square
// of digits is a Perfect Square
 
#include 
using namespace std;
 
// function to check if
// number is a perfect square
int isSquare(int n)
{
    int k = sqrt(n);
    return (k * k == n);
}
 
// function to calculate the
// smallest N digit number
int calculate(int pos, int prev,
              int sum, vector& v)
{
 
    if (pos == v.size())
        return isSquare(sum);
 
    // place digits greater than equal to prev
    for (int i = prev; i <= 9; i++) {
        v[pos] = i;
        sum += i * i;
 
        // check if palcing this digit leads
        // to a solution then return it
        if (calculate(pos + 1, i, sum, v))
            return 1;
 
        // else backtrack
        sum -= i * i;
    }
    return 0;
}
 
string minValue(int n)
{
 
    vector v(n);
    if (calculate(0, 1, 0, v)) {
 
        // create a string representing
        // the N digit number
        string answer = "";
        for (int i = 0; i < v.size(); i++)
 
            answer += char(v[i] + '0');
 
        return answer;
    }
 
    else
        return "-1";
}
 
// driver code
int main()
{
 
    // initialise N
    int N = 2;
 
    cout << minValue(N);
 
    return 0;
}


Java
// Java implementation to find Smallest N
// digit number whose sum of square
// of digits is a Perfect Square
class GFG{
     
// function to check if
// number is a perfect square
static int isSquare(int n)
{
    int k = (int)Math.sqrt(n);
    return k * k == n ? 1 : 0;
}
 
// Function to calculate the
// smallest N digit number
static int calculate(int pos, int prev,
                     int sum, int[] v)
{
    if (pos == v.length)
        return isSquare(sum);
 
    // Place digits greater than equal to prev
    for(int i = prev; i <= 9; i++)
    {
        v[pos] = i;
        sum += i * i;
 
        // Check if palcing this digit leads
        // to a solution then return it
        if (calculate(pos + 1, i, sum, v) != 0)
            return 1;
 
        // Else backtrack
        sum -= i * i;
    }
    return 0;
}
 
static String minValue(int n)
{
    int[] v = new int[n];
    if (calculate(0, 1, 0, v) != 0)
    {
         
        // Create a string representing
        // the N digit number
        String answer = "";
         
        for(int i = 0; i < v.length; i++)
            answer += (char)(v[i] + '0');
 
        return answer;
    }
    else
        return "-1";
}
 
// Driver code
public static void main(String[] args)
{
 
    // Initialise N
    int N = 2;
 
    System.out.println(minValue(N));
}
}
 
// This code is contributed by jrishabh99


Python3
# Python3 implementation to find Smallest N
# digit number whose sum of square
# of digits is a Perfect Square
from math import sqrt
 
# function to check if
# number is a perfect square
def isSquare(n):
    k = int(sqrt(n))
    return (k * k == n)
 
# function to calculate the
# smallest N digit number
def calculate(pos, prev, sum, v):
 
    if (pos == len(v)):
        return isSquare(sum)
 
    # place digits greater than equal to prev
    for i in range(prev, 9 + 1):
        v[pos] = i
        sum += i * i
 
        # check if palcing this digit leads
        # to a solution then return it
        if (calculate(pos + 1, i, sum, v)):
            return 1
 
        # else backtrack
        sum -= i * i
 
    return 0
 
def minValue(n):
    v = [0]*(n)
    if (calculate(0, 1, 0, v)):
 
        # create a representing
        # the N digit number
        answer = ""
        for i in range(len(v)):
 
            answer += chr(v[i] + ord('0'))
 
        return answer
 
    else:
        return "-1"
 
 
# Driver code
if __name__ == '__main__':
 
    # initialise N
    N = 2
 
    print(minValue(N))
 
# This code is contributed by mohit kumar 29


C#
// C# implementation to find Smallest N
// digit number whose sum of square
// of digits is a Perfect Square
using System;
class GFG{
     
// function to check if
// number is a perfect square
static int isSquare(int n)
{
    int k = (int)Math.Sqrt(n);
    return k * k == n ? 1 : 0;
}
 
// Function to calculate the
// smallest N digit number
static int calculate(int pos, int prev,
                     int sum, int[] v)
{
    if (pos == v.Length)
        return isSquare(sum);
 
    // Place digits greater than equal to prev
    for(int i = prev; i <= 9; i++)
    {
        v[pos] = i;
        sum += i * i;
 
        // Check if palcing this digit leads
        // to a solution then return it
        if (calculate(pos + 1, i, sum, v) != 0)
            return 1;
 
        // Else backtrack
        sum -= i * i;
    }
    return 0;
}
 
static string minValue(int n)
{
    int[] v = new int[n];
    if (calculate(0, 1, 0, v) != 0)
    {
         
        // Create a string representing
        // the N digit number
        string answer = "";
         
        for(int i = 0; i < v.Length; i++)
            answer += (char)(v[i] + '0');
 
        return answer;
    }
    else
        return "-1";
}
 
// Driver code
public static void Main()
{
 
    // Initialise N
    int N = 2;
 
    Console.Write(minValue(N));
}
}


C++
// C++ implementation to find the Smallest
// N digit number whose sum of square
// of digits is a Perfect Square
#include 
using namespace std;
long long value[8100006];
int first[8100006];
// array for all possible changes
int coins[8] = { 3, 8, 15, 24, 35, 48, 63, 80 };
 
void coinChange()
{
    const long long inf = INT_MAX;
 
    // iterating till 81 * N
    // since N is at max 10^5
    for (int x = 1; x <= 8100005; x++) {
 
        value[x] = inf;
 
        for (auto c : coins) {
            if (x - c >= 0 && value[x - c] + 1 < value[x]) {
                value[x] = min(value[x], value[x - c] + 1);
 
                // least value of coin
                first[x] = c;
            }
        }
    }
}
 
// function to find the
// minimum possible value
string minValue(int n)
{
 
    // aplying coin change for all the numbers
    coinChange();
 
    string answer = "";
 
    // check if number is
    // perfect square or not
    if ((sqrt(n) * sqrt(n)) == n) {
        for (int i = 0; i < n; i++)
 
            answer += "1";
 
        return answer;
    }
 
    long long hi = 81 * n;
    long long lo = sqrt(n);
 
    // keeps a check whether
    // number is found or not
    bool found = false;
 
    long long upper = 81 * n;
    long long lower = n;
 
    // sotring suffix strings
    string suffix;
    bool suf_init = false;
 
    while ((lo * lo) <= hi) {
        lo++;
 
        long long curr = lo * lo;
 
        long long change = curr - n;
 
        if (value[change] <= lower) {
 
            // build a suffix string
            found = true;
 
            if (lower > value[change]) {
                // number to be used for updation of lower,
                // first values that will be used
                // to construct the final number later
                lower = value[change];
                upper = change;
                suffix = "";
                suf_init = true;
                int len = change;
 
                while (len > 0) {
                    int k = sqrt(first[len] + 1);
                    suffix = suffix + char(k + 48);
                    len = len - first[len];
                }
            }
 
            else if (lower == value[change]) {
                string tempsuf = "";
                int len = change;
                while (len > 0) {
                    int k = sqrt(first[len] + 1);
                    tempsuf = tempsuf + char(k + 48);
                    len = len - first[len];
                }
 
                if (tempsuf < suffix or suf_init == false) {
                    lower = value[change];
                    upper = change;
                    suffix = tempsuf;
                    suf_init = true;
                }
            }
        }
    }
    // check if number is found
    if (found) {
        // construct the number from first values
        long long x = lower;
        for (int i = 0; i < (n - x); i++)
            answer += "1";
 
        long long temp = upper;
 
        // fill in rest of the digits
        while (temp > 0) {
            int dig = sqrt(first[temp] + 1);
            temp = temp - first[temp];
            answer += char(dig + '0');
        }
        return answer;
    }
    else
        return "-1";
}
 
// driver code
int main()
{
 
    // initialise N
    int N = 2;
 
    cout << minValue(N);
 
    return 0;
}


输出
34

方法2:
上述问题也可以使用动态编程解决。如果我们仔细观察该问题,就会发现它可以转换为标准的找零问题。给定N为位数,则基本答案将为N 1,其位数的平方和为N。

  • 如果N本身是一个完美的正方形,那么N乘以1将是最终答案。
  • 否则,我们将不得不用2-9之间的其他数字替换答案中的一些1。数字中的每个替换将使平方和增加一定量,并且由于1可以更改为仅其他8个可能的数字,因此只有8个这样的可能增量。例如,如果1更改为2,则增量将为2 2 – 1 2 =3。类似地,所有可能的更改为:{3,8,15,24,35,48,63,80}。

因此,现在可以将问题解释为具有上述值的8种硬币,并且我们可以使用任意次数的任何硬币来创建所需的总和。平方和在N(所有数字均为1)到81 * N(所有数字均为9)的范围内。我们只需要考虑该范围内的理想平方和,并使用硬币找零的想法来找到答案中要用到的N位数字。我们需要考虑的重要一点是,我们必须找到最小的N位数字,而不是数字平方和最小的数字。
下面是上述方法的实现:

C++

// C++ implementation to find the Smallest
// N digit number whose sum of square
// of digits is a Perfect Square
#include 
using namespace std;
long long value[8100006];
int first[8100006];
// array for all possible changes
int coins[8] = { 3, 8, 15, 24, 35, 48, 63, 80 };
 
void coinChange()
{
    const long long inf = INT_MAX;
 
    // iterating till 81 * N
    // since N is at max 10^5
    for (int x = 1; x <= 8100005; x++) {
 
        value[x] = inf;
 
        for (auto c : coins) {
            if (x - c >= 0 && value[x - c] + 1 < value[x]) {
                value[x] = min(value[x], value[x - c] + 1);
 
                // least value of coin
                first[x] = c;
            }
        }
    }
}
 
// function to find the
// minimum possible value
string minValue(int n)
{
 
    // aplying coin change for all the numbers
    coinChange();
 
    string answer = "";
 
    // check if number is
    // perfect square or not
    if ((sqrt(n) * sqrt(n)) == n) {
        for (int i = 0; i < n; i++)
 
            answer += "1";
 
        return answer;
    }
 
    long long hi = 81 * n;
    long long lo = sqrt(n);
 
    // keeps a check whether
    // number is found or not
    bool found = false;
 
    long long upper = 81 * n;
    long long lower = n;
 
    // sotring suffix strings
    string suffix;
    bool suf_init = false;
 
    while ((lo * lo) <= hi) {
        lo++;
 
        long long curr = lo * lo;
 
        long long change = curr - n;
 
        if (value[change] <= lower) {
 
            // build a suffix string
            found = true;
 
            if (lower > value[change]) {
                // number to be used for updation of lower,
                // first values that will be used
                // to construct the final number later
                lower = value[change];
                upper = change;
                suffix = "";
                suf_init = true;
                int len = change;
 
                while (len > 0) {
                    int k = sqrt(first[len] + 1);
                    suffix = suffix + char(k + 48);
                    len = len - first[len];
                }
            }
 
            else if (lower == value[change]) {
                string tempsuf = "";
                int len = change;
                while (len > 0) {
                    int k = sqrt(first[len] + 1);
                    tempsuf = tempsuf + char(k + 48);
                    len = len - first[len];
                }
 
                if (tempsuf < suffix or suf_init == false) {
                    lower = value[change];
                    upper = change;
                    suffix = tempsuf;
                    suf_init = true;
                }
            }
        }
    }
    // check if number is found
    if (found) {
        // construct the number from first values
        long long x = lower;
        for (int i = 0; i < (n - x); i++)
            answer += "1";
 
        long long temp = upper;
 
        // fill in rest of the digits
        while (temp > 0) {
            int dig = sqrt(first[temp] + 1);
            temp = temp - first[temp];
            answer += char(dig + '0');
        }
        return answer;
    }
    else
        return "-1";
}
 
// driver code
int main()
{
 
    // initialise N
    int N = 2;
 
    cout << minValue(N);
 
    return 0;
}
输出:
34

时间复杂度: O(81 * N)