【问题标题】:How to solve Permutation of a phone number problem如何解决电话号码排列问题
【发布时间】:2021-03-04 01:06:11
【问题描述】:

问题:

一家公司正在向其员工分发电话号码,以使事情变得更容易。下一个数字不能等于最后一个数字是唯一的规则,例如 0223 是不允许的,而 2023 是允许的。每次至少排除三位数字。编写一个函数,接收电话号码的长度和将被排除的数字。该函数应打印所有可能的电话号码。

我在一次采访中得到了这个问题,我以前在大学里也看到过这样的问题。这是一个排列问题。我的问题是在没有一百万个 for 循环的情况下解决这个问题的最佳方法或体面方法是什么。

我确实明白这在技术上是这样工作的

电话号码长度 = 3;

[0-9],[0-9]不包括最后一位,[0-9]不包括最后一位

但我不确定如何将其转换为代码的最佳方式。接受任何语言!

谢谢:

另外,我可能在错误的地方问这个问题。如果我是,请告诉我。

【问题讨论】:

  • 也许你可以写一个递归过程?你学会这个技巧了吗?
  • 我在面试中尝试了递归函数,但是我的大脑失败了。
  • 啊,对不起。但是,一种无需递归即可做到这一点的方法可能只涉及遍历从 0 到 10^(位数)- 1 的所有整数,并测试每个数字。例如,当电话号码的长度为 3 时,您可以从 0 迭代到 999,并注意每个号码如何对应一个唯一的 3 位电话号码序列(并且每个电话号码序列对应于其中一个 3 位数)。然后,只需测试每个单独的数字。
  • 我也是这样做的。我创建了一个变量来保存值 10^lengthOfNum 并且我做了 while(i
  • 在这种情况下,这种方法有什么问题吗?你有什么具体问题吗?

标签: c++ permutation


【解决方案1】:

解决此问题的一种简单方法是使用递归。这是我注释的 C++ 代码:

void solve(int depth, int size, vector <int> &curr_seq){

    // If the recursion depth is equal to size, that means we've decided size
    // numbers, which means that curr_seq.size() == size. In other words, we've
    // decided enough numbers at this point to create a complete phone number, so
    // we print it and return.

    if(depth == size){
        for(int item : curr_seq){
            cout << item;
        }
        cout << "\n";

        return;
    }

    // Try appending every possible digit to the current phone number
    for(int i = 0; i <= 9; ++i){

        // Make sure to only append the digit i if it is not equal to the last digit
        // of the phone number. We can also append it, however, if curr_seq
        // is empty (because that means that we haven't decided the 1st digit yet).
        if(curr_seq.empty() || curr[curr.size() - 1] != i){
            curr_seq.push_back(i);
            solve(depth + 1, size, curr);
            curr_seq.pop_back();
        }
    }
}

【讨论】:

  • 最初你会如何运行这个函数?只是一个空的arr?
  • 我知道了,深度是否像值所在的位置一样,如果它是 3 它会在 _ _ _
  • @devin 是的,这是正确的。 depth指的是solve()的递归深度,也就是说它也代表了我们此刻决定了多少个数字(curr_seq中有多少个数字)。
  • 我将其标记为正确答案,因为它确实有效,但我不确定 curr_seq 如何知道如何分隔每个数字。当程序到达 for 循环时,程序是如何逐步为我工作的。我会检查它是否为空,或者之前的数字是否与现在的数字不同。然后它将附加这个数字并将其推送到数组中,因此第一个将为 0。然后它将在下一个位置再次运行该函数,因此如果它的大小为 3,它将在十位。或在中间。这是令人困惑的地方。它会将 1 附加到 0,因此数组是 {0,1}
  • 我的问题@Telescope 是每次它再次运行相同的函数时都使用相同的向量,所以不应该是 0123456789 重复 3 次吗?它怎么知道在字符串的第三个数字处停止?
【解决方案2】:

我想我喜欢递归解决方案,但您也可以只生成所有排列达到限制(迭代),过滤掉任何重复数字,并打印成功的候选者:

#include <iomanip>
#include <iostream>
#include <sstream>

using namespace std;

// Because C/C++ still has no integer power function.
int ipow(int base, int exp) {
    int result = 1;
    for (;;) {
        if (exp & 1)
            result *= base;
        exp >>= 1;
        if (!exp)
            return result;
        base *= base;
    }
}

void noconsec(const int len) {
    int lim = ipow(10, len);

    // For e.g. len 4 (lim 10000),
    // obviously 00xx won't work, so skip anything smaller than lim / 100.
    int start = (len <= 2) ? 0 : (lim / 100);

    for (int num = start;num < lim;num++) {
        // Convert to string.
        std::stringstream ss;
        ss << std::setw(len) << std::setfill('0') << num;
        std::string num_s = ss.str();

        // Skip any consecutive digits.
        bool is_okay = true;
        auto prev_digit = num_s[0];
        for (int digit_idx = 1;digit_idx < num_s.length();digit_idx++) {
            auto digit = num_s[digit_idx];
            if (prev_digit == digit) {
                is_okay = false;
            }
            prev_digit = digit;
        }

        // Output result.
        if (is_okay) {
            cout << num_s << "\n";
        }
    }
}

int main(const int argc, const char * const argv[]) {
    noconsec(4);
}

需要注意的差异,这需要一个整数幂函数来计算极限。将 int 转换为字符串然后检查字符串比直接构造字符串更复杂。如果你已经有一个整数列表,我想这可能会很有用,但我这样做主要是为了好玩。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-28
    • 1970-01-01
    • 2011-09-21
    • 1970-01-01
    相关资源
    最近更新 更多