用 C++ 在给定的未排序序列中找到第一个最长的升序或降序子序列

Posted

技术标签:

【中文标题】用 C++ 在给定的未排序序列中找到第一个最长的升序或降序子序列【英文标题】:find the first longest ascending or descending sub-sequence in a given unsorted sequence by C++ 【发布时间】:2013-09-03 17:31:29 【问题描述】:

我正在编写一个 C++ 程序,它将查找并打印第一个最长的 整数向量的升序或降序连续子序列。例如, 给定一个带有

的向量
 4, 2, 1, 2, 3, 4, 3, 5, 1, 2, 4, 6, 5

返回 1,2,3,4

我的代码如下:

但是,我不知道如何返回第一个最优解。 例如,上面的序列有 1、2、4、6,也是 4 长。 但是,我们只需要返回 1,2,3,4。

bool findLong(const vector<int> v)

  if (v.size() <1)
    return false;
  if (v.size() == 1)
    cout << v[0] << endl;
    return true;
  
  vector::const_iterator itr_left, itr_right;
  itr_left = v.begin();
  itr_right = v.begin()+1;
  bool ascending_flag ;
  int counter =0;
  if (*itr_right > *(itr_right-1))
    bool ascending_flag = true;
    ++ascending_counter;    
   
  else
    bool ascending_flag = false;
    ++descending_counter;
  
  int longest = INT_MIN;
  Vector<int>::iterator longest_left = v.begin(), longest_right =v.begin(); 
  ++itr_right; 
  while (itr_right != v.end())
  
   if (ascending_flag && *itr_right > *(itr_right-1))
     ++ascending_counter; 

   if (!ascending_flag&& *itr_right < *(itr_right-1))     
     ++descending_counter;       

   if  (ascending_flag&& *itr_right < *(itr_right-1))
   
     if (ascending_counter > longest )
     
        longest  = ascending_counter;
        longest_left = itr_left;
        longest_right = itr_right;
    
    itr_left = itr_right;    
    ascending_counter = 0 ;  
    ascending_flag = false;
  
  if  (ascending_flag && *itr_right > *(itr_right-1))
  
    if (descending_counter > longest )
    
        longest  = descending_counter;
        longest_left = itr_left;
        longest_right = itr_right;
           
    itr_left = itr_right;      
    descending_counter = 0 ;
    ascending_flag = true;
  
  ++itr_right;
 
 for_each( longest_left , longest_right, print);
 cout << endl;


Void print(int i)

  cout << i << " , " ;

欢迎任何cmets!

谢谢!

【问题讨论】:

1 2 3 4 5 6 是一个较长的子序列。你的意思是 substring 还是 contiguous subsequence 还是你的例子错了? 这是一个基本的动态规划问题(例如适用于许多生物技术问题),因此您可能想研究一下。 @IVIAd,是的,它是连续的子序列。对困惑感到抱歉。已更正。 【参考方案1】:

您的代码中有很多错字: 你隐藏了ascending_flag的初始化 您的长度计数似乎不正确。

以下应该可以工作(只要没有两个具有相同值的邻居)。

bool findLong(const vector<int>& v)

    if (v.empty())
        return false;
    if (v.size() == 1) 
        cout << v[0] << endl;
        return true;
    
    vector<int>::const_iterator itr_left = v.begin();
    vector<int>::const_iterator itr_right = v.begin() + 1;
    vector<int>::const_iterator longest_left = itr_left;
    vector<int>::const_iterator longest_right = itr_right;
    bool ascending_flag = (*itr_right > *(itr_right - 1));

    for (++itr_right; itr_right != v.end(); ++itr_right)
    
        if (ascending_flag ^ (*itr_right < *(itr_right - 1)))
        
            if (itr_right - itr_left > longest_right - longest_left)
            
                longest_left = itr_left;
                longest_right = itr_right;
            
            itr_left = itr_right - 1;
            ascending_flag = !ascending_flag;
        
    
    for_each(longest_left, longest_right, print);
    cout << endl;
    return true;

【讨论】:

【参考方案2】:

以下是一些想法:

    如果函数名为“findX()”,它应该返回 X(例如,指向序列第一个元素的指针或 NULL,或第一个元素的索引或 -1)。如果函数打印 X,则应命名为“printX()”。 尚不清楚您需要升序还是严格升序(即 (1, 2, 2, 3) 是否适合您)。

    你把事情复杂化了。如果您需要 first 序列,则只需使用反向迭代器并从头到尾,就像这样(我不使用迭代器,但应该清楚如何包含它们):

    int maxLength=1, currentUp=1, currentDown=1; //Last element is sequence of 1 element
    size_t result = v.length()-1;
    for(size_t i = v.length()-1; i!=0; --i)
        if(v[i-1] > v[i]) 
            currentDown++; currentUp=0;
         else if(v[i-1] < v[i]) 
            currentUp++; currentDown=0;
         else 
            //Not clear what should happen, change may be needed
            currentUp++; currentDown++;
        
    
        if(maxLength <= max(currentUp, currentDown)) 
            result = i-1;
            maxLength = max(currentUp, currentDown);
        
    
    
    return result;
    

【讨论】:

【参考方案3】:

好吧,对于初学者来说,您的函数将始终返回 true。

if (v.size() <1)
  return false;
if (v.size() == 1)
  cout << v[0] << endl;
return true;

应该是

if (v.size() <1) 
  return false;

 else if (v.size() == 1) 
  cout << v[0] << endl;
  return true;

【讨论】:

以上是关于用 C++ 在给定的未排序序列中找到第一个最长的升序或降序子序列的主要内容,如果未能解决你的问题,请参考以下文章

674. 最长连续递增序列

14. 最长公共前缀

最长连续序列

Leetcode 128 最长连续序列

Leetcode 673.最长递增子序列的个数

Q673 最长递增子序列的个数