从整数中查找重复元素

Find the duplicate element from an integer

本文关键字:元素 查找 整数      更新时间:2023-10-16

上周我参加了面试。他们问了一个在整数值中寻找重复元素的问题。我知道程序使用数组,但他们要求我不用数组。请帮我在没有数组的整数中找到重复的元素。

问题:

从整数中查找重复的元素,显示没有重复编号的元素。如I/P:43456 O/P:4356。条件:不使用数组

编码:

void printRepeating(int arr[], int size) {
    int i;
    printf("The repeating elements are: n");
    for (i = 0; i < size; i++) {
        if (arr[abs(arr[i])] >= 0)
            arr[abs(arr[i])] = -arr[abs(arr[i])]; elseprintf(" %d ", abs(arr[i]));
    }
}
int main() {
    int arr[] = { 1, 2, 3, 1, 3, 6, 6 };
    int arr_size = sizeof(arr) / sizeof(arr[0]);
    printRepeating(arr, arr_size);
    getchar();
    return 0;
}

我实际上理解这个问题的意思是应该给出一个整数,而不是整数数组作为输入:

他们问了一个在整数值中查找重复元素的问题。

这里有一个解决这个问题的方法。在我最初的解中,主函数是递归的。这个函数似乎可以工作,但是我误解了这个问题要求首先从低阶数字中取出重复的数字。我的递归解先去除了高阶数字。这意味着对于提供的样本输入,43456求值为3456,而不是期望的4356

我重新设计了remove_dups()函数来满足这个要求。它不再是递归的。该函数通过使用输入的数字,除去重复项后,取最高阶数字并将其与剩余数字中的最高阶数字组合,从而构建一个新数字。

使用了三个辅助函数。remove_digits()函数用于从一个数字中删除所有出现的数字。get_place()remove_place()函数用于在给定的位置上获取一个数字,其中一个位置用1,10,100,…

下面是get_place()函数如何工作的一个例子:

get_place(1234, 100) --> (1234 % (10 * 100) - 1234 % 100) / 100
                     --> (1234 % 1000 - 1234 % 100) / 100
                     --> (234 - 34) / 100
                     --> 200 / 100
                     --> 2

remove_place()函数如何工作的一个例子:

remove_place(1234, 100) --> (1234 / (10 * 100)) * 100 + 1234 % 100
                        --> (1234 / 1000) * 100 + 34
                        --> 1 * 100 + 34
                        --> 100 + 34
                        --> 134
<标题> 更新

我最初发布的代码不处理负数。这是因为当我最初用负数测试时,结果是不正确的。在这个破碎的版本中,我在函数中使用了long值,除了plc参数,它们是unsigned long。我错误地认为这个问题与模数运算符有关,只是将所有内容更改为unsigned。将想要的负数转换为正数,然后将结果乘以-1,似乎很简单。下面是原始代码的函数原型:

long get_place(long num, unsigned long plc);
long remove_place(long num, unsigned long plc);
long remove_digits(long num, long d);
long remove_dups(long num);

但进一步考虑发现,原来的问题是unsigned long值不能转换为long值,因为有unsigned long值不能表示为long值。这导致了get_place()remove_place()函数中的一些垃圾结果。将所有内容更改为unsigned long解决了这个问题,代价是排除负输入值。但是,随着对问题的更好理解,我将所有函数参数和返回值更改为类型long。这解决了这个问题,并允许正确处理负输入值。

代码如下:

