Проверете за повтарящи се знаци в низ Javascript

Чудех се дали има начин да проверя за повтарящи се знаци в низ, без да използвам двоен цикъл. Може ли това да стане с рекурсия?

Пример за код, използващ двоен цикъл (връща вярно или невярно в зависимост от това дали има повтарящи се знаци в низ):

var charRepeats = function(str) {
    for(var i = 0; i <= str.length; i++) {
        for(var j = i+1; j <= str.length; j++) {
            if(str[j] == str[i]) {
                return false;
            }
        }
    }
    return true;
}

Много благодаря предварително!


person yinjia    schedule 11.11.2015    source източник
comment
Можете ли да добавите някои примерни данни, които ще бъдат проверени и очакваните резултати?   -  person Jesse Kernaghan    schedule 11.11.2015
comment
Какво се брои за низ в този случай? напр. изречение или дума? И какво се счита за повтаряне? Множество повторения? Или две букви една до друга?   -  person jerdiggity    schedule 11.11.2015
comment
Възможен дубликат на повтарящи се знаци в средата на низ   -  person    schedule 11.11.2015
comment
Необходима ли е рекурсия? или само друг вариант? Ако е така, проверете отговора ми за актуализация. :)   -  person winner_joiner    schedule 11.11.2015
comment
@JarrodRoberson този въпрос не е дубликат, защото не трябва да повтаря знаци, тъй като е препратеният въпрос, той трябва да проверява дали даден низ има дублиращи се знаци, а също така е различен скриптов език.   -  person winner_joiner    schedule 12.11.2015
comment
@Yinjia отговорено ли е на въпроса ви? Имате ли нужда от още помощ/разяснение?   -  person winner_joiner    schedule 12.11.2015
comment
@winner_joiner, благодаря, сега го разбрах!   -  person yinjia    schedule 14.11.2015
comment
@Prinzhorn благодаря, добавих това сравнение в публикацията си   -  person Joseph Myers    schedule 14.11.2015
comment
@Prinzhorn най-якото решение!!!   -  person winner_joiner    schedule 17.11.2015
comment
Публикувах отговор, идентичен с решението на @Prinzhorn на въпрос, който беше затворен като дубликат на този. Добавих го по-долу.   -  person thedarklord47    schedule 18.02.2016


Отговори (9)


(Рекурсивно решение може да се намери в края на този отговор.)

Можете да използвате вградени в JavaScript функции за масив някои MDN някаква справка

 var text = "test".split("");
 text.some(function(v,i,a){
   return a.lastIndexOf(v)!=i;
 });

параметри за обратно извикване:
v текущата стойност на итерацията
i текущият индекс на итерацията
a< /strong> текущ масив

