用于打印重复字符的星号的算法

时间:2014-05-14 09:56:57

标签: c++ algorithm

我在接受采访时被问到这个问题:
给定一个带有输入字符串的数组,显示输出如下所示

输入

INDIA  

输出

INDA  
****  
* 

我遍历数组并将每个字符存储为std::map中的一个键,其值为出现次数。稍后我迭代地图并打印星号并减少地图中每个角色的值。

最初,我被要求不使用任何库。我给出了一个需要大量迭代的解决方案。对于每个字符,迭代完整数组直到索引以查找先前出现的事件,依此类推。 有没有更好的方法,例如更好的复杂性,例如更快的操作,可以实现这一目标吗?

8 个答案:

答案 0 :(得分:5)

基本上你要问的是如何在不使用STL代码的情况下实现map,因为使用某种复制map基本功能的数据结构几乎是最合理的解决方法这个问题。

有很多方法可以做到这一点。如果你的密钥(这里是可能的字符)来自一个非常大的集合,其中集合的大多数元素没有出现(例如完整的Unicode字符集),你可能想要使用树或散列表。这两种数据结构都非常重要,有很多变化和不同的实现方式。关于这两个结构有很多信息和示例代码。

正如@PeterG在评论中所说,如果你要看到的唯一字符来自一组256个8位字符(例如ASCII或类似字符),或者像大写字母一样的其他有限集合,你应该只需使用256个int的数组,并为其中的每个字符存储一个计数。

答案 1 :(得分:1)

如果所考虑的字母表是固定的,可以分两次完成:

  1. 创建一个整数数组A,其大小为字母,用全零初始化。
  2. 使用输入大小创建一个布尔数组B,使用所有false初始化。
  3. 迭代输入;为每个角色增加A的相应内容。
  4. 迭代输入;如果它的值为B,则输出一个字符,并将其B值设置为true。最后,输出一个回车。
  5. 重置B.
  6. 如4.中所示迭代输入,但如果A中的字符数是正数,则打印星号,然后减少此计数;否则打印一个空格。
  7. 输出回车;只要输出中有任何星星,就循环到5。

答案 2 :(得分:1)

以下代码正常运行。我假设您不能使用std :: string并注意,由于我没有使用动态容器,因此不会考虑溢出。这也假定字符可以用char表示。

#include <iostream>

int main()
{
    char input[100];
    unsigned int input_length = 0;
    char letters[100];
    unsigned int num_of_letters = 0;
    std::cin >> input;
    while (input[input_length] != '\0')
    {
        input_length += 1;
    }
    //This array acts like a hash map.
    unsigned int occurrences[256] = {0};
    unsigned int max_occurrences = 1;
    for (int i = 0; i < input_length; ++i)
    {
        if ((occurrences[static_cast<unsigned char>(input[i])] += 1) == 1)
        {
            std::cout<< " " << (letters[num_of_letters] = input[i]) << " ";
            num_of_letters += 1;
        }
        if (occurrences[static_cast<unsigned char>(input[i])] > max_occurrences)
        {
            max_occurrences = occurrences[static_cast<unsigned char>(input[i])];
        }
    }
    std::cout << std::endl;
    for (int row = 1; row <= max_occurrences; ++row)
    {
        for (int i = 0; i < num_of_letters; ++i)
        {

            if (occurrences[static_cast<unsigned char>(letters[i])] >= row)
            {
                std::cout << " * ";
            }
            else
            {
                std::cout << "   ";
            }

        }
        std::cout << std::endl;
    }
    return 0;
}

答案 3 :(得分:1)

这很有趣。你不应该使用stl :: map,因为那不是一个hashmap。 stl映射是二叉树。 unordered_map实际上是一个哈希映射。在这种情况下,我们也不需要。我们可以使用一个简单的数组来计算字数。

void printAstr(std::string str){
 int array[256] ;// assumining it is an ascii string
 memset(array, 0, sizeof(array));
 int astrCount = 0;
 for(int i = 0; i < str.length()-1; i++){
     array[(int) str[i]]++;
     if(array[(int) str[i]] > 1) astrCount++;
 }
std::cout << str  << std::endl;
for(int i = 0;  i < str.length()-1;i++) std::cout << "* ";
std::cout << std::endl;
while(astrCount != 0){
   for(int i= 0; i< str.length() - 1;i++){
       if(array[(int) str[i]] > 1){
          std::cout << "* ";
          array[(int) str[i]]--;
          astrCount--;
       }else{
        std::cout << " ";
       }
   }
   std::cout << std::endl;
}

}

非常简单,只需将所有值添加到数组中,然后将它们打印出你看起来的次数。

编辑:抱歉,只是做了一些逻辑更改。这现在有效。

答案 4 :(得分:1)

这是另一个: 您可以看到它正常工作HERE

#include <stdio.h>
int main()
{
    int i,j=0,f=1;
    char input[50]={'I','N','D','I','A','N','A','N'};
    char letters[256]={0};
    int counter[256]={0};
    for(i=0;i<50;i++)
    {
        if(input[i])
         counter[input[i]]++;
         if(counter[input[i]]==1)
         {
            putchar(input[i]);
            letters[j]=input[i];
            j++;
         }    
    }
    putchar('\n');
    while(f)
    {
        f=0;      
        for(i=0;i<j;i++)
            if(counter[letters[i]])
            {
                putchar('*');
                counter[letters[i]]--;
                f=1;
            }
            else
            {
                putchar(' ');
            }
        putchar('\n');  
    }
    return 0;
}