#include <stdio.h>
long get_place(long num, long plc);
long remove_place(long num, long plc);
long remove_digits(long num, long d);
long remove_dups(long num);
int main(void)
{
    long number;
    printf("Enter a number (q to quit): ");
    while (scanf("%ld", &number) == 1) {
        printf("%ldn", remove_dups(number));
        printf("Enter a number (q to quit): ");
    }
    return 0;
}
/* return digit at plc = 1, 10, 100, ... */
long get_place(long num, long plc)
{
    return (num % ( 10 * plc) - num % plc) / plc;
}
/* remove digit at plc = 1, 10, 100, ..., and return result */
long remove_place(long num, long plc)
{
    return (num / (10 * plc)) * plc + num % plc;
}
/* remove all occurrences of d in num and return result */
long remove_digits(long num, long d)
{
    long place = 1;
    while (num / place) {
        if (get_place(num, place) == d)
            num = remove_place(num, place);
        else
            place *= 10;
    }
    return num;
}
long remove_dups(long num)
{
    long result, next_digit;
    long last_place = 1;
    result = 0;
    while (num) {
        for(last_place = 1; (num / (10 * last_place)); last_place *= 10)
            continue;
        next_digit = get_place(num, last_place);
        result = result * 10 + next_digit;
        num = remove_digits((num % last_place), next_digit);
    }
    return result;
}

下面是一些示例输出:

Enter a number (q to quit): -43456
-4356
Enter a number (q to quit): 43456
4356
Enter a number (q to quit): -12321
-123
Enter a number (q to quit): 299792458
297458
Enter a number (q to quit): 0
0
Enter a number (q to quit): 1
1
Enter a number (q to quit): -1
-1
Enter a number (q to quit): q

这是一个草图:

对于输入中的每个整数,从开始遍历输入,并将每个整数与当前整数进行比较。如果有匹配,则继续下一个输入整数。如果你到达开头,它不是重复的,所以打印它。

void printRepeating(const int arr[], size_t size) {
    const int* begin = arr;
    const int* end = arr + size;
    if ( begin == end ) return;
    // First element cannot be a duplicate, so always print it
    std::cout << *begin;
    // Traverse input array
    const int* curr = begin;
    while ( ++curr < end ) {
        // Traverse back to find a duplicate
        const int* curr_rev = curr - 1;
        for ( ; curr_rev >= begin && *curr != *curr_rev; --curr_rev );
        if ( curr_rev < begin )
            // Reached the beginning, so it cannot be a duplicate
            std::cout << " " << *curr;
    }
}

虽然我不确定,是否在数组之前构造一个指向元素的指针是未定义的行为,这里有一个轻微的变化,它从前到后遍历输入以找到重复的。这只是主循环——其他的和上面一样:

    // Traverse input array
    const int* curr = begin;
    while ( ++curr < end ) {
        // Traverse again to find a duplicate
        const int* cmp = begin;
        for ( ; cmp < curr && *cmp != *curr; ++cmp );
        if ( cmp == curr )
            // Reached current integer, so it cannot be a duplicate
            std::cout << " " << *curr;
    }

给定程序:

int main() {
    const int arr[]{ 1, 2, 3, 1, 3, 6, 6 };
    printRepeating( arr, std::end( arr ) - std::begin( arr ) );
}

产生以下输出:

1 2 3 6

对于您的示例

I/p: 43456 O/p: 4356

考虑这个问题的一种方法是,一个数字只有在它不出现在数字的更有效部分时才输出。所以我们从最低位到最高位逐个检查。如果数字(lastdig(num))出现在数字(butlastdig(num))的高有效部分,则丢弃该数字,否则保留该数字。

#include <stdbool.h>
#include <stdio.h>
inline unsigned lastdig(unsigned n) { return n%10; }
inline unsigned butlastdig(unsigned n) { return n/10; }
inline bool is_single_digit(unsigned n) { return n<10; }
bool is_in(unsigned digit, unsigned num)
{
    if (is_single_digit(num))
        return digit==num;
    else
        return (digit==lastdig(num)) || is_in(digit, butlastdig(num));
}
unsigned unique(unsigned num)
{
    unsigned last, butlast;
    if (is_single_digit(num))
        return num;
    last=lastdig(num);        
    butlast=unique(butlastdig(num));
    if (is_in(last, butlast))
        return butlast;
    else
        return butlast*10 + last;
}
main(int argc, char **argv)
{
    int i=atoi(argv[1]);
    if (i < 0)
        printf("nonnegative numbers onlyn");
    else
        printf("%u %un", i, unique(i));
}