【问题标题】:Find the largest multiple of 3 from array of digits in O(n) time complexity从 O(n) 时间复杂度的数字数组中找到 3 的最大倍数
【发布时间】:2021-03-21 12:01:51
【问题描述】:

给定一个数字数组(0 到 9)。找出可以由数组的部分或全部数字组成且能被 3 整除的最大数。同一个元素可能在数组中出现多次,但数组中的每个元素只能使用一次。 例子: 输入:arr[] = {5, 4, 3, 1, 1} 输出:4311

算法

  1. 获取数组大小和数组输入,并在获取输入时计算总和。
  2. 按升序对数组进行排序
  3. 取三个队列,迭代数组并将数字除以 3,然后根据余数放入各自的队列中,
    队列 0 保存数字 % 3 == 0
    队列 1 保存数字 % 3 == 1
    Queue2 保存数字 % 3 == 2
  4. 计算余数 = sum % 3,
    如果余数等于 1,则从 Queue1 中取出一个元素或从 Queue2 中取出两个元素
    如果余数等于 2,则从 Queue2 中取出一个元素或从 Queue1 中取出两个元素
  5. 将 Queue0、Queue1 和 Queue2 合并为一个队列
  6. 按降序对合并队列进行排序
  7. 打印合并队列。

代码

#include<stdio.h> 
int main()
{
    int n,sum=0;
    scanf("%d",&n);
    int a[n],q1[n],q2[n],q3[n];
    int c1=0,c2=0,c3=0;
    for(int i=0;i<n;i++) {
    scanf("%d",&a[i]);
    sum+=a[i]; }
    for(int i=0;i<n;i++){
        if(a[i]%3==0) {
            q1[c1]=a[i]; c1++; }
        else if(a[i]%3==1) {
            q2[c2]=a[i]; c2++; }
        else {
            q3[c3]=a[i]; c3++; }
    }
    if(sum%3==1&&c1!=0)
    c1--;
    else {
        if(c2>1)
            c2-2;
        else
            printf("Not Possible");
    }
    if(sum%3==2&&c2!=0)
    c2--;
    else {
        if(q1>1)
            c1-2;
        else
            printf("Not Possible");
    }
    int k=0,b[n];
    for(int i=0;i<c1;i++) {
        b[k]=q1[i]; k++; }
    for(int i=0;i<c2;i++) {
        b[k]=q2[i]; k++; }
    for(int i=0;i<c3;i++) {
        b[k]=q3[i]; k++; }
    }

我是编码新手,无法弄清楚 O(n) 中的排序和合并队列。在第 2 步和第 5 步方面需要帮助。

