C ++中的唯一数字

时间:2012-01-29 20:50:04

标签: c++ performance algorithm math

我正在努力有效地列出1到100之间的数字。但是我必须摆脱相同数字的数字 示例:的 根据这个规则12是21的相同 13是31 14是41 所以for循环它不会超过相同的数字。
我正在考虑一些技巧,例如从1到100获取所有数字,然后删除当前数字的找到的排列。 我问这个的原因是因为像100000这样的大范围会失败。 另一个例子: 124等于142,241,214,412,421

12 个答案:

答案 0 :(得分:6)

您可以申请递归。这个函数的原型就像:

print_digits(int num_of_remaining_digits,int start_from_digit, int current_number);

编辑:为了完成,我在这里提出了我的解决方案(我认为它比Ben Voigt和提升输出订单具有更好的可读性

void print_digits(int num_of_remaining_digits,int start_from_digit, int current_number)
{
  if(num_of_remaining_digits == 0) 
  {
    std::cout << current_number << std::endl;
    return;
  }

  for(int i=start_from_digit;i<=9;i++)
  {
     print_digits(num_of_remaining_digits-1,i,10*current_number+i);
  }
}

这里是测试代码

http://ideone.com/Xm8Mv

这是如何运作的?

它是递归中的经典之一。首先是停止状态。然后是主循环。
主循环从start_from_digit开始,因为所有生成的数字都将以非递减顺序排列。例如,如果current_number15,则会调用print_digits whith

print_digits(num_of_remaining_digits-1,5,155)
print_digits(num_of_remaining_digits-1,6,156)
print_digits(num_of_remaining_digits-1,7,157)
print_digits(num_of_remaining_digits-1,8,158)
print_digits(num_of_remaining_digits-1,9,159)

在每次通话中,它会检查我们是否达到了结束白色num_of_remaining_digits,如果不是,则会使用start_from_digit

继续按current_number(第2个参数)推送的数字

答案 1 :(得分:3)

您正在寻找具有一定长度(100 = 2,1000 = 3)的某些字符(0..9)的组合。

看看Algorithm to return all combinations of k elements from n

答案 2 :(得分:1)

我会通过重载正确的操作符来编写适合您比较需求的类(从我的头顶开始,应该只有less)并使用std::set

答案 3 :(得分:1)

我会使用哈希表,类似这样的

1)从导出的数字中导出一个密钥,使得具有相同编号的数字具有相同的密钥(例如,对数字求和,因此“124”和“142”具有密钥7,或取得产品的数字(+1),所以“124”和“142”具有键30 - 必须为数字0的+1)

2)将数字放在由其键

索引的哈希表中

现在,关于您是否已经具有相同数字的数字的测试仅限于具有相同键的哈希表中的实体。该算法需要线性存储,其性能取决于您可以提供的密钥的好坏。

答案 4 :(得分:1)

首先,请注意您的规则排除了11的倍数。(为什么?)

首先生成所有2位数字,第一个数字= 1。

现在,生成所有2位数字,第一个数字= 2,但不生成任何与第一个数字中的数字匹配的数字。

重复3,但不要从前两个列表中生成任何数字。

观察到,对于任何2位数字ab,要使其符合资格,必须是a&lt; b,或者您已经生成了相应的数字ba。

在PASCAL中,仅仅因为我感觉不舒服:

var i:integer;  j:integer;
begin
  for i := 1 to 8 do
    for j := i+1 to 9 do
      println(i*10+j);
end;

稍后再添加

观察您要生成的数字将始终严格单调增加其数字。对于数量为2abc的资格,观察2&lt; a&lt; b&lt; C。 (示例:2539是2359的匹配,应该被拒绝。)

答案 5 :(得分:1)

#include <stdio.h>

size_t enum_canonical(char* begin, char* end, char min, char max)
{
    if (begin == end) {
        puts(begin);
        putchar('\n');
        return 1;
    }

    size_t result_count = 0;
    --end;
    for( *end = min; *end <= max; ++*end )
        result_count += enum_canonical(begin, end, min, *end);

    return result_count;
}

