【问题标题】:Checking numbers in an array检查数组中的数字
【发布时间】:2017-06-16 01:36:37
【问题描述】:

我想编写一个函数,当且仅当在大小为 n 的数组 t 中,我有 1,2 中的每一个数字,... n

我的想法是:

bool g(int* t, int n){
    for(int i = 0; i < n; i++){
        for(int j = n; j > 0; j--){
           if(t[i] == n)
              break;
           else
              return false;
        }
    }
    return true;
}

但是 int t[6] = {6, 2, 3, 4, 5, 1}; 的这个返回零是错误的,因为从 1 到 6 的所有数字都在一个数组中。

如何改进?此外,如何改进这个问题?

【问题讨论】:

  • 对数组求和,看是否等于n*(n+1)/2
  • @Ics 但如果 t[6]={1,1,1,1,1,16};
  • @Rama 因此事实上这个解决方案并不通用......总而言之我猜你必须浏览数组但是如何?
  • 排序后再一一检查。或者把它塞进一个哈希图中,然后一一检查。

标签: c++ if-statement for-loop


【解决方案1】:

你来了

#include <iostream>
#include <iomanip>

bool g( const int a[], int n )
{
    int long long sum = 0;
    int i = 0;

    for ( ; i < n && a[i] > 0 ; i++ ) sum += a[i];

    return i == n && sum == ( long long int )n * ( n + 1 ) / 2;
}   

int main() 
{
    const int N = 6;        
    int t[N] = { 6, 2, 3, 4, 5, 1 }; 

    std::cout << std::boolalpha << g( t, N ) << std::endl;
}

程序输出是

true

如果数组的所有元素都不同,此函数将起作用。

至于你的代码然后这个循环

    for(int j=n;j>0;j--){
    if(t[i]==n)
      break;
    else
      return false;
    }

没有意义。

【讨论】:

  • 正如 OP 中所述,此代码给出误报,例如:t[6]={1,1,1,6,6,6}; :ideone.com/xiWaFJ
  • @Rama 你是对的。应该附加一个要求,数组的所有元素都是不同的。:)
【解决方案2】:

试试这个。

#include <set>

typedef int data;
typedef std::set<data> set;

template<typename Iterator>
bool g(Iterator begin, const Iterator end) {

    set elements, expected;
    data i = 1;
    for (; begin != end; ++begin, ++i) {
        elements.insert(*begin);
        expected.insert(i);
    }

    return elements == expected;

}

【讨论】:

    【解决方案3】:

    我认为,最简单的方法是计算出现次数。 用零初始化 n+1 大小的数组“a”并增加 a[t[i]]。 它将在重复时退出。还要确保 t[i] 在有效范围内。

    bool g(int* t, int n)
        {
              int* a = (int*) calloc(n+1, sizeof(int));
              for(int i=0; i<n; i++)
              {
                    a[ t[i] ]++;
                    if(t[i]>n || t[i]<=0 || a[ t[i] ]>1)
                          return false;
              }
              return true;
        }
    

    【讨论】:

    • 你的函数有内存泄漏。
    • 你是对的。但它只是为了显示问题的解决方案
    【解决方案4】:

    我的解决方案是赋予值权重,例如二进制数字权重。 例如:

    1 => 重量1
    价值2 => 重量2
    价值3 => 重量4
    价值4 => 重量8
    价值x => 重量1 &lt;&lt; x-1

    然后将所有权重相加,并检查是否满足sum = 2^n-1

    #include <iostream>
    #include <iomanip>
    #include <cmath>
    
    bool g( const int a[], int n )
    {
        int long long sum = 0;
        int i = 0;
        long long int target = (1<<n)-1;
    
        for ( ; i < n && a[i] > 0 ; i++ ) sum += 1<<a[i]-1;
    
        return i == n && sum == target;
    }   
    
    int main() 
    {
        const int N = 6;        
        int t[N] = { 6, 2, 3, 4, 5, 1 }; 
    
        std::cout << std::boolalpha << g( t, N ) << std::endl;
    }
    

    这里的工作代码:http://ideone.com/DscXJH

    这个可能的解决方案是受到 OP 中@lcs 评论的启发。

    【讨论】:

    • @PaulMcKenzie 谢谢!按照stackoverflow.com/questions/18155883/…中的建议添加了round()
    • 要注意的不仅仅是舍入。 pow 可能非常昂贵。在这种情况下,n 的 2 非常容易通过位移 (1&lt;&lt;n) 执行,并且它可能比pow 函数调用开销更短,不包括计算结果所花费的时间。
    • @user4581301 太好了!谢谢,将 pow 行更改为:long long int target = (1&lt;&lt;n)-1;
    【解决方案5】:

    这是另一种解决方案,使用 STL 算法函数:

    #include <iostream>
    #include <algorithm>
    #include <numeric>
    using namespace std;
    
    bool g(int *t, int n)
    {
        if ( n == 0 ) 
           return false;
        std::sort(t, t + n);
        return (t[0] == 1) &&  // first number must be 1
                (std::distance(t, std::unique(t, t + n)) == n) &&  // all must be unique
                (std::accumulate(t, t + n, 0) == (n * (n + 1)) / 2); // has to add up correctly
    }
    
    int main()
    {
       int arr[] = {1,2,3,4,5,6,7};
       std::cout << g(arr, 7);
    }
    

    Live Example

    对数字列表排序后,std::unique算法函数用于将非唯一项移动到数组的末尾,然后给我们一个指向该非唯一项序列开始的指针。如果所有值都是唯一的,则std::unique 将返回数组末尾之后的一个位置。

    这就是std::distance 的原因——它告诉我们非唯一序列的开头和开头之间的数字数量是否等于整个列表中的数字数量。

    std::accumulate 只是简单地将序列中的所有数字相加,看看结果是否为(n * (n+1)) / 2,这是求第一个n 连续整数(从1 开始)之和的经典公式。


    这是一个更短的解决方案:

    #include <iostream>
    #include <algorithm>
    using namespace std;
    
    bool g(int *t, int n)
    {
        if ( n == 0 ) 
           return false;
        std::sort(t, t + n);
        return (t[0] == 1) &&  // first number must be 1
                (t[n-1] == n) && // last must be n
                (std::distance(t, std::unique(t, t + n)) == n); // all must be unique
    }
    

    另一种方法:

    #include <iostream>
    #include <algorithm>
    #include <set>
    using namespace std;
    
    bool g(int *t, int n)
    {
        if ( n == 0 ) 
           return false;
        std::sort(t, t + n);
        return (t[0] == 1) &&  // first number must be 1
                (t[n-1] == n) && // last must be n
                (std::set<int>(t, t+n).size() == n); // all must be unique
    }
    
    int main()
    {
       int arr[] = {1,2,3,4,5,6,7};
       std::cout << g(arr, 7);
    }
    

    Live Example

    在这种方法中,会从号码列表中创建一个临时的std::set。由于std::set只存储唯一的数字,所以插入所有项目后集合的size()必须等于n才能确定所有数字是否唯一。

    【讨论】:

      【解决方案6】:

      让 STL 完成这项工作。n 是非负数

      #include <set>
      
      bool g(int *t, int n)
      {
          std::set<int> s {t, t+n};
          return n > 0 && s.size() == n && *s.begin() == 1 && *s.rbegin() == n;
      }
      

      【讨论】:

        猜你喜欢
        • 2022-12-18
        • 2017-01-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-03-20
        • 1970-01-01
        • 2013-03-26
        • 2016-01-16
        相关资源
        最近更新 更多