为重复字符打印星号的算法

Algorithm to print asterisks for duplicate characters

本文关键字:算法 打印 字符      更新时间:2023-10-16

我在一次面试中被问到这个问题:
给定一个带有输入字符串的数组,显示如下所示的输出

输入

INDIA  

INDA  
****  
* 

遍历数组并将每个字符存储为std::map中的键,value作为出现次数。稍后,我迭代映射并打印星号,并减少映射中每个字符的值。

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

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

有很多方法可以做到这一点。如果您的键(这里是可能的字符)来自一个非常大的集合,而该集合的大多数元素都不出现(例如完整的Unicode字符集),那么您可能希望使用树或散列表。这两种数据结构都非常重要,它们有很多变化,实现方式也不同。有很多关于这两个结构的信息和示例代码。

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

这是另一个:你可以在这里看到它的工作

#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;
}

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

  1. 用字母表的大小创建一个整数数组A,初始化为全零。
  2. 创建一个布尔数组B,大小与输入相同,初始化为false。
  3. 迭代输入;A.每增加一个字符对应的含量。
  4. 迭代输入;如果它在B中的值为false,则输出一个字符,并将其在B中的值设置为true。最后,输出一个回车。
  5. 重置b .
  6. 按4迭代输入。,但如果字符在a中的计数为正数,则打印星号,然后减少该计数;否则打印空格。
  7. 输出回车;只要在生成的输出中有任何星星,循环到5。

这很有趣。不应该使用stl::map,因为它不是hashmap。一个静态映射是一个二叉树。unordered_map实际上是一个散列映射。在这种情况下,我们都不需要。我们可以使用一个简单的数组来存储char计数。

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;
}

}

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

编辑:对不起,只是做了一些逻辑上的改变。

下面的代码可以正常工作。我假设您不能使用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] != '')
    {
        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;
}

这个问题被标记为c++,但在我看来,答案并不都是相当 c++ 'ish,但可能很难实现一个良好的c++代码与一个奇怪的要求,如"不使用任何库"。在我的方法中,我使用了一些很酷的 c++ 11特性,如类内初始化或nullptr,下面是实时演示代码:

struct letter_count
{
    char letter = '';
    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 == '')
        {
            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;

既然"no libraries are allowed"(除了<iostream> ?)我已经避免使用std::pair<char, int>(这可能是letter_count结构体),我们必须编写许多实用程序(如maxstrlen);程序avobe的输出是:

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

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

#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
****************
***

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

#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;
    }
}