📌  相关文章
📜  范围内的数字计数,其中第一个数字等于该数字的最后一个数字

📅  最后修改于: 2021-04-24 04:44:09             🧑  作者: Mango

给定一个由两个正整数L和R表示的范围。请在该范围的第一个数字等于最后一个数字的范围内找到数字的计数。

例子:

Input : L = 2, R = 60
Output : 13
Explanation : Required numbers are 
2, 3, 4, 5, 6, 7, 8, 9, 11, 22, 33, 44 and 55

Input : L = 1, R = 1000
Output : 108

先决条件:Digit DP
有两种方法可以解决此类问题,一种可以是组合解决方案,而另一种可以是基于动态编程的解决方案。下面是使用数字动态编程解决此问题的详细方法。

动态编程解决方案:首先,如果我们能够计算直到R的所需数字,即在[0,R]范围内,则可以通过求解从零到R的值,轻松地在[L,R]范围内得出答案。然后减去求解后得到的答案,从零到L –1。现在,我们需要定义DP状态。

DP州

  • 既然我们可以考虑我们的号码作为数字序列,一个状态是,我们目前的位置,这个位置可以有值从0到18,如果我们用数字处理高达10 18。在每个递归调用中,我们尝试通过从0到9放置一个数字来从左到右构建序列。
  • 第二个状态是firstD ,它定义了我们要构建的数字的第一个数字,其值可以从0到9。
  • 第三个状态是lastD ,它定义了我们要构建的数字的最后一位,其值可以从0到9。
  • 另一个状态是布尔变量tight ,它指示我们要构建的数字已经小于R,因此在接下来的递归调用中,我们可以将0到9之间的任何数字放置。如果数字没有变小,则为最大限制我们可以放置的位数是R中当前位置的位数。

在每个递归调用中,我们将最后一位数字设置为放置在最后位置的数字,然后将第一位数字设置为该数字的第一个非零数字。在最后的递归调用中,如果我们位于最后一个位置(如果第一个数字等于最后一个数字),则返回1,否则返回0。

下面是上述方法的实现。

C++
// C++ Program to find the count of
// numbers in a range where the number
// does not contain more than K non
// zero digits
 
#include 
 
using namespace std;
 
const int M = 20;
 
// states - position, first digit,
// last digit, tight
int dp[M][M][M][2];
 
// This function returns the count of
// required numbers from 0 to num
int count(int pos, int firstD, int lastD,
        int tight, vector num)
{
    // Last position
    if (pos == num.size()) {
 
        // If first digit is equal to
        // last digit
        if (firstD == lastD)
            return 1;
        return 0;
    }
 
    // If this result is already computed
    // simply return it
    if (dp[pos][firstD][lastD][tight] != -1)
        return dp[pos][firstD][lastD][tight];
 
    int ans = 0;
 
    // Maximum limit upto which we can place
    // digit. If tight is 1, means number has
    // already become smaller so we can place
    // any digit, otherwise num[pos]
    int limit = (tight ? 9 : num[pos]);
 
    for (int dig = 0; dig <= limit; dig++) {
        int currFirst = firstD;
 
        // If the position is 0, current
        // digit can be first digit
        if (pos == 0)
            currFirst = dig;
 
        // In current call, if the first
        // digit is zero and current digit
        // is nonzero, update currFirst
        if (!currFirst && dig)
            currFirst = dig;
 
        int currTight = tight;
 
        // At this position, number becomes
        // smaller
        if (dig < num[pos])
            currTight = 1;
 
        // Next recursive call, set last
        // digit as dig
        ans += count(pos + 1, currFirst,
                    dig, currTight, num);
    }
    return dp[pos][firstD][lastD][tight] = ans;
}
 
// This function converts a number into its
// digit vector and uses above function to compute
// the answer
int solve(int x)
{
    vector num;
    while (x) {
        num.push_back(x % 10);
        x /= 10;
    }
    reverse(num.begin(), num.end());
 
    // Initialize dp
    memset(dp, -1, sizeof(dp));
    return count(0, 0, 0, 0, num);
}
 
// Driver Code
int main()
{
    int L = 2, R = 60;
    cout << solve(R) - solve(L - 1) << endl;
 
    L = 1, R = 1000;
    cout << solve(R) - solve(L - 1) << endl;
     
    return 0;
}