.split("") create an array from a string
.some(function(v,i,a){ ... }) goes through an array until the function returns true, and ends than right away. (doesn't loop through the whole array, if it finds an match earlier)

Details to the some function can be found here

Tests, with several strings:

var texts = ["test", "rest", "why", "puss"];


for(var idx in texts){
    var text = texts[idx].split("");
    document.write(text + " -> " + text.some(function(v,i,a){return a.lastIndexOf(v)!=i;}) +"<br/>");
    
  }
  //tested on win7 in chrome 46+

Ако е необходима рекурсия.

Актуализация за рекурсия:

//recursive function
function checkString(text,index){
    if((text.length - index)==0 ){ //stop condition
        return false; 
    }else{
        return checkString(text,index + 1) 
        || text.substr(0, index).indexOf(text[index])!=-1;
    }
}

// example Data to test
var texts = ["test", "rest", "why", "puss"];

for(var idx in texts){
    var txt = texts[idx];
    document.write( txt +  " ->" + checkString(txt,0) + "<br/>");
}
//tested on win7 in chrome 46+

person winner_joiner    schedule 11.11.2015

Това ще направи:

function isIsogram (str) {
    return !/(.).*\1/.test(str);
}
person thedarklord47    schedule 17.02.2016
comment
Това може да бъде наистина полезно. Също така бързо, защото използва регулярен израз. Изненадан съм, че този отговор няма повече гласове. - person SwiftNinjaPro; 15.05.2020

можете да използвате .indexOf() и .lastIndexOf(), за да определите дали даден индекс се повтаря. Което означава, че ако първото появяване на знака е и последното появяване, тогава знаете, че не се повтаря. Ако не е вярно, значи се повтаря.

var example = 'hello';

var charRepeats = function(str) {
    for (var i=0; i<str.length; i++) {
      if ( str.indexOf(str[i]) !== str.lastIndexOf(str[i]) ) {
        return false; // repeats
      }
    }
  return true;
}

console.log( charRepeats(example) ); // 'false', because when it hits 'l', the indexOf and lastIndexOf are not the same.
person tdc    schedule 11.11.2015
comment
Използвайте toLowerCase(), за да преобразувате символите в същия регистър. - person Juni Brosas; 05.12.2017

Представеният алгоритъм има сложност (1 + n - (1)) + (1 + n - (2)) + (1 + n - (3)) + ... + (1 + n - (n-1)) = (n-1)*(1 + n) - (n)(n-1)/2 = (n^2 + n - 2)/2, която е O(n2).

Така че би било по-добре да използвате обект за картографиране и запомняне на знаците, за да проверите за уникалност или дубликати. Ако приемем максимален размер на данните за всеки знак, този процес ще бъде O(n) алгоритъм.

function charUnique(s) {
  var r = {}, i, x;
  for (i=0; i<s.length; i++) {
    x = s[i];
    if (r[x])
      return false;
    r[x] = true;
  }
  return true;
}

В малък тестов случай функцията наистина работи няколко пъти по-бързо.

Имайте предвид, че JavaScript низовете се дефинират като последователности от 16-битови цели числа без знак. http://bclary.com/2004/11/07/#a-4.3.16

Следователно все още можем да приложим същия основен алгоритъм, но използвайки много по-бързо търсене на масив, отколкото търсене на обект. Резултатът вече е приблизително 100 пъти по-бърз.

var charRepeats = function(str) {
  for (var i = 0; i <= str.length; i++) {
    for (var j = i + 1; j <= str.length; j++) {
      if (str[j] == str[i]) {
        return false;
      }
    }
  }
  return true;
}

function charUnique(s) {
  var r = {},
    i, x;
  for (i = 0; i < s.length; i++) {
    x = s[i];
    if (r[x])
      return false;
    r[x] = true;
  }
  return true;
}

function charUnique2(s) {
  var r = {},
    i, x;
  for (i = s.length - 1; i > -1; i--) {
    x = s[i];
    if (r[x])
      return false;
    r[x] = true;
  }
  return true;
}

function charCodeUnique(s) {
  var r = [],
    i, x;
  for (i = s.length - 1; i > -1; i--) {
    x = s.charCodeAt(i);
    if (r[x])
      return false;
    r[x] = true;
  }
  return true;
}

function regExpWay(s) {
  return /(.).*\1/.test(s);
}


function timer(f) {
  var i;
  var t0;

  var string = [];
  for (i = 32; i < 127; i++)
    string[string.length] = String.fromCharCode(i);
  string = string.join('');
  t0 = new Date();
  for (i = 0; i < 10000; i++)
    f(string);
  return (new Date()) - t0;
}

document.write('O(n^2) = ',
  timer(charRepeats), ';<br>O(n) = ',
  timer(charUnique), ';<br>optimized O(n) = ',
  timer(charUnique2), ';<br>more optimized O(n) = ',
  timer(charCodeUnique), ';<br>regular expression way = ',
  timer(regExpWay));

person Joseph Myers    schedule 14.11.2015

Друг начин да го направите с помощта на lodash

var _ = require("lodash");
var inputString = "HelLoo world!"
var checkRepeatition = function(inputString) {
  let unique = _.uniq(inputString).join('');
  if(inputString.length !== unique.length) {
    return true; //duplicate characters present!
  }
  return false;
};
console.log(checkRepeatition(inputString.toLowerCase()));
person pride    schedule 14.05.2019

Можете да използвате "Задаване на обект"!

Обектът Set ви позволява да съхранявате уникални стойности от всякакъв тип, независимо дали са примитивни стойности или препратки към обекти. Има някои методи за добавяне или проверка дали съществува свойство в обекта.

Прочетете повече за наборите в MDN

Ето как го използвам:

 function isIsogram(str){
  let obj = new Set();

  for(let i = 0; i < str.length; i++){
    if(obj.has(str[i])){
      return false
    }else{
      obj.add(str[i])
    }
  }
  return true
}

isIsogram("Dermatoglyphics") // true
isIsogram("aba")// false
person Klodian Koni    schedule 25.01.2020

Използване на регулярен израз за решаване=›

function isIsogram(str){
  return !/(\w).*\1/i.test(str);
}

console.log(isIsogram("isogram"), true );
console.log(isIsogram("aba"), false, "same chars may not be adjacent" );
console.log(isIsogram("moOse"), false, "same chars may not be same case" );
console.log(isIsogram("isIsogram"), false );
console.log(isIsogram(""), true, "an empty string is a valid isogram" );

person Enzo Fernandes    schedule 10.01.2021

 const str = "afewreociwddwjej";
  const repeatedChar=(str)=>{
  const result = [];
  const strArr = str.toLowerCase().split("").sort().join("").match(/(.)\1+/g);
  
  if (strArr != null) {
    strArr.forEach((elem) => {
      result.push(elem[0]);
    });
  }
  return result;
}
console.log(...repeatedChar(str));

Можете също да използвате следния код, за да намерите повтарящия се знак в низ

person Force Bolt    schedule 30.04.2021

person    schedule
comment
Моля, включете някои подробности или контекст, вече имаше приет отговор - person jhhoff02; 31.07.2017
comment
Това е любимият ми подход за намиране на дублирани знаци в дума, тъй като се възползва от вграденото ES6 new Set вградено филтриране на дубликати от масив, но може да се напише много по-сбито по следния начин: функция chkRepeat(word) { return new Set( word.toUpperCase()).size == word.length} - person Angus Grant; 06.01.2020