29

I was wondering if there is a way to check for repeated characters in a string without using double loop. Can this be done with recursion?

An example of the code using double loop (return true or false based on if there are repeated characters in a string):

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

Many thanks in advance!

yinjia
  • 804
  • 2
  • 10
  • 20

16 Answers16

40

This will do:

function hasRepeats (str) {
    return /(.).*\1/.test(str);
}
thedarklord47
  • 3,183
  • 3
  • 26
  • 55
30

(A recursive solution can be found at the end of this answer)

You could simply use the builtin javascript Array functions some MDN some reference

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

callback parameters:
v ... current value of the iteration
i ... current index of the iteration
a ... array being iterated

.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. (it doesn't loop through the whole array, which is good for performance)

Details to the some function here in the documentation

Here some tests, with several different 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+

If you will want recursion.

Update for recursion:

//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+
winner_joiner
  • 12,173
  • 4
  • 36
  • 61
9

you can use .indexOf() and .lastIndexOf() to determine if an index is repeated. Meaning, if the first occurrence of the character is also the last occurrence, then you know it doesn't repeat. If not true, then it does repeat.

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.
tdc
  • 5,174
  • 12
  • 53
  • 102
4
function chkRepeat(word) {
    var wordLower = word.toLowerCase();
    var wordSet = new Set(wordLower);
    var lenWord = wordLower.length;
    var lenWordSet =wordSet.size;

    if (lenWord === lenWordSet) {
        return "false"
    } else {
        return'true'
    }
}
Guilherme Oliveira
  • 2,008
  • 3
  • 27
  • 44
j.Doe
  • 41
  • 1
  • Please include some details or context, there was already an accepted answer – jhhoff02 Jul 31 '17 at 17:56
  • 3
    This is my faviourite approch for finding duplicate characters in a word as it takes advantage of the inbuilt ES6 new Set inbuilt filtering of duplicates from an Array however it could be written much more concisely like this: function chkRepeat(word) { return new Set(word.toUpperCase()).size == word.length } – Angus Grant Jan 05 '20 at 23:53
2

Using regex to solve=>

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" );
1

The algorithm presented has a complexity of (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 which is O(n2).

So it would be better to use an object to map and remember the characters to check for uniqueness or duplicates. Assuming a maximum data size for each character, this process will be an O(n) algorithm.

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

On a tiny test case, the function indeed runs a few times faster.

Note that JavaScript strings are defined as sequences of 16-bit unsigned integer values. http://bclary.com/2004/11/07/#a-4.3.16

Hence, we can still implement the same basic algorithm but using a much quicker array lookup rather than an object lookup. The result is approximately 100 times faster now.

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));
Joseph Myers
  • 6,434
  • 27
  • 36
1
let myString = "Haammmzzzaaa";

myString = myString
   .split("")
   .filter((item, index, array) => array.indexOf(item) === index)
   .join("");
   
console.log(myString); // "Hamza"
  • While this code may answer the question, providing additional context regarding *how* and/or *why* it solves the problem would improve the answer's long-term value. – Sven Eberth Aug 30 '21 at 17:39
0

Another way of doing it using 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()));
pride
  • 85
  • 1
  • 11
0
 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));

You can also use the following code to find the repeated character in a string

Force Bolt
  • 1,117
  • 9
  • 9
0

//Finds character which are repeating in a string
var sample = "success";
function repeatFinder(str) {
    let repeat="";
    for (let i = 0; i < str.length; i++) {
        for (let j = i + 1; j < str.length; j++) {
            if (str.charAt(i) == str.charAt(j) && repeat.indexOf(str.charAt(j)) == -1) {
                repeat += str.charAt(i);
            }
        }
    }
    return repeat;
}
console.log(repeatFinder(sample)); //output: sc
0
   const checkRepeats = (str: string) => {
   const arr = str.split('')
   const obj: any = {}
   for (let i = 0; i < arr.length; i++) {
    if (obj[arr[i]]) {
        return true
    }
    obj[arr[i]] = true
  }
     return false
 }

 console.log(checkRepeats('abcdea'))
0
function repeat(str){
let h =new Set()
for(let i=0;i<str.length-1;i++){
    let a=str[i]
    if(h.has(a)){
        console.log(a)
    }else{
        h.add(a)
    }
}
return 0

} let str = '

function repeat(str){
    let h =new Set()
    for(let i=0;i<str.length-1;i++){
        let a=str[i]
        if(h.has(a)){
            console.log(a)
        }else{
            h.add(a)
        }
    }
    return 0
}
let str = 'haiiiiiiiiii'
console.log(repeat(str))

' console.log(repeat(str))

  • As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Nov 15 '22 at 10:48
0

Cleanest way for me:

  • Convert the string to an array
  • Make a set from the array
  • Compare the length of the set and the array

Example function:

function checkDuplicates(str) {
  const strArray = str.split('');
  if (strArray.length !== new Set(strArray).size) {
    return true;
  }
  return false;
}
Schmidko
  • 690
  • 1
  • 7
  • 17
0
Example: I/p: "aabcdd"
         O/P: { a:2, b:1, c:1, d:2}
function duplicateCharCount(str) {  
    if(str) {
        var obj = {};
        for(let i = 0; i < str.length; i++) {
            if(obj[str[i]]){
                obj[str[i]] ++;
            }else {
                obj[str[i]] = 1;
            }
        }
        console.log(obj);
    }       
} 
duplicateCharCount("aaaauiytioiibcdd");
channaveer
  • 39
  • 4
  • While this code may answer the question, providing additional context regarding *how* and/or *why* it solves the problem would improve the answer's long-term value. You also might want to read _[How do I create a runnable stack snippet?](https://meta.stackoverflow.com/questions/358992)_. – Scott Sauyet Mar 15 '23 at 12:43
0

The Set object lets you store unique values of any type.

function charRepeats(s) {
    return new Set(...s).size !== s.length;
}
cookie
  • 1
-1

You can use "Set object"!

The Set object lets you store unique values of any type, whether primitive values or object references. It has some methods to add or to check if a property exist in the object.

Read more about Sets at MDN

Here how i use it:

 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