📌  相关文章
📜  在具有最大位数的范围内找到数字

📅  最后修改于: 2021-04-22 03:08:14             🧑  作者: Mango

给定一个由两个正整数L和R表示的范围。找到该范围内具有数字最大乘积的数字。
例子:

Input : L = 1, R = 10
Output : 9

Input : L = 51, R = 62
Output : 59

方法:此处的关键思想是从最高有效数字开始对数字R的数字进行迭代。从左到右,即从最高有效数字到最低有效数字,用比当前数字少一位代替当前数字,并将数字中当前数字之后的所有数字替换为9,因为数字已经小于R在当前位置,因此我们可以安全地在以下数字中放置任何数字,以最大程度地增加数字乘积。另外,检查结果数是否大于L以保持在该范围内并更新最大乘积。
下面是上述方法的实现:

C++
// CPP Program to find the number in a
// range having maximum product of the
// digits
 
#include 
using namespace std;
 
// Returns the product of digits of number x
int product(int x)
{
    int prod = 1;
    while (x) {
        prod *= (x % 10);
        x /= 10;
    }
    return prod;
}
 
// This function returns the number having
// maximum product of the digits
int findNumber(int l, int r)
{
    // Converting both integers to strings
    string a = to_string(l);
    string b = to_string(r);
 
    // Let the current answer be r
    int ans = r;
    for (int i = 0; i < b.size(); i++) {
        if (b[i] == '0')
            continue;
 
        // Stores the current number having
        // current digit one less than current
        // digit in b
        string curr = b;
        curr[i] = ((curr[i] - '0') - 1) + '0';
 
        // Replace all following digits with 9
        // to maximise the product
        for (int j = i + 1; j < curr.size(); j++)
            curr[j] = '9';
 
        // Convert string to number
        int num = 0;
        for (auto c : curr)
            num = num * 10 + (c - '0');
 
        // Check if it lies in range and its product
        // is greater than max product
        if (num >= l && product(ans) < product(num))
            ans = num;
    }
 
    return ans;
}
 
// Driver Code
int main()
{
    int l = 1, r = 10;
    cout << findNumber(l, r) << endl;
 
    l = 51, r = 62;
    cout << findNumber(l, r) << endl;
 
    return 0;
}


Java
// Java Program to find the number in a
// range having maximum product of the
// digits
 
class GFG
{
     
// Returns the product of digits of number x
static int product(int x)
{
    int prod = 1;
    while (x > 0)
    {
        prod *= (x % 10);
        x /= 10;
    }
    return prod;
}
 
// This function returns the number having
// maximum product of the digits
static int findNumber(int l, int r)
{
    // Converting both integers to strings
    //string a = l.ToString();
    String b = Integer.toString(r);
 
    // Let the current answer be r
    int ans = r;
    for (int i = 0; i < b.length(); i++)
    {
        if (b.charAt(i) == '0')
            continue;
 
        // Stores the current number having
        // current digit one less than current
        // digit in b
        char[] curr = b.toCharArray();
        curr[i] = (char)(((int)(curr[i] -
                    (int)'0') - 1) + (int)('0'));
 
        // Replace all following digits with 9
        // to maximise the product
        for (int j = i + 1; j < curr.length; j++)
            curr[j] = '9';
 
        // Convert string to number
        int num = 0;
        for (int j = 0; j < curr.length; j++)
            num = num * 10 + (curr[j] - '0');
 
        // Check if it lies in range and its product
        // is greater than max product
        if (num >= l && product(ans) < product(num))
            ans = num;
    }
 
    return ans;
}
 
// Driver Code
public static void main (String[] args)
{
    int l = 1, r = 10;
    System.out.println(findNumber(l, r));
 
    l = 51;
    r = 62;
    System.out.println(findNumber(l, r));
}
}
 
// This code is contributed by chandan_jnu


Python3
# Python3 Program to find the number
# in a range having maximum product
# of the digits
 
# Returns the product of digits
# of number x
def product(x) :
     
    prod = 1
    while (x) :
        prod *= (x % 10)
        x //= 10;
     
    return prod
 
