【问题标题】:Calculating lowest subtotal of array in C计算C中数组的最低小计
【发布时间】:2022-01-07 09:22:13
【问题描述】:

我想在数组 z 中搜索 k 值的最低小计,其中包含由用户输入填充的 n 个元素。这适用于 k==1,但我不明白为什么我的代码不适用于 k>1。 我的程序输出了错误的索引和小计。

从main调用函数,在循环中用n个int值元素填充数组直到它被填充,要求k的所需长度。

请帮助我理解我做错了什么

#include <stdio.h>

void lowest_subtotal(int z[], int n, int k){
   int t[]={0};
   int i = 0, position = 0, tempmin;

   if(k==1){ //working 100%
       while(i<n){
           if(z[i]<tempmin){
               tempmin=z[i];
               position=i;
           }
           i++;
        }
   printf("Lowest subtotal on Index %d. (sum: %d.)", position, tempmin);
   }

   else{
       //calculate subtotals
       while(i<=n){ 
           for(int j=0; j<k; j++){
               if(z[i+j]<0){
                   t[i] -= z[j];
               }
               else{
                   t[i] += z[j];
               }
           }
           i++;
       }
    
       //search for lowest subtotal
       i = 0;
       while(i<n-k+1){
           if(t[i] < tempmin){
               tempmin = t[i];
               position=i;
           }
       i++;
       }
       //wrong result of index and sum?
       printf("Lowest subtotal on Index %d. (sum: %d.)",position-k-1,tempmin);
   }
}
    int main(){
    int n,k; //length of vector, length of subtotal
    
    printf("n: ");
    scanf("%d",&n);
    
    int z[99] = { 0 }; //initialize array
    
    
    printf("input elements:\n");
    for(int i=0; i<n; i++){
        scanf("%d",&z[i]);
    }
    
    printf("length of subtotal?: ");
    scanf("%d",&k);
    
    lowest_subtotal(z,n,k);
}

【问题讨论】:

  • @vnmsc 为什么减去一个负值 t[i] -= z[j];?
  • int t[]={0}; 定义数组 t 并为 one 元素定义空间,使用 0 初始化该单个元素。
  • 变量n 中有数组z 的元素数。为什么不使用它来定义 z 并使用适当的大小呢?如int z[n];?
  • 另外,请尝试提出语义上重要的变量名称,而不是非描述性的单字母名称。
  • 在其他错误中,tempmin 的值在初始化之前被使用。

标签: arrays c c99 subtotal


【解决方案1】:

如果你把它分成单独的任务(函数),对你来说会容易得多。

long long subtotal(int *arr, size_t size, size_t start, size_t k)
{
    long long result = 0;

    for(size_t index = 0; index < k; index ++)
    {
        result += arr[start + index];
    }
    return result;
}

long long smallestSubtotal(int *arr, size_t size, size_t k, size_t *startpos)
{
    long long result = LLONG_MAX;
    for(size_t start = 0; start < size - k; start++)
    {
        long long sum = subtotal(arr, size, start, k);
        if(result > sum)
        {
            if(startpos) *startpos = start;
            result = sum;
        }
    }
    return result;
}
void lowest_subtotal(int z[], size_t n, size_t k)
{
    size_t index;
    long long subt;

    subt = smallestSubtotal(z, n, k, &index);

    printf("The smallest subtotal of length %zu is %lld at index %zu\n", k, subt, index);
}

int main(void)
{
    int arr[SIZE];

    srand(time(NULL));
    for(size_t index = 0; index < SIZE; index++)
    {
        arr[index] = rand();
    }

    lowest_subtotal(arr, SIZE, 15);
}

【讨论】:

  • srand(time(NULL));
  • @svnmsc 甚至我的回答:stackoverflow.com/a/70583744/6110094
  • 我搜索了它,但无法弄清楚为什么在这种情况下你使用随机性,因为它似乎没有必要
  • @svnmsc 在每个程序运行时生成 distinct 个测试用例。
【解决方案2】:

正如我从 OP 代码中了解到的,任务是在 n 数字数组中找到 k 连续 数字的起始索引,使得 k 数字的总和是最小的。

k=1 的情况不必是特殊情况。此外,更新k 元素的“窗口”之和的想法很好,但在实现中存在一些错误。 lowest_subtotal() 的工作版本如下:

#include<limits.h>

int lowest_subtotal(int z[], int n, int k)
{
    if(k > n || k < 1)
    {
        return -1;  // Error, k must be in the range from 1 to n 
    }

    // Calculate sum in window at index 0
    int sum = 0;
    for(int i = 0; i < k; i++)
    {
        sum += z[i];
    }

    // Slide window and update sum
    int index = 0;
    int min_sum = sum;
    for(int i = 1; i < n - k; i++)
    {
        sum += z[i+k-1] - z[i-1];  // Add incoming value and subtract the leaving value
        if(sum < min_sum)
        {
             min_sum = sum;
             index = i;
        }
    }
    printf("Lowest subtotal at index %d (sum=%d)\n", index, min_sum);
    return index;
}

【讨论】:

  • 1.索引类型错误。 2. sum 很容易溢出
  • @0___________ 你在这两个方面都是对的。我将根据用例的需要将此作为练习。我的主要观点是展示正确的“滑动窗口”实现,它提供 O(n) 性能,而不是天真的实现的 O(nk)。
  • 我不认为他想要任何不幼稚的东西。他正在学习基本的东西:)。性能不如避免 UB 陷阱重要
  • @0___________ 那么系统允许多个答案涵盖不同方面是很好的:-)
猜你喜欢
  • 2015-08-31
  • 2019-10-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-05-12
  • 1970-01-01
  • 2020-09-16
相关资源
最近更新 更多