Java
// Java program to find the count of
// numbers in a range where the number
// does not contain more than K non
// zero digits
import java.util.Collections;
import java.util.Vector;
 
class GFG
{
    static int M = 20;
 
    // states - position, first digit,
    // last digit, tight
    static int[][][][] dp = new int[M][M][M][2];
 
    // This function returns the count of
    // required numbers from 0 to num
    static int count(int pos, int firstD,
                     int lastD, int tight,
                     Vector num)
    {
 
        // Last position
        if (pos == num.size())
        {
 
            // If first digit is equal to
            // last digit
            if (firstD == lastD)
                return 1;
            return 0;
        }
 
        // If this result is already computed
        // simply return it
        if (dp[pos][firstD][lastD][tight] != -1)
            return dp[pos][firstD][lastD][tight];
        int ans = 0;
 
        // Maximum limit upto which we can place
        // digit. If tight is 1, means number has
        // already become smaller so we can place
        // any digit, otherwise num[pos]
        int limit = (tight == 1 ? 9 : num.elementAt(pos));
 
        for (int dig = 0; dig <= limit; dig++)
        {
            int currFirst = firstD;
 
            // If the position is 0, current
            // digit can be first digit
            if (pos == 0)
                currFirst = dig;
 
            // In current call, if the first
            // digit is zero and current digit
            // is nonzero, update currFirst
            if (currFirst == 0 && dig != 0)
                currFirst = dig;
 
            int currTight = tight;
 
            // At this position, number becomes
            // smaller
            if (dig < num.elementAt(pos))
                currTight = 1;
 
            // Next recursive call, set last
            // digit as dig
            ans += count(pos + 1, currFirst,
                         dig, currTight, num);
        }
        return dp[pos][firstD][lastD][tight] = ans;
    }
 
    // This function converts a number into its
    // digit vector and uses above function to
    // compute the answer
    static int solve(int x)
    {
        Vector num = new Vector<>();
        while (x > 0)
        {
            num.add(x % 10);
            x /= 10;
        }
 
        Collections.reverse(num);
 
        // Initialize dp
        for (int i = 0; i < M; i++)
            for (int j = 0; j < M; j++)
                for (int k = 0; k < M; k++)
                    for (int l = 0; l < 2; l++)
                        dp[i][j][k][l] = -1;
 
        return count(0, 0, 0, 0, num);
    }
 
    // Driver Code
    public static void main(String[] args)
    {
        int L = 2, R = 60;
        System.out.println(solve(R) - solve(L - 1));
 
        L = 1;
        R = 1000;
        System.out.println(solve(R) - solve(L - 1));
    }
}
 
// This code is contributed by
// sanjeev2552


Python3
# Python3 code for above approach
 
# Returns the count of numbers in range
# if the first digit is equal to last digit of number
def count(l, r):
    cnt = 0       # Initialize counter
    for i in range(l, r):
         
        # If number is less than 10
        # then increment counter
        # as number has only one digit
        if(i < 10):    
            cnt += 1
             
        else:
            n = i % 10     # Find the last digit
            k = i
 
            # Find the first digit
            while(k >= 10):
                k = k // 10
 
            # If first digit equals last digit
            # then increment counter
            if(n == k):
                cnt += 1
                 
    return(cnt)     # Return the count
 
# Driver Code
L = 2; R = 60;
print(count(L, R))
 
L = 1; R = 1000;
print(count(L, R))
 
# This code is contributed by Raj


C#
// C# program to find the count of
// numbers in a range where the number
// does not contain more than K non
// zero digits
using System;
using System.Collections.Generic;            
     
class GFG
{
    static int M = 20;
 
    // states - position, first digit,
    // last digit, tight
    static int[,,,] dp = new int[M, M, M, 2];
 