# This function returns the number having
# maximum product of the digits
def findNumber(l, r) :
     
    # Converting both integers to strings
    a = str(l);
    b = str(r);
 
    # Let the current answer be r
    ans = r
     
    for i in range(len(b)) :
        if (b[i] == '0') :
            continue
 
        # Stores the current number having
        # current digit one less than current
        # digit in b
        curr = list(b)
        curr[i] = str(((ord(curr[i]) -
                        ord('0')) - 1) + ord('0'))
 
        # Replace all following digits with 9
        # to maximise the product
        for j in range(i + 1, len(curr)) :
            curr[j] = str(ord('9'))
             
        # Convert string to number
        num = 0
        for c in curr :
            num = num * 10 + (int(c) - ord('0'))
 
        # Check if it lies in range and its
        # product is greater than max product
        if (num >= l and product(ans) < product(num)) :
            ans = num
 
    return ans
 
# Driver Code
if __name__ == "__main__" :
     
    l, r = 1, 10
    print(findNumber(l, r))
 
    l, r = 51, 62
    print(findNumber(l, r))
 
# This code is contributed by Ryuga


C#
// C# Program to find the number in a
// range having maximum product of the
// digits
using System;
 
class GFG
{
     
// Returns the product of digits of number x
static int product(int x)
{
    int prod = 1;
    while (x > 0)
    {
        prod *= (x % 10);
        x /= 10;
    }
    return prod;
}
 
// This function returns the number having
// maximum product of the digits
static int findNumber(int l, int r)
{
    // Converting both integers to strings
    //string a = l.ToString();
    string b = r.ToString();
 
    // Let the current answer be r
    int ans = r;
    for (int i = 0; i < b.Length; i++)
    {
        if (b[i] == '0')
            continue;
 
        // Stores the current number having
        // current digit one less than current
        // digit in b
        char[] curr = b.ToCharArray();
        curr[i] = (char)(((int)(curr[i] -
                    (int)'0') - 1) + (int)('0'));
 
        // Replace all following digits with 9
        // to maximise the product
        for (int j = i + 1; j < curr.Length; j++)
            curr[j] = '9';
 
        // Convert string to number
        int num = 0;
        for (int j = 0; j < curr.Length; j++)
            num = num * 10 + (curr[j] - '0');
 
        // Check if it lies in range and its product
        // is greater than max product
        if (num >= l && product(ans) < product(num))
            ans = num;
    }
 
    return ans;
}
 
// Driver Code
static void Main()
{
    int l = 1, r = 10;
    Console.WriteLine(findNumber(l, r));
 
    l = 51;
    r = 62;
    Console.WriteLine(findNumber(l, r));
}
}
 
// This code is contributed by chandan_jnu


PHP
= $l and
            product($ans) < product($num))
            $ans = $num;
    }
 
    return $ans;
}
 
// Driver Code
$l = 1;
$r = 10;
print(findNumber($l, $r) . "\n");
 
$l = 51;
$r = 62;
print(findNumber($l, $r));
 
// This code is contributed
// by chandan_jnu
?>


C++
// CPP program for the above approach
#include 
using namespace std;
#define int long long int
 
// pair of array to store product and number
// dp[pos][tight1][tight2][start]
pair dp[20][2][2][2];
 
pair recur(string l, string r, int pos, int ta,
                        int tb, int st)
{
 
    // Base case if pos is equal
    // to l or r size return
    // pair{1,""}
    if (pos == l.size()) {
        return { 1, "" };
    }
 
    // look up condition
    if (dp[pos][ta][tb][st].first != -1)
        return dp[pos][ta][tb][st];
 
    // Lower bound condition
    int start = ta ? l[pos] - '0' : 0;
 
    // Upper bound condition
    int end = tb ? r[pos] - '0' : 9;
 
    // To store the maximum product
    // initially its is set to -1
    int ans = -1;
 
    // To store the corresponding
    // number as number is large
    // so store it as a string
    string s = "";
 
    for (int i = start; i <= end; i++) {
 
        // Multiply with this val
        int val = i;
 
        // check for leading zeroes as 00005
        if (st == 0 and i == 0) {
 
            val = 1;
        }
 
        // Recursive call for next
        // position and store it in
        // a pair pair first gives
        // maximum product pair
        // second gives number which
        // gave maximum product
        pair temp
 
            = recur(l, r, pos + 1, ta & (i == start),
 
                    tb & (i == end), st | i > 0);
 
        // check if calculated product is greater than
        // previous calculated ans
        if (temp.first * val > ans) {
 
            ans = temp.first * val;
 
            // update string only if no leading zeroes
            // becoz no use to append the leading zeroes
            if (i == 0 and st == 0) {
 
                s = temp.second;
            }
 
            else {
 
                s = temp.second;
 
                s.push_back('0' + i);
            }
        }
    }
 
    // while returning memoize the ans
    return dp[pos][ta][tb][st] = { ans, s };
}
 
