这是破解编码面试手册。
设计算法并编写代码以删除字符串中的重复字符 不使用任何额外的缓冲区。注意:一个或两个额外的变量是好的。 数组的额外副本不是。
在书中它说时间复杂度是$ O(N ^ 2)$。我们如何判断解决方案的时间复杂度是$ O(N ^ 2)$? 我对解决方案如何删除重复字符有疑问。我已将它们包含在下面的内联评论中。
public static void removeDuplicates(char[] str) {
if (str == null) return; // if the array is empty return nothing?
int len = str.length; // get the length of the array
if (len < 2) return; // if the array length is only 1 return nothing?
int tail = 1; // initialise tail variable as 1 !
// Why are we starting at second character here (at i = 1),why not start at i = 0 ?
for (int i = 1; i < len; ++i) {
int j;
for (j = 0; j < tail; ++j) { // so are we checking if j is less then 1 as tail has been initialized to 1
if (str[i] == str[j]) break; // stop, if we find duplicate.
}
if (j == tail) { why are we comparing j to tail(1) here ?
str[tail] = str[i]; // assigning the value
++tail; // incrementing tail
}
}
str[tail] = 0; //setting last element as 0
}
-
答案 0 :(得分:3)
我完全依赖@pbabcdefp评论,因为我懒得测试它,但看起来你的算法不起作用。
无论如何我不喜欢它,在这里我将如何在评论中解释:
public static void main(String[] args) {
removeDuplicates(new char[]{'a','a','b','b','c','d','c'});
}
public static final void removeDuplicates(char[] str)
{
/*
* If the str is not instantiated, or there is maximum 1 char there is no need to remove duplicates as
* it is just impossible to have duplicate with 1 char.
*/
if (str == null || str.length < 2)
return;
//loop over each char
for(int i = 0; i < str.length; i++)
{
//no need to check with earlier character as they were already checked, so we start at i + 1
for(int j = i + 1; j < str.length; j++)
{
//if they match we clear
if(str[j] == str[i])
str[j] = ' ';
}
}
System.out.println(str);
}
这将输出a b cd
。
答案 1 :(得分:3)
首先,这是一本很棒的书,我希望向大家推荐!
通常,如果允许使用大量内存,可以节省时间,如果允许使用一些变量,那么您仍然可以通过较慢的算法解决此问题。当你检查每一个可能的解决方案时,有完整的暴力算法。
public static void removeDuplicates(char[] str) {
if (str == null) return; // if the array is empty return nothing?
输入是字符串指针,因此字符串存在于内存中的某个位置,代码可以修改它,但它保持在同一个地方。这就是函数的返回类型为void的原因,因此它不会返回任何内容。返回时,原始位置的字符串不重复。
int len = str.length; // get the length of the array
if (len < 2) return; // if the array length is only 1 return nothing?
与上述相同,没有返回值。如果字符串小于2个字符,则它不能包含重复。
从这里开始,逻辑如下: 拿第i个角色。检查字符串中此位置之前是否存在。如果存在,则算法删除第i个字符。如果它不存在则保留在字符串中。
证明这是正确的算法: 没有任何字符会保留字符串中较早存在的字符。如果字符串稍后存在,则由于先前的规则,它将被删除。
如果这是算法,它会正常工作,但字符串中会有“空”字符。字符串不会更小,即使很难,它应该包含更少的字符。
这就是算法跟踪“输出字符串尾部”的原因。这就是尾部在开头等于1的原因,因为第一个字符肯定是结果字符串的一部分。 当应删除当前字符时,输出字符串的尾部不会移动,不会在结果中添加新字符。当前字符应该是结果的一部分时,它会被复制到结果字符串的尾部。
当算法到达输入字符串的末尾时,它会关闭结果字符串。
复杂性: 这意味着,相对于输入的大小,称为“n”算法必须采取多少步骤。通常,循环和递归仅计数。 此代码有2个for循环嵌入到彼此中。 外部每次从1到n。 内部从0到尾部,尾部从1到n。因此,在最糟糕的情况下,内部的平均值从1到n / 2。 这意味着您的复杂性为n *(n / 2)。由于2是常数,因此复杂度为n * n。
答案 2 :(得分:2)
O时间复杂度与最坏情况有关。忽略你得到的数组以及你对它做的动作,当你有两个由字符串长度限制的嵌套for循环时,你的复杂性不能高于n ^ 2,因此它是O(n ^ 2) (它只是一个上限,如果你想表明它也是一个下限,应该做更多的工作。)
答案 3 :(得分:2)
O(N ^ 2)基本上意味着随着输入数量的增加,N是输入数量,复杂度(执行的操作数量)将按比例缩放到N ^ 2 +某个常数值。
所以看一下代码,str.length是N.对于每个元素,你将它与其他元素进行比较,N比较N次= N ^ 2.
现在O(N ^ 2)并不准确。根据定义,它只关注导致复杂性增长的非常数因素。它永远不会告诉你特定算法运行的速度,它纯粹告诉你运行所需的时间如何随着操作元素数量的波动而缩放。
答案 4 :(得分:0)
static boolean contains(char c, char[] array) {
for (char x : array) {
if (x == c) {
return true;
}
}
return false;
}
public static void main(String[] args) {
String s = "stackoverflow11221113" ;
String result = "";
for(char ch:s.toCharArray()){
if(!contains(ch,result.toCharArray())){
result +=ch;
}
}
System.out.println(result);
}
static boolean contains(char c, char[] array) {
for (char x : array) {
if (x == c) {
return true;
}
}
return false;
}
public static void main(String[] args) {
String s = "StackOverFlow11221113" ;
String result = "";
for(char ch:s.toCharArray()){
if(!contains(ch,result.toLowerCase().toCharArray())){
result +=ch;
}
}
System.out.println(result);
}