определить, имеет ли строка все уникальные символы?

может ли кто-нибудь сказать мне, как реализовать программу для проверки строки, содержащей все уникальные символы ?

16 ответов


Если вы говорите о строке ASCII:

  1. создать массив int [0-255], один для каждого индекса символов, инициализировано до нуля.

  2. цикл каждый символ в строке и увеличьте соответствующую позицию массива для этого символа

  3. Если позиция массива уже содержит 1, то этот символ уже был обнаружен. Результат => не уникален.

  4. Если вы достигнете конец строки без вхождения (3), Result => строка уникальна.


сортировка символов в строке с помощью алгоритма выбора (например, builtin qsort функция), затем сканируйте строку, проверяя последовательные повторяющиеся буквы; если Вы дойдете до конца, не найдя ни одного, строка содержит все уникальные символы.

альтернативой может быть использование некоторой структуры, которая имеет по одному ведру для каждого символа, который может содержать строка, инициализированная до нуля; вы сканируете строку, увеличивая значение ведра, соответствующее текущему характер. Если вы увеличиваете ведро, в котором уже есть 1, Вы уверены, что ваша строка содержит дубликаты.

Это может работать нормально с chars и массив (размера UCHAR_MAX+1), но это быстро выходит из-под контроля, когда вы начинаете иметь дело с широкими символами. В таком случае вам понадобится hashtable или какой-либо другой "серьезный" контейнер.

лучший алгоритм зависит от длины строк для изучения, размера каждого символа, скорости алгоритм сортировки и стоимость выделения / использования структуры для хранения частот символов.


#include <iostream>
#include <string>
using namespace std;

bool isUnique(string _str)
{
        bool char_set[256];
        int len = _str.length();

        memset(char_set, '', 256);
        for(int i = 0; i < len; ++i)
        {
            int val = _str[i]- '0';
            if(char_set[val])
            {
                return false;
            }
            char_set[val] = true;
        }

        return true;
    }

    int main()
    {
        cout<<"Value: "<<isUnique("abcd")<<endl;
        return 0;
    }

сделайте набор букв и подсчитайте значения.

set("adoihgoiaheg") = set(['a', 'e', 'd', 'g', 'i', 'h', 'o']):

def hasUniqueLetters(str):
    return (len(set(str)) == len(str))

>>> hasUniqueLetters("adoihgoiaheg")
False

используйте массив с 256 входами. Заполните его 0. Теперь пересеките строку, установив соответствующую запись в массиве в 1, если она равна 0. В противном случае в строке появляются повторяющиеся символы.


задайте массив логических значений размером, равным набору символов false. (Постоянное время.) Сканируйте строку; для каждого символа проверьте массив в слоте characater; если true, строка имеет повторяющиеся символы. Если false, установите для этого слота значение true и продолжайте. Если вы доберетесь до конца, не встретив дубликата, их не будет, а строка содержит только уникальные символы. Время выполнения: O (n), когда n-длина строки, с довольно маленькой константой.


аналогично (и без массивов) используйте хэш-таблицу!

/ / код psuedo:

  1. пройти через каждый символ строки
  2. хэш char и посмотреть его в хэш-таблице
  3. если таблица имеет хэш, верните FALSE // так как она не уникальна
  4. __else хранить хэш
  5. вернитесь к шагу #1, пока не закончите

время выполнения O (n) и пространство памяти также лучше, так как вам не нужен массив из 256 (asciis)


#include <stdio.h>

#define ARR_SIZE 32

unsigned char charFlag[ARR_SIZE];

void initFlag() {
    int i = 0;

    for (i = 0; i < ARR_SIZE; i++)
        charFlag[i] = 0;

}

int getFlag(int position) {
    int val = 0;
    int flagMask = 1;

    int byteIndex = position / 8;
    int locPos = position % 8;

    flagMask = flagMask << locPos;
//  flagMask = ~flagMask;

    val = charFlag[byteIndex] & flagMask;
    val = !(!val);
//  printf("\nhex: %x\n", val);
    return val;

}