答案 5 :(得分:1)

这个问题被标记为,但在我看来答案并非完全是 C ++'ish ,但是很难用奇怪的方法来实现一个好的C ++代码要求“不使用任何库”。在我的方法中,我使用了一些 C ++ 11功能,如类内初始化或nullptrhere是现场演示,位于代码下方:

struct letter_count
{
    char letter = '\0';
    int count = 0;
};

int add(letter_count *begin, letter_count *end, char letter)
{
    while (begin != end)
    {
        if (begin->letter == letter)
        {
            return ++begin->count;
        }
        else if (begin->letter == '\0')
        {
            std::cout << letter; // Print the first appearance of each char
            ++begin->letter = letter;
            return ++begin->count;
        }

        ++begin;
    }

    return 0;
}

int max (int a, int b)
{
    return a > b ? a : b;
}

letter_count *buffer = nullptr;

auto testString = "supergalifragilisticoespialidoso";

int len = 0, index = 0, greater = 0;

while (testString[index++])
    ++len;

buffer = new letter_count[len];

for (index = 0; index < len; ++index)
    greater = max(add(buffer, buffer + len, testString[index]), greater);

std::cout << '\n';

for (int count = 0; count < greater; ++count)
{
    for (index = 0; buffer[index].letter && index < len; ++index)
        std::cout << (count < buffer[index].count ? '*' : ' ');

    std::cout << '\n';
}

delete [] buffer;

由于“不允许使用库”(<iostream>除外?)我避免使用std::pair<char, int>(可能是letter_count结构),我们必须编码许多实用程序(例如maxstrlen); avobe程序的输出是:

supergaliftcod
**************
* *******   * 
*     ***   * 
*       *     
        *     
        *     

答案 6 :(得分:1)

我的一般解决方案是遍历单词并用未使用的无意义字符替换重复的字符。下面是一个简单的例子,我用了一个感叹号(!)来表示无意义的字符(输入可能更健壮,某些字符不容易输入,不允许回答中的无意义字符,错误检查等)。遍历之后,最后一步将删除无意义的字符。问题是跟踪星号,同时保留他们所暗示的原始位置。为此,我使用临时字符串来保存字母和进程字符串以创建最终输出字符串和星号。

#include <iostream>
#include <string>

using namespace std;

int
main ()
{
  string input = "";
  string tempstring = "";
  string process = "";
  string output = "";
  bool test = false;

  cout << "Enter your word below: " << endl;
  cin >> input;

  for (unsigned int i = 0; i < input.length (); i++)
  { //for the traversed letter, traverse through subsequent letters    
    for (unsigned int z = i + 1; z < input.length (); z++)
    {
        //avoid analyzing nonsense characters
        if (input[i] != '!')    
        {           
          if (input[i] == input[z]) 
          { //matched letter; replace with nonsense character
            input[z] = '!';
            test = true;    //for string management later
          }
        }
    }
    if (test)   
    {
      tempstring += input[i];
      input[i] = '*';
      test = false; //reset bool for subsequent loops
    }
  }

  //remove garbage symbols and save to a processing string
  for (unsigned int i = 0; i < input.size (); i++)
    if (input[i] != '!')
      process += input[i];

  //create the modified output string
  unsigned int temp = 0;
  for (unsigned int i = 0; i < process.size (); i++)
    if (process[i] == '*')
    { //replace asterisks with letters stored in tempstring
      output += tempstring[temp];
      temp++;
    }
    else
      output += process[i];

   //output word with no repeated letters
  cout << output << endl;

  //output asterisks equal to output.length
  for (unsigned int a = 0; a < output.length (); a++)
    cout << "*";

  cout << endl;

  //output asterisks for the letter instances removed
  for (unsigned int i = 0; i < process.size (); i++)      
    if (process[i] != '*')
      process[i] = ' ';

  cout << process << endl << endl;
}

我通过运行代码收到的示例输出:

Enter your word below: 
INDIA
INDA
****
*

Enter your word below: 
abcdefgabchijklmnop
abcdefghijklmnop
****************
***

答案 7 :(得分:0)

可以使用简单数组来保持值的计数。

#include<iostream>
#include<string>

using namespace std;

int main(){

    string s;
    char arr[10000];
    cin>>s;
    int count1[256]={0},count2[256]={0};
    for(int i=0;i<s.size();++i){
        count1[s[i]]++;
        count2[s[i]]++;
    }
    long max=-1;
    int j=0;
    for(int i=0;i<s.size();++i){
        if(count1[s[i]]==count2[s[i]]){ //check if not printing duplicate
            cout<<s[i]; 
            arr[j++]=s[i];
        }
        if(count2[s[i]]>max)
            max=count2[s[i]];
        --count1[s[i]];
    }
    cout<<endl;
    for(int i =1; i<=max;++i){
        for(int k=0;k<j;++k){
            if(count2[arr[k]]){
                cout<<"*";
                count2[arr[k]]--;
            }
            else
                cout<<" ";
        }
        cout<<endl;

    }

}