    // This function returns the count of
    // required numbers from 0 to num
    static int count(int pos, int firstD,
                     int lastD, int tight,
                     List num)
    {
 
        // Last position
        if (pos == num.Count)
        {
 
            // If first digit is equal to
            // last digit
            if (firstD == lastD)
                return 1;
            return 0;
        }
 
        // If this result is already computed
        // simply return it
        if (dp[pos, firstD, lastD, tight] != -1)
            return dp[pos, firstD, lastD, tight];
        int ans = 0;
 
        // Maximum limit upto which we can place
        // digit. If tight is 1, means number has
        // already become smaller so we can place
        // any digit, otherwise num[pos]
        int limit = (tight == 1 ? 9 : num[pos]);
 
        for (int dig = 0; dig <= limit; dig++)
        {
            int currFirst = firstD;
 
            // If the position is 0, current
            // digit can be first digit
            if (pos == 0)
                currFirst = dig;
 
            // In current call, if the first
            // digit is zero and current digit
            // is nonzero, update currFirst
            if (currFirst == 0 && dig != 0)
                currFirst = dig;
 
            int currTight = tight;
 
            // At this position, number becomes
            // smaller
            if (dig < num[pos])
                currTight = 1;
 
            // Next recursive call, set last
            // digit as dig
            ans += count(pos + 1, currFirst,
                         dig, currTight, num);
        }
        return dp[pos, firstD, lastD, tight] = ans;
    }
 
    // This function converts a number into its
    // digit vector and uses above function to
    // compute the answer
    static int solve(int x)
    {
        List num = new List();
        while (x > 0)
        {
            num.Add(x % 10);
            x /= 10;
        }
 
        num.Reverse();
 
        // Initialize dp
        for (int i = 0; i < M; i++)
            for (int j = 0; j < M; j++)
                for (int k = 0; k < M; k++)
                    for (int l = 0; l < 2; l++)
                        dp[i, j, k, l] = -1;
 
        return count(0, 0, 0, 0, num);
    }
 
    // Driver Code
    public static void Main(String[] args)
    {
        int L = 2, R = 60;
        Console.WriteLine(solve(R) - solve(L - 1));
 
        L = 1;
        R = 1000;
        Console.WriteLine(solve(R) - solve(L - 1));
    }
}
 
// This code is contributed by 29AjayKumar


C++
// C++ program to implement
// the above approach
#include 
using namespace std;
 
int solve(int x)
{
 
    int ans = 0, first, last, temp = x;
 
    // Base Case
 
    if (x < 10)
        return x;
 
    // Calculating the last digit
    last = x % 10;
 
    // Calculating the first digit
    while (x) {
        first = x % 10;
        x /= 10;
    }
 
    if (first <= last)
        ans = 9 + temp / 10;
    else
        ans = 8 + temp / 10;
 
    return ans;
}
 
// Drivers Code
int main()
{
 
    int L = 2, R = 60;
    cout << solve(R) - solve(L - 1) << endl;
 
    L = 1, R = 1000;
    cout << solve(R) - solve(L - 1) << endl;
 
    return 0;
}


Java
// Java program to implement
// the above approach
class GFG{
    
public static int solve(int x)
{
  int ans = 0, first = 0,
      last, temp = x;
 
  // Base Case
  if (x < 10)
    return x;
 
  // Calculating the
  // last digit
  last = x % 10;
 
  // Calculating the
  // first digit
  while (x != 0)
  {
    first = x % 10;
    x /= 10;
  }
 
  if (first <= last)
    ans = 9 + temp / 10;
  else
    ans = 8 + temp / 10;
 
  return ans;
}
     
// Driver code
public static void main(String[] args)
{
  int L = 2, R = 60;
  System.out.println(solve(R) -
                     solve(L - 1));
 
  L = 1; R = 1000;
  System.out.println(solve(R) -
                     solve(L - 1));
}
}
 
// This code is contributed by divyeshrabadiya07


Python3
# Python3 program to implement
# the above approach
def solve(x):
 
    ans, temp = 0, x
     
    # Base Case
    if (x < 10):
        return x
 
    # Calculating the last digit
    last = x % 10
 
    # Calculating the first digit
    while (x):
        first = x % 10
        x = x // 10
 
    if (first <= last):
        ans = 9 + temp // 10
    else:
        ans = 8 + temp // 10
 
    return ans
 
# Driver Code
L, R = 2, 60
print(solve(R) - solve(L - 1))
 
L, R = 1, 1000
print(solve(R) - solve(L - 1))
 
# This code is contributed by divyesh072019


C#
// C# program to implement
// the above approach
using System;
 