pair solve(int a, int b)
 
{
 
    // convert int l to sting L and int r to string R ,
    // as integer value should be large
    string L = to_string(a);
 
    string R = to_string(b);
 
    // to make the size of strings
    // equal append zeroes in
    // front of string L
    if (L.size() < R.size()) {
 
        reverse(L.begin(), L.end());
 
        while (L.size() < R.size()) {
 
            L.push_back('0');
        }
 
        reverse(L.begin(), L.end());
    }
 
    // initialize dp
    // as it is pair of array so memset will not work
    for (int i = 0; i < 20; i++) {
 
        for (int j = 0; j < 2; j++) {
 
            for (int k = 0; k < 2; k++) {
 
                for (int l = 0; l < 2; l++) {
 
                    dp[i][j][k][l].first = -1;
                }
            }
        }
    }
 
    // as we have to return pair second value
    // it's that number which gaves mximum product
    // initally pos=0,ta=1,tb=1,start=0(becoz number is not
    // started yet)
 
    pair ans = recur(L, R, 0, 1, 1, 0);
 
    // reverse it becoz we were appending from right to left
    // in recursive call
    reverse(ans.second.begin(), ans.second.end());
 
    return { ans.first, ans.second };
}
 
signed main()
 
{
 
    // take l and r as input
 
    int l = 52, r = 62;
    cout << "l= " << l << "\n";
    cout << "r= " << r << "\n";
    pair ans = solve(l, r);
    cout << "Maximum Product: " << ans.first << "\n";
    cout << "Number which gave maximum product: "
         << ans.second;
 
    return 0;
}


输出:
9
59

时间复杂度:O(18 * 18),如果我们要处理的数字最大为10 18

另一种方法:可以使用Digit Dp解决

观察要点:

1.据我们所知,我们使用紧缩数字dp来检查该数字的范围是否受到限制,同样,在这里,我们将使用紧缩ta紧缩tb (基本上是两个紧缩条件),其中ta会告诉我们

数字和tb的lower_bound会告诉我们数字的upper_bound ,使用两个紧密值的原因是我们必须计算最大乘积,可能是这样的:

max(l,r)≠max(r)– max(l-1) ,我们的整数应在从l到r的范围内。

2.假设范围值分别为l = 5和r = 15,因此要使大小相等,我们应在转换为字符串后在数字前附加零,并在计算答案时注意前导零,

Dp状态包括:-

1)位置

  • 它会从整数的左方告诉索引的位置

2)

  • 它代表数字的下界,我们必须确保数字应大于或等于{l}
  • 假设我们正在构建一个大于0055的数字,并且创建了一个类似于005的序列,那么在第4位,我们不能放置小于5的数字,而该数字只能介于5到9之间。因此,进行检查这个界限,我们需要ta。
Example : Consider the value of  l = 005
Index   : 0 1 2
digits  : 0 0 5
valid numbers like: 005,006,007,008...
invalid numbers like: ...001,002,003,004

3)待定

  • 数字的上限,我们必须确保数字应小于或等于{r}
  • 再次假设我们正在构建一个小于526的数字,并且创建了一个类似52的序列,因此在第3位,我们不能放置大于6的数字,而只能在0到6之间放置。检查这个界限,我们需要TB
Example : Consider the value of  r = 150
Index   : 0 1 2
digits  : 1 5 0
valid numbers like: ...148,149,150
invalid numbers like: 151,152,153...

4)圣

  • 用于检查前导零(从005〜5)

3.约束:l和r(1≤l≤r≤10 ^ 18)

算法:

  • 我们将根据紧缩ta紧缩tb从头到尾遍历i,如下所示:
start = ta == 1 ? l[ pos ] - '0' : 0;
end = tb ==1 ? r[ pos ] -'0'  : 9;
  • 首先,我们将检查前导零为:
if ( st == 0 and i = 0) then multiply with 1,else multiply with i
  • 对于每个位置,我们将计算序列的乘积并检查是否为最大乘积,并存储相应的数字
int ans = 0;
for(int i = start; i <= end; i++){
  int val = i;
  if (st==0 and i==0) val = 1;
  ans = max (ans, val * solve (pos+1, ta&(i==start),tb&(i==end) ,st|i>0);
}

C++实现:

C++

// CPP program for the above approach
#include 
using namespace std;
#define int long long int
 
// pair of array to store product and number
// dp[pos][tight1][tight2][start]
pair dp[20][2][2][2];
 
pair recur(string l, string r, int pos, int ta,
                        int tb, int st)
{
 
    // Base case if pos is equal
    // to l or r size return
    // pair{1,""}
    if (pos == l.size()) {
        return { 1, "" };
    }
 
    // look up condition
    if (dp[pos][ta][tb][st].first != -1)
        return dp[pos][ta][tb][st];
 
    // Lower bound condition
    int start = ta ? l[pos] - '0' : 0;
 
    // Upper bound condition
    int end = tb ? r[pos] - '0' : 9;
 
    // To store the maximum product
    // initially its is set to -1
    int ans = -1;
 
    // To store the corresponding
    // number as number is large
    // so store it as a string
    string s = "";
 
    for (int i = start; i <= end; i++) {
 
        // Multiply with this val
        int val = i;
 
        // check for leading zeroes as 00005
        if (st == 0 and i == 0) {
 
            val = 1;
        }
 
        // Recursive call for next
        // position and store it in
        // a pair pair first gives
        // maximum product pair
        // second gives number which
        // gave maximum product
        pair temp
 
            = recur(l, r, pos + 1, ta & (i == start),
 
                    tb & (i == end), st | i > 0);
 
        // check if calculated product is greater than
        // previous calculated ans
        if (temp.first * val > ans) {
 
            ans = temp.first * val;
 
            // update string only if no leading zeroes
            // becoz no use to append the leading zeroes
            if (i == 0 and st == 0) {
 
                s = temp.second;
            }
 
            else {
 
                s = temp.second;
 
                s.push_back('0' + i);
            }
        }
    }
 
    // while returning memoize the ans
    return dp[pos][ta][tb][st] = { ans, s };
}
 
pair solve(int a, int b)
 
{
 
    // convert int l to sting L and int r to string R ,
    // as integer value should be large
    string L = to_string(a);
 
    string R = to_string(b);
 
    // to make the size of strings
    // equal append zeroes in
    // front of string L
    if (L.size() < R.size()) {
 
        reverse(L.begin(), L.end());
 
        while (L.size() < R.size()) {
 
            L.push_back('0');
        }
 
        reverse(L.begin(), L.end());
    }
 
    // initialize dp
    // as it is pair of array so memset will not work
    for (int i = 0; i < 20; i++) {
 
        for (int j = 0; j < 2; j++) {
 
            for (int k = 0; k < 2; k++) {
 
                for (int l = 0; l < 2; l++) {
 
                    dp[i][j][k][l].first = -1;
                }
            }
        }
    }
 
    // as we have to return pair second value
    // it's that number which gaves mximum product
    // initally pos=0,ta=1,tb=1,start=0(becoz number is not
    // started yet)
 
    pair ans = recur(L, R, 0, 1, 1, 0);
 
    // reverse it becoz we were appending from right to left
    // in recursive call
    reverse(ans.second.begin(), ans.second.end());
 
    return { ans.first, ans.second };
}
 
signed main()
 
{
 
    // take l and r as input
 
    int l = 52, r = 62;
    cout << "l= " << l << "\n";
    cout << "r= " << r << "\n";
    pair ans = solve(l, r);
    cout << "Maximum Product: " << ans.first << "\n";
    cout << "Number which gave maximum product: "
         << ans.second;
 
    return 0;
}
输出
l= 52
r= 62
Maximum Product: 45
Number which gave maximum product: 59