【问题标题】:How to group "unlike" elements when iterating array (e.g.:{1,2,2,1,3,3,3,2,1,1} to {1,2}{2,1,3}{3}{3,2,1}{1})?迭代数组时如何对“不同”元素进行分组(例如:{1,2,2,1,3,3,3,2,1,1} 到 {1,2}{2,1,3}{3} {3,2,1}{1})?
【发布时间】:2016-08-28 06:13:15
【问题描述】:

我有数组

int a[]={1,2,2,1,3,3,3,2,1,1};

如果我想在迭代时对相同的元素进行分组(没有任何临时变量或数组来存储或复制元素),例如,在迭代时在一行中打印相同的元素:

1 
2 2 
1 
3 3 3 
2 
1 1 

我可以有这样的 for 循环和 if 条件:

#include <stdio.h>
int main(){
    int a[]={1,2,2,1,3,3,3,2,1,1};
    for(int i=0,j=0;i<sizeof(a)/sizeof(int);i++){
        if(i==sizeof(a)/sizeof(int)-1 || a[i]!=a[i+1]){
            for(;j<=i;j++){
                printf("%d ",a[j]);
            }
            printf("\n");
        }
    }
    return 0;
}

但现在我想在迭代时对“不同”元素进行分组:每个组附近没有相同的元素:

1 2 
2 1 3 
3 
3 2 1 
1 

是否有可能有类似于以前版本的解决方案

for(int i=0,j=0;i<sizeof(a)/sizeof(int);i++){
    if(...){
        for(;j<=i;j++){
            printf("%d ",a[j]);
        }
        printf("\n");
    }
}

可以在没有任何临时变量的情况下迭代数组以打印这样的结果?

【问题讨论】:

  • 如果一个元素与下一个元素相同,打印一个'\n'。最后要小心。 (或者反过来,检查是否和前面一样,一开始要小心)。
  • @amuse 如果您不想使用任何临时变量,请参阅我的解决方案。

标签: c++ arrays algorithm for-loop iterator


【解决方案1】:
int a[] = {1,2,2,1,3,3,3,2,1,1};

int prev = a[0];
bool first = false;
printf("%d", prev);

for (int i=1; i < sizeof(a) / sizeof(int); ++i) {
    int curr = a[i];
    if (curr != prev) {
        // start a new line for a new group
        printf("\n");
        first = true;
    }
    if (!first) {
        // print a space after each element
        printf(" ");
    }
    printf("%d", curr);
    first = false;
    prev = curr;
}

【讨论】:

  • int first:我宁愿在 C++ 中使用bool
  • @Melebius 基于printf 的使用,并且看不到一个std::,我认为他将其误认为是C 问题。
  • @BoBTFish 我不是 C++ 人(按行业),但 OP 对我来说很有趣,所以我尝试了一个答案。
【解决方案2】:

只需对数组进行一次迭代,无需使用任何临时变量即可轻松解决问题。

主要思想是在打印当前索引处的元素之前先向后看,如果它们都匹配,那么我们必须将当前索引处的元素放在一个新行上,仅此而已。

第一个元素被打印,循环从第二个元素开始,因为第一个元素后面没有元素。

使用这个基本思想,代码如下:

int a[] = {1,2,2,1,3,3,3,2,1,1};
//print the first element
printf("%d ",a[0]);
for (int i=1; i < sizeof(a) / sizeof(int); ++i) {
 //check if the element at current index matches previous element.
 if(a[i] == a[i-1]) 
  printf("\n%d ",arr[i]);
 else printf("%d ",arr[i]);

}

【讨论】:

  • 我几乎喜欢这个,除了它总是会在每一行打印一个额外的空格(不是世界末日)。
  • @TimBiegeleisen 尝试将第一个格式说明符更改为"%d",将循环中的其他格式说明符更改为"\n%d"" %d",或者使用cout &lt;&lt; a[0];,然后使用cout &lt;&lt; '\n' &lt;&lt; arr[i];cout &lt;&lt; ' ' &lt;&lt; arr[i];。然后我意识到你已经这样回答了;)...
【解决方案3】:

这只是乞求adjacent_find解决。

对于不同的元素进行分组,您可以这样做:

auto i = cbegin(a);

for (auto j = adjacent_find(cbegin(a), cend(a)); j != cend(a); i = j, j = adjacent_find(i, cend(a))) {
    copy(i, ++j, ostream_iterator<decltype(*cbegin(a))>(cout, " "));
    cout << endl;
}
copy(i, cend(a), ostream_iterator<decltype(*cbegin(a))>(cout, " "));

对于类似元素的分组,您可以简单地使用not_equal_to 作为adjacent_find 的二元谓词:

auto i = cbegin(a);

for (auto j = adjacent_find(cbegin(a), cend(a), not_equal_to<decltype(*cbegin(a))>()); j != cend(a); i = j, j = adjacent_find(i, cend(a), not_equal_to<decltype(*cbegin(a))>())) {
    copy(i, ++j, ostream_iterator<decltype(*cbegin(a))>(cout, " "));
    cout << endl;
}
copy(i, cend(a), ostream_iterator<decltype(*cbegin(a))>(cout, " "));

Live Examples

注意:decltype(*cbegin(a)) 可能看起来有点复杂,可以用int 代替,但是你会失去灵活性。现在,如果您任意想将a 声明为string 甚至set&lt;double&gt;,则此代码无需更改。

【讨论】:

    【解决方案4】:

    你为解决这个问题所做的一切都是时间复杂度O(N^2)。但是可以在时间复杂度O(N)中解决这个问题,这在前面的答案中解释得很好。但我认为你只需要通过更改if(...) 来做到这一点。我在这里找到了解决方案。用以下代码替换该行。

    if( (i<sizeof(a)/sizeof(int) && a[i]==a[i+1]) || i==sizeof(a)/sizeof(int)-1 )
    

    您无需更改任何其他内容。

    我认为(i&lt;sizeof(a)/sizeof(int) &amp;&amp; a[i]==a[i+1]) 部分很好理解,i==sizeof(a)/sizeof(int)-1 部分专门用于最后一个元素,如果最后一个元素等于倒数第二个元素。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-01-19
      • 1970-01-01
      • 1970-01-01
      • 2020-08-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多