class GFG{
     
public static int solve(int x)
{
    int ans = 0, first = 0,
        last, temp = x;
         
    // Base Case
    if (x < 10)
        return x;
     
    // Calculating the
    // last digit
    last = x % 10;
     
    // Calculating the
    // first digit
    while (x != 0)
    {
        first = x % 10;
        x /= 10;
    }
     
    if (first <= last)
        ans = 9 + temp / 10;
    else
        ans = 8 + temp / 10;
     
    return ans;
}
     
// Driver code
public static void Main(String[] args)
{
    int L = 2, R = 60;
    Console.WriteLine(solve(R) -
                      solve(L - 1));
     
    L = 1; R = 1000;
    Console.WriteLine(solve(R) -
                      solve(L - 1));
}
}
 
// This code is contributed by shivanisinghss2110


Javascript


输出
13
108

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

替代方法:

我们也可以通过递归来解决这个问题,对于每个位置,我们可以填充除给定位置的第一个和最后一个位置以外的任何满足给定条件的数字,因为它们将配对在一起,为此,我们将使用递归,并且在每次调用中都只需检查一下如果第一个数字小于或大于最后一个数字(如果结果大于),我们将加8否则为9并要求数字/ 10,一旦该数字小于第一个10且最后一个数字相同,则返回数字本身。

下面是上述方法的实现

C++

// C++ program to implement
// the above approach
#include 
using namespace std;
 
int solve(int x)
{
 
    int ans = 0, first, last, temp = x;
 
    // Base Case
 
    if (x < 10)
        return x;
 
    // Calculating the last digit
    last = x % 10;
 
    // Calculating the first digit
    while (x) {
        first = x % 10;
        x /= 10;
    }
 
    if (first <= last)
        ans = 9 + temp / 10;
    else
        ans = 8 + temp / 10;
 
    return ans;
}
 
// Drivers Code
int main()
{
 
    int L = 2, R = 60;
    cout << solve(R) - solve(L - 1) << endl;
 
    L = 1, R = 1000;
    cout << solve(R) - solve(L - 1) << endl;
 
    return 0;
}

Java

// Java program to implement
// the above approach
class GFG{
    
public static int solve(int x)
{
  int ans = 0, first = 0,
      last, temp = x;
 
  // Base Case
  if (x < 10)
    return x;
 
  // Calculating the
  // last digit
  last = x % 10;
 
  // Calculating the
  // first digit
  while (x != 0)
  {
    first = x % 10;
    x /= 10;
  }
 
  if (first <= last)
    ans = 9 + temp / 10;
  else
    ans = 8 + temp / 10;
 
  return ans;
}
     
// Driver code
public static void main(String[] args)
{
  int L = 2, R = 60;
  System.out.println(solve(R) -
                     solve(L - 1));
 
  L = 1; R = 1000;
  System.out.println(solve(R) -
                     solve(L - 1));
}
}
 
// This code is contributed by divyeshrabadiya07

Python3

# Python3 program to implement
# the above approach
def solve(x):
 
    ans, temp = 0, x
     
    # Base Case
    if (x < 10):
        return x
 
    # Calculating the last digit
    last = x % 10
 
    # Calculating the first digit
    while (x):
        first = x % 10
        x = x // 10
 
    if (first <= last):
        ans = 9 + temp // 10
    else:
        ans = 8 + temp // 10
 
    return ans
 
# Driver Code
L, R = 2, 60
print(solve(R) - solve(L - 1))
 
L, R = 1, 1000
print(solve(R) - solve(L - 1))
 
# This code is contributed by divyesh072019

C#

// C# program to implement
// the above approach
using System;
 
class GFG{
     
public static int solve(int x)
{
    int ans = 0, first = 0,
        last, temp = x;
         
    // Base Case
    if (x < 10)
        return x;
     
    // Calculating the
    // last digit
    last = x % 10;
     
    // Calculating the
    // first digit
    while (x != 0)
    {
        first = x % 10;
        x /= 10;
    }
     
    if (first <= last)
        ans = 9 + temp / 10;
    else
        ans = 8 + temp / 10;
     
    return ans;
}
     
// Driver code
public static void Main(String[] args)
{
    int L = 2, R = 60;
    Console.WriteLine(solve(R) -
                      solve(L - 1));
     
    L = 1; R = 1000;
    Console.WriteLine(solve(R) -
                      solve(L - 1));
}
}
 
// This code is contributed by shivanisinghss2110

Java脚本


输出
13
108