【问题讨论】:

  • 由于数组只包含一位数字,所以不需要三个队列。您需要的是数字的直方图。
  • 我们不需要 2 个循环来生成直方图吗?代码需要在 O(n) for (i = 0; i
  • @Arjun 你可以用一个循环来完成。 int h[10]={0}; for (i=0; i&lt;n; i++) h[a[i]]++; 实际上,您可以在读取输入的同时计算直方图。你甚至不需要a 数组。读取每个数字,更新总和,更新直方图。
  • 在第 4 步中,您将减少直方图中一位或两位数字的计数。然后生成输出需要两个循环:for (i=9; i&gt;=0;i--) for (count=h[i]; count&gt;0; count--) result[r++] = i; 但是这两个循环总共执行了n 次,因为直方图中的计数总和为n
  • 如果想提出我认为总体上更快的方法。不仅仅是没有队列,而是一个简单的判断可分性的条件。

标签: c


【解决方案1】:

1.对数组进行升序排序(计数排序)。
2.队列 q0 存储除以 3 余数为 0 的元素。
3.队列 q1 存储除以 3 得到余数 1 的元素。
4.队列 q2 存储除以 3 得到余数 2 的元素。
5.找到所有给定数字的总和。让它成为's'。
6.如果 s 能被 3 整除,则转到第 9 步。
7.如果 s 除以 3 得到余数 1:
从 q1 中删除一项。
如果 q1 为空,则从 q2 中删除两项。
如果 q2 包含的元素少于两个,则 number 是不可能的。
8.If s 除以 3 得到余数 2:
从 q2 中删除一项。
如果 q2 为空,则从 q1 中删除两项。
如果 q1 包含的元素少于两个,则 number 是不可能的。
9.将所有队列清空成一个临时数组,并按降序排序。

#include<stdio.h> 
int main()
{
    int n,max,f=0,c=0;
    scanf("%d",&n);
    int a[n],ct[10]={0},b[10],sum=0;
    for(int i=0;i<n;i++) {
        scanf("%d",&a[i]);
        sum+=a[i];}
    max=a[0];
    for(int i=0;i<n;i++)
        if(max<a[i])
            max=a[i];
    for(int i=0;i<n;i++)
        ct[a[i]]+=1;
    for(int i=1;i<=max;i++)
        ct[i]+=ct[i-1];
    for(int i=n-1;i>=0;i--)
        b[--ct[a[i]]]=a[i];
    if(sum%3==0)
        goto print;
    else if(sum%3==1) {
        for(int i=n-1;i>=0;i--)
            if(b[i]%3==1) {
                b[i]=-1; f=1;
                goto print;
            }
    }
    else {
        for(int i=n-1;i>=0;i--)
            if(b[i]%3==2) {
                b[i]=-1; f=1;
                goto print;
            }
    }
    if(f==0&&sum%3==1) {
        for(int i=n-1;i>=0&&c<2;i--)
            if(b[i]%3==2) {
                b[i]=-1;
                c++;
            }
    }
    if(f==0&&sum%3==2) {
        for(int i=n-1;i>=0&&c<2;i--)
            if(b[i]%3==1) {
                b[i]=-1;
                c++;
            }
    }
    print:
    for(int i=n-1;i>=0;i--)
        if(b[i]!=-1)
            printf("%d",b[i]);
    return 0;
}

【讨论】:

  • 您是否介意通过解释您正在做的什么来增强您的答案?单独的代码不是一个好的答案。
  • 我希望编辑足以解释代码。 @thebusybee
  • 请显示您的描述如何映射到源。例如,如果在第 6 步中跳转到第 9 步,我找不到队列的清空和排序。 - 此外,您的来源非常非常密集且难以跟踪。请查找一些代码样式,选择一种,并坚持下去。变量的名称应该更具描述性。 (我在多年前开始使用 C 时编写了这样的代码;与此同时,我艰难地了解到这是一个错误。)
  • 很抱歉我的错误我修改了很多原始代码。我只是将所有排序的元素放入数组 b 并检查所有元素总和的余数是否为 1 我使用 for 循环遍历数组 b 并检查是否 b[i]%3==1 并将其替换为 -1如果没有可替换的元素,我使用标志 f 替换 2 b[i]%3==2 个元素。sum%3==2 也是如此。如果 sum%3==0 我只是反向打印数组。对于其他人,我反向打印除 -1 以外的所有元素,以从数字数组中获得 3 的最大倍数。 @thebusybee
  • 我是编码新手。我上大学才一个月。我以前从未编程过。现在我不仅在学习用 c 编写代码,而且还在学习用 c 编写数据结构。
【解决方案2】:

要在O(n) 中排序,您需要使用Radix sort

// Let's start with the array that your code generates in step 5
int b[4] = {1, 1, 4, 3}

// Count the number of times each value is seen.
int buckets[10] = {};
for (int i=0; i<4; i++)
  buckets[b[i]]++;

// Update the b array with the sorted data.
int *b_iterator = &b[0];
for (int i=0; i<10; i++)
  for (int count=0; count<buckets[i]; count++)
    *b_iterator++ = i;

// b is now sorted. {1, 1, 3, 4}.

【讨论】:

  • 对于 OP 正在寻找的内容,无需进行拆包。直方图包含所有必要的信息。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-30
  • 1970-01-01
相关资源
最近更新 更多