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

📅  最后修改于: 2021-09-17 07:24:00             🧑  作者: 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

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

动态规划解决方案:首先,如果我们能够计算到 R 所需的数字,即在 [0, R] 范围内,我们可以通过求解从零到 R 和然后将求解后得到的答案从 0 减去 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


Javascript


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 并调用 number / 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

蟒蛇3

# 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