void setFlag(int position) {
    int flagMask = 1;
    int byteIndex = position / 8;
    int locPos = position % 8;

    flagMask = flagMask << locPos;
    charFlag[byteIndex] = charFlag[byteIndex] | flagMask;

}
int isUniq(char *str) {
    int is_uniq = 1;

    do {
        char *lStr = str;
        int strLen = 0;
        int i;

        if (str == 0)
            break;

        while (*lStr != 0) {
            lStr++;
            strLen++;
        }

        initFlag();
        lStr = str;
        for (i = 0; i < strLen; i++) {
            if (getFlag(lStr[i]))
                break;

            setFlag(lStr[i]);
        }

        if (i != strLen)
            is_uniq = 0;

    } while (0);

    return is_uniq;
}

int main() {

    char *p = "abcdefe";
    printf("Uniq: %d\n", isUniq(p));
    return 0;
}

используйте хэш-таблицу, добавьте ключ для каждого символа вместе с количеством вхождений в качестве значения. Цикл через ключи HashTable, чтобы увидеть, если вы столкнулись с count > 1. Если это так, выведите false.


простое решение будет использовать 2 цикла. Для отслеживания символов не требуется дополнительная структура данных.

bool has_unique_char(char *str,int n)
{
      if(n==0)
           return true;

      for(int i=1;i<n;i++){
            for(int j=0;j<i;j++){
                    if(str[i] == str[j])
                          return false;
            }      
      }
      return true;
}

bool isUnique(char st[],int size)
{
    bool char_set[256]=false;
    for(int i=0;i<size;i++)
    {
        if(char_set[st[i]]-'0')
        return false;
        char_set[st[i]-'0')=true;
    }
    return true;
}

мой первоначальный ответ также выполнял аналогичную технику массива и подсчитывал появление символов.

но я делал это в C, и я думаю, что это может быть просто, используя некоторые манипуляции указателем и полностью избавиться от массива

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

void main (int argc, char *argv[])
{
    char *string;
    if (argc<2)
    {
        printf ("please specify a string parameter.\n");
        exit (0);       
    }

    string = argv[1];
    int i;

    int is_unique = 1;
    char *to_check;
    while (*string)
    {
        to_check = string+1;
        while (*to_check)
        {
            //printf ("s = %c, c = %c\n", *string, *to_check);
            if (*to_check == *string)
            {
                is_unique = 0;
                break;
            }
            to_check++;
        }
        string++;
    }

    if (is_unique)
        printf ("string is unique\n");
    else
        printf ("string is NOT unique\n");
}

без использования дополнительной памяти:

#define UNIQUE_ARRAY 1
int isUniqueArray(char* string){
    if(NULL == string ) return ! UNIQUE_ARRAY;
    char* current = string;
    while(*current){
        char* next   = current+1;
        while(*next){
            if(*next == *current){
                return ! UNIQUE_ARRAY;
            }
            next++;
        }
        current++;
    }
    return UNIQUE_ARRAY;
}

Я верю, что есть гораздо более простой способ:

int check_string_unique(char *str) 
{
   int i = 0;
   int a = 0;
   while (str[i])
   {
      a = i + 1; // peak to the next character
      while (str[a])
      {
          if (str[i] == str[a]) // you found a match
             return (0); // false
          a++; // if you've checked a character before, there's no need to start at the beggining of the string each time. You only have to check with what is left.
      }
   i++; //check each character.
   }
return (1); //true!
}

Я надеюсь, это может помочь вам

#include <iostream>
using namespace std;
int main() {
 string s;
 cin>>s;
 int a[256]={0};
 int sum=0;
 for (int i = 0; i < s.length();i++){
    if(a[s[i]]==0)++sum;
    a[s[i]]+=1;
 }
 cout<<(sum==s.length()?"yes":"no");
 return 0;

}


это оптимальное решение для этой проблемы. он принимает только целочисленную переменную и может сказать, является ли она уникальной или нет, независимо от размера строки.

сложности

лучший вариант O (1)

в худшем случае O (n)

public static boolean isUniqueChars(String str) {
    int checker = 0;
    for (int i = 0; i < str.length(); ++i) {
        int val = str.charAt(i) - ‘a’;
        if ((checker & (1 << val)) > 0) 
            return false;
        checker |= (1 << val);
    }
    return true;
}