算法专题-STL篇

  这篇文章着重记录c++中STL的用法。主要粗略的介绍其用法,以知识点的形式呈现其功能,不会深入源码分析其工作原理。

  排序和检索.

  sort(a,a+n),对a[0]往后的n个元素(包括a[0])进行排序,默认的这种形式由小到大的排序.其属于<algorithm>这个头文件中,它可以给任何对象进行排序,但是需要写自定义函数cmp.完整形式为sort(a,a+n,cmp).

low_bound(a , a+n ,x)-a得到数组a[]从a[0]往后n个长度中,第一个大于或者等于x的下标index.这里的下标,是指数组a[0],a[1],a[2],…,a[n-1]中的下标。

Q1(uva 10474):

  现在有N个大理石每颗石头上写了一个非负整数。首先把各数从小到大排序,然后进行Q次质询,每次质询给出一个负整数,需要你找到这个整数在第几颗石头上(排序后)。

  具体代码:

 

 #include<cstdio>
#include<algorithm>

using namespace std;
const int maxn = 10000;

int main()
{
    int n , q , a[maxn] , kase = 1;
    while(scanf("%d%d",&n , &q) != EOF)
    {
         if(n == 0)  break;
          printf("CASE# %d:\n",kase++);
         for(int i = 0;i < n;i++)
              scanf("%d",&a[i]);

         sort(a , a + n);
         while(q--)
         {

            int x;
            scanf("%d",&x);
            int index;
            index = lower_bound(a , a + n , x) - a;
            if(a[index] == x)  printf("%d found at %d\n",x , index + 1);
            else               printf("%d not found\n",x);
         }
    }
}

 

 

 集合set:集合是stl中一个容器,它储存字符串的时候。默认按照字典序排列。

 stringstream(str):这个对象的用法,是以流的方式,将一个字符串s(形如s1 s2 s3)分别表示成三个子串s1,s2,s3的形式。

  Q2:给出一个文本,找出所有不同的单词(连续的字母序列),按字典序从小到大输出,单词不区分大小写。

  分析:这个问题就是为了简单的呈现set和stringstream的用法。首先我们利用特殊的输入技巧,将文本的被空格分隔的连续串拿下来,然后基于stringstream的用法再将某个连续串中非字母的成分变为空格,再把真正的连续字母序列拿到,将其存在容器set里面,由于set容器对字符串默认为由小到大的字典序排列,我们只需要再将容器中的内容顺序输出即可。

  参考代码如下:

 

 #include<cstdio>
#include<iostream>
#include<string>
#include<set>
#include<sstream>
using namespace std;
set<string> dict;

int main()
{
     string s , buf;
     while(cin>>s)
     {
          for(int i = 0;i < s.length();i++)
             if(isalpha(s[i]))  s[i] = tolower(s[i]);
             else               s[i] = ' ';

            stringstream ss(s);
            while(ss >>  buf)  dict.insert(buf);
     }

     for(set<string>::iterator it = dict.begin();it != dict.end();++it)

           cout <<*it<<"\n";

     return 0;
}

 
 

   映射map:

  map能够建立两个数组元素之间的一一对应关系,例如我们建立星期几的英文单词和数字1~7的映射关系,就可以定义map<string , int> a,  a[“Monday”] = 1.

  Q3(uva 156):

  给出一个文本,找到文本中的一类单词,这一类单词满足该文本中其余任何单词,通过重组字母序列,都无法得到这个单词,找到所有这类的单词之后,按照字典序输出。

  分析:这个看似和字符串有关的复杂模拟题目,和诸多stl中的用法结合起来,就会显得一场简洁.

  考虑如何满足那条性质,假设我们用一个vector<string> s来储存原始的文本,遍历每个单词,我们将得到的单词按照字母大小顺序进行重排,得到新的序列r,将其放入映射中,我们领用map<string , int> cnt记录重排后的序列r出现的次数,遍历完文本单词之后,我们再遍历储存原始文本的向量s,如果当前的单词s[i],其重排之后的序列r,满足cnt[r] = 1,说明这个字符串是满足要求的字符串,将其放入一个新的字符串向量ans中,枚举完成后,将ans按照字典序排序,然后顺序输出即可。

  参考代码如下:

 

#include<cstdio>
#include<iostream>
//#include<cctype>
#include<vector>
#include<map>
#include<algorithm>
using namespace std;
map<string , int> cnt;
vector<string> words;

string repr(const string &s)
{
      string ans = s;
      for(int i = 0;i < ans.length();i++)
          ans[i] = tolower(ans[i]);

      sort(ans.begin() , ans.end());

      return ans;
}

int main()
{
      int n = 0;
      string s;
      while(cin >> s)
      {
            if(s[0] == '#') break;
             words.push_back(s);
             string r = repr(s);

             if(!cnt.count(r))  cnt[r] = 0;
             cnt[r]++;
      }

      vector<string> ans;
      for(int i = 0;i < words.size();i++)
          if(cnt[repr(words[i])] == 1)   ans.push_back(words[i]);
      sort(ans.begin() , ans.end());

      for(int i = 0;i < ans.size();i++)
        cout<<ans[i]<<"\n";
}

 

posted on 2016-10-21 01:35  在苏州的城边  阅读(330)  评论(0编辑  收藏  举报

导航