如果字符串s只包含小写字母(a-z),则查找(即打印)重复的字符。
例如,如果string s =“aabcacdddec”
输出:a c d
存在这个问题的3种方法:
[强力]检查字符串的每个字符(即s [i]与其他所有字符串并打印,如果两者都相同) 时间复杂度:O(n ^ 2) 空间复杂度:O(1)
[排序然后比较相邻元素]排序后(在O(n log(n)时间内),遍历字符串并检查s [i]和s [i + 1]是否相等 时间复杂度:O(n logn)+ O(n)= O(n logn) 空间复杂度:O(1)
[在数组中存储字符数]创建一个大小为26的数组(以跟踪a - z)和每个s [i],存储在index = s [i]的增量值 - 26在数组中。最后遍历数组并打印值大于1的所有元素(即'a'+ i) 时间复杂度:O(n) 空间复杂度:O(1)但我们有一个单独的数组用于存储每个元素的频率。
是否有O(n)方法不使用任何数组/哈希表/映射(等)?
提示:使用BIT向量
答案 0 :(得分:4)
这是element distinctness problem,所以一般来说 - 没有办法在O(n)
没有额外空间的情况下解决它。
然而,如果您将字母表视为常量(az字符只是非常常量),您可以在O(1)
空格中创建这些字符的位集[它是常量! ]或检查O(n)
中的每个字符是否重复多次,它将是O(constant*n)
,仍然在O(n)
。
第一个解决方案的伪代码:
bit seen[] = new bit[SIZE_OF_ALPHABET] //contant!
bit printed[] = new bit[SIZE_OF_ALPHABET] //so is this!
for each i in seen.length: //init:
seen[i] = 0
printed[i] = 0
for each character c in string: //traverse the string:
i = intValue(c)
//already seen it and didn't print it? print it now!
if seen[i] == 1 and printed[i] == 0:
print c
printed[i] = 1
else:
seen[i] = 1
第二种解决方案的伪代码:
for each character c from a-z: //constant number of repeats is O(1)
count = 0
for each character x in the string: //O(n)
if x==c:
count += 1
if count > 1
print count
答案 1 :(得分:2)
字符集的大小是常量,因此您可以扫描输入26次。您只需要一个计数器来存储您看到与当前迭代对应的字符的次数。在每次迭代结束时,如果您的计数器大于1,则打印该字符。
它在运行时是O(n),在辅助空间中是O(1)。
答案 2 :(得分:2)
Java实现
public static void findDuplicate(String str) {
int checker = 0;
char c = 'a';
for (int i = 0; i < str.length(); ++i) {
int val = str.charAt(i) - c;
if ((checker & (1 << val)) > 0) {
System.out.println((char)(c+val));
}else{
checker |= (1 << val);
}
}
}
使用int作为存储并执行按位运算符以查找重复项。
它在O(n)..解释如下
输入为“abddc”
i == 0
STEP #1 : val = 98 - 98 (0) str.charAt(0) is a and conversion char to int is 98 ( ascii of 'a')
STEP #2 : 1 << val equal to ( 1 << 0 ) equal to 1 finally 1 & 0 is 0
STEP #3 : checker = 0 | ( 1 << 0) equal to 0 | 1 equal to 1 checker is 1
i == 1
STEP #1 : val = 99 - 98 (1) str.charAt(1) is b and conversion char to int is 99 ( ascii of 'b')
STEP #2 : 1 << val equal to ( 1 << 1 ) equal to 2 finally 1 & 2 is 0
STEP #3 : checker = 2 | ( 1 << 1) equal to 2 | 1 equal to 2 finally checker is 2
i == 2
STEP #1 : val = 101 - 98 (3) str.charAt(2) is d and conversion char to int is 101 ( ascii of 'd')
STEP #2 : 1 << val equal to ( 1 << 3 ) equal to 8 finally 2 & 8 is 0
STEP #3 : checker = 2 | ( 1 << 3) equal to 2 | 8 equal to 8 checker is 8
i == 3
STEP #1 : val = 101 - 98 (3) str.charAt(3) is d and conversion char to int is 101 ( ascii of 'd')
STEP #2 : 1 << val equal to ( 1 << 3 ) equal to 8 finally 8 & 8 is 8
Now print 'd' since the value > 0
你也可以使用位向量,取决于它可以节省空间的语言。在java中,我更喜欢使用int来处理这个固定的(只有26个)常量情况
答案 3 :(得分:0)
在C#中实现(递归解决方案)
static void getNonUniqueElements(string s, string nonUnique)
{
if (s.Count() > 0)
{
char ch = s[0];
s = s.Substring(1);
if (s.LastIndexOf(ch) > 0)
{
if (nonUnique.LastIndexOf(ch) < 0)
nonUnique += ch;
}
getNonUniqueElements(s, nonUnique);
}
else
{
Console.WriteLine(nonUnique);
return;
}
}
static void Main(string[] args)
{
getNonUniqueElements("aabcacdddec", "");
Console.ReadKey();
}