int main(void)
{
    char buff[7];
    printf("%d results\n", enum_canonical(buff, &(buff[6] = '\0'), '0', '9'));
}

演示:http://ideone.com/BWGdg

答案 6 :(得分:1)

让我们取1到1000.由于1000中有4位数字,我打印1为0001,因此0001,0010,0100,1000与我的算法相同。 0120,001,02010,0102,0201,0021也是相同的数字。

以下是该计划:

int main()
{
    int i=0, j=0, k=0;

    while(i<=9)
    {
        int unique=(i*100 + j*10 + k);
        printf("unique number : %3d\n", unique);

        if(j==9 && k==9)
        {
            i++;
            k=i;
            j=i;
        }
        else if(k==9)
        {
            j++;
            k=j;
        }
        else 
            k++;
    }

}

答案 7 :(得分:0)

似乎它可以像这样简单:

list = {}
for (j = 1 to 100)
     if (j is not excluded from list)
          list += j;

实际上,只有if条件很有趣:需要检查列表项的所有相关属性。

答案 8 :(得分:0)

创建一个接受字符串的函数,并返回一个字符串数组,其中包含该字符串中字符的所有可能排列。这并不难,但最简单的做法是递归。虽然说起来容易做起来难。

一旦你有了这个函数,并且它返回了数组,你只需要遍历数组并删除与数组中的一个共享一个公共数字的indecies。

答案 9 :(得分:0)

我会使用set来表示数字的数字排列:

std::vector<int> list_unwanted = digit_permutations(number);
std::unordered_set<int> set_unwanted(begin(list_unwanted), end(list_unwanted));

然后从0循环到极限,不会通过检查它们是否在集set_unwanted中添加不需要的数字:

std::vector<int> numbers;
numbers.reserve(limit - set_unwanted.count());

for (int i = 0; i < limit; ++i)
    if (!set_unwanted.count(i))

答案 10 :(得分:0)

如果你有一组数字,那么这个集合的任何排列都不是一个有效的解决方案,所以首先要建立一个函数来建立一组数字是否是另一个集合的排列。 要获得单个数字,您可以递归地除以10,直到得到零值。 如果你把所有的数字放在像[1,2,4]这样的数组中,检查antoher数组是否是一个排列(只有它们具有相同的长度才能检查)的antoher集:

bool permutation(int *a, int *b, int n) // n leading dimension
{
    bool result=true, vector[n]={false};
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n ;j++)
        {
            if(a[i]==b[j])
                vector[i]=false;
        }
    }
    for(int i=0;i<n && result;i++)
        result=(vector[i]==true);   // if vector[i] is false, result is false, is
                                    // not a permutation and the loop ends
    return result;
}

我没有测试过,但我认为它有效,否则请告诉我。 至于将所有数字放在一个数组中,我认为这很容易。 生成所有数字后,您会检查某个数字是否是已经采用的数字的排列。

答案 11 :(得分:0)

这是我的想法,因为每个值都将它的数字放在一个集合中。将该集合用作另一个集合的密钥,以跟踪已使用的数字。在我的例子中,我使用位字段作为数字的集合,即数字0由1表示,数字1由2表示(2乘以4,依此类推)。太累了解释,这是代码:

unsigned int get_digits(int v)
{
  unsigned int rv = 0;
  do
  {
    rv |= 1 << (v % 10);
    v /= 10;
  } while(v);
  return rv;
}

void unique_ints(int n)
{
  std::set<unsigned int> used_combinations;
  for(int i = 0; i < n; ++i)
  {
    const unsigned int d = get_digits(i);
    if(used_combinations.find(d) == used_combinations.end())
    {
      used_combinations.insert(d);
      // cout or some other way to store the value
      std::cout << i <<  std::endl;
    